1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include "rtfexport.hxx" 21 22 #include "rtfexportfilter.hxx" 23 #include "rtfsdrexport.hxx" 24 #include "rtfattributeoutput.hxx" 25 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> 26 #include <com/sun/star/frame/XModel.hpp> 27 #include <com/sun/star/i18n/ScriptType.hpp> 28 #include <com/sun/star/beans/XPropertySet.hpp> 29 #include <com/sun/star/beans/XPropertySetInfo.hpp> 30 #include <docsh.hxx> 31 #include <viewsh.hxx> 32 #include <viewopt.hxx> 33 #include <fmtpdsc.hxx> 34 #include <ftninfo.hxx> 35 #include <fmthdft.hxx> 36 #include <editeng/colritem.hxx> 37 #include <editeng/udlnitem.hxx> 38 #include <editeng/fontitem.hxx> 39 #include <editeng/paperinf.hxx> 40 #include <editeng/brushitem.hxx> 41 #include <editeng/protitem.hxx> 42 #include <editeng/lrspitem.hxx> 43 #include <editeng/ulspitem.hxx> 44 #include <editeng/boxitem.hxx> 45 #include <editeng/shaditem.hxx> 46 #include <lineinfo.hxx> 47 #include <redline.hxx> 48 #include <swmodule.hxx> 49 #include <IDocumentLayoutAccess.hxx> 50 #include <comphelper/string.hxx> 51 #include <svtools/rtfkeywd.hxx> 52 #include <filter/msfilter/rtfutil.hxx> 53 #include <unotools/docinfohelper.hxx> 54 #include <osl/diagnose.h> 55 #include <rtl/tencinfo.h> 56 #include <sal/log.hxx> 57 #if OSL_DEBUG_LEVEL > 1 58 #include <iostream> 59 #endif 60 #include <svx/xflclit.hxx> 61 #include <fmtmeta.hxx> 62 #include <IDocumentSettingAccess.hxx> 63 #include <fmtfsize.hxx> 64 #include <ndtxt.hxx> 65 #include <numrule.hxx> 66 #include <frmatr.hxx> 67 #include <swtable.hxx> 68 #include <IMark.hxx> 69 70 using namespace ::com::sun::star; 71 72 // the default text encoding for the export, if it doesn't fit unicode will 73 // be used 74 #define DEF_ENCODING RTL_TEXTENCODING_ASCII_US 75 76 AttributeOutputBase& RtfExport::AttrOutput() const { return *m_pAttrOutput; } 77 78 MSWordSections& RtfExport::Sections() const { return *m_pSections; } 79 80 RtfSdrExport& RtfExport::SdrExporter() const { return *m_pSdrExport; } 81 82 bool RtfExport::CollapseScriptsforWordOk(sal_uInt16 nScript, sal_uInt16 nWhich) 83 { 84 // FIXME is this actually true for rtf? - this is copied from DOCX 85 if (nScript == i18n::ScriptType::ASIAN) 86 { 87 // for asian in ww8, there is only one fontsize 88 // and one fontstyle (posture/weight) 89 switch (nWhich) 90 { 91 case RES_CHRATR_FONTSIZE: 92 case RES_CHRATR_POSTURE: 93 case RES_CHRATR_WEIGHT: 94 return false; 95 default: 96 break; 97 } 98 } 99 else if (nScript != i18n::ScriptType::COMPLEX) 100 { 101 // for western in ww8, there is only one fontsize 102 // and one fontstyle (posture/weight) 103 switch (nWhich) 104 { 105 case RES_CHRATR_CJK_FONTSIZE: 106 case RES_CHRATR_CJK_POSTURE: 107 case RES_CHRATR_CJK_WEIGHT: 108 return false; 109 default: 110 break; 111 } 112 } 113 return true; 114 } 115 116 void RtfExport::AppendBookmarks(const SwTextNode& rNode, sal_Int32 nCurrentPos, sal_Int32 nLen) 117 { 118 std::vector<OUString> aStarts; 119 std::vector<OUString> aEnds; 120 121 IMarkVector aMarks; 122 if (GetBookmarks(rNode, nCurrentPos, nCurrentPos + nLen, aMarks)) 123 { 124 for (const auto& pMark : aMarks) 125 { 126 const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex(); 127 const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex(); 128 129 if (nStart == nCurrentPos) 130 aStarts.push_back(pMark->GetName()); 131 132 if (nEnd == nCurrentPos) 133 aEnds.push_back(pMark->GetName()); 134 } 135 } 136 137 m_pAttrOutput->WriteBookmarks_Impl(aStarts, aEnds); 138 } 139 140 void RtfExport::AppendBookmark(const OUString& rName) 141 { 142 std::vector<OUString> aStarts; 143 std::vector<OUString> aEnds; 144 145 aStarts.push_back(rName); 146 aEnds.push_back(rName); 147 148 m_pAttrOutput->WriteBookmarks_Impl(aStarts, aEnds); 149 } 150 151 void RtfExport::AppendAnnotationMarks(const SwWW8AttrIter& rAttrs, sal_Int32 nCurrentPos, 152 sal_Int32 nLen) 153 { 154 std::vector<OUString> aStarts; 155 std::vector<OUString> aEnds; 156 157 IMarkVector aMarks; 158 if (GetAnnotationMarks(rAttrs, nCurrentPos, nCurrentPos + nLen, aMarks)) 159 { 160 for (const auto& pMark : aMarks) 161 { 162 const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex(); 163 const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex(); 164 165 if (nStart == nCurrentPos) 166 aStarts.push_back(pMark->GetName()); 167 168 if (nEnd == nCurrentPos) 169 aEnds.push_back(pMark->GetName()); 170 } 171 } 172 173 m_pAttrOutput->WriteAnnotationMarks_Impl(aStarts, aEnds); 174 } 175 176 //For i120928,to export graphic of bullet for RTF filter 177 void RtfExport::ExportGrfBullet(const SwTextNode& /*rNd*/) 178 { 179 // Noop, would be too late, see WriteNumbering() instead. 180 } 181 182 void RtfExport::WriteChar(sal_Unicode /*c*/) { /* WriteChar() has nothing to do for rtf. */} 183 184 static bool IsExportNumRule(const SwNumRule& rRule) 185 { 186 sal_uInt8 nEnd = MAXLEVEL; 187 while (nEnd-- && !rRule.GetNumFormat(nEnd)) 188 ; 189 ++nEnd; 190 191 sal_uInt8 nLvl; 192 193 for (nLvl = 0; nLvl < nEnd; ++nLvl) 194 { 195 const SwNumFormat* pNFormat = &rRule.Get(nLvl); 196 if (SVX_NUM_NUMBER_NONE != pNFormat->GetNumberingType() || !pNFormat->GetPrefix().isEmpty() 197 || (!pNFormat->GetSuffix().isEmpty() && pNFormat->GetSuffix() != ".")) 198 break; 199 } 200 201 return nLvl != nEnd; 202 } 203 204 void RtfExport::BuildNumbering() 205 { 206 const SwNumRuleTable& rListTable = m_rDoc.GetNumRuleTable(); 207 208 SwNumRule* pOutlineRule = m_rDoc.GetOutlineNumRule(); 209 if (IsExportNumRule(*pOutlineRule)) 210 GetNumberingId(*pOutlineRule); 211 212 for (auto n = rListTable.size(); n;) 213 { 214 SwNumRule* pRule = rListTable[--n]; 215 if (!SwDoc::IsUsed(*pRule)) 216 continue; 217 218 if (IsExportNumRule(*pRule)) 219 GetNumberingId(*pRule); 220 } 221 } 222 223 void RtfExport::WriteNumbering() 224 { 225 SAL_INFO("sw.rtf", __func__ << " start"); 226 227 if (!m_pUsedNumTable) 228 return; // no numbering is used 229 230 Strm() 231 .WriteChar('{') 232 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE) 233 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LISTTABLE); 234 235 CollectGrfsOfBullets(); 236 if (!m_vecBulletPic.empty()) 237 Strm() 238 .WriteChar('{') 239 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE) 240 .WriteCharPtr(LO_STRING_SVTOOLS_RTF_LISTPICTURE); 241 BulletDefinitions(); 242 if (!m_vecBulletPic.empty()) 243 Strm().WriteChar('}'); 244 245 AbstractNumberingDefinitions(); 246 Strm().WriteChar('}'); 247 248 Strm().WriteChar('{').WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LISTOVERRIDETABLE); 249 NumberingDefinitions(); 250 Strm().WriteChar('}'); 251 252 SAL_INFO("sw.rtf", __func__ << " end"); 253 } 254 255 void RtfExport::WriteRevTab() 256 { 257 int nRevAuthors = m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size(); 258 259 if (nRevAuthors < 1) 260 return; 261 262 // RTF always seems to use Unknown as the default first entry 263 GetRedline("Unknown"); 264 265 for (SwRangeRedline* pRedl : m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()) 266 { 267 GetRedline(SW_MOD()->GetRedlineAuthor(pRedl->GetAuthor())); 268 } 269 270 // Now write the table 271 Strm() 272 .WriteChar('{') 273 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE) 274 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_REVTBL) 275 .WriteChar(' '); 276 for (std::size_t i = 0; i < m_aRedlineTable.size(); ++i) 277 { 278 const OUString* pAuthor = GetRedline(i); 279 Strm().WriteChar('{'); 280 if (pAuthor) 281 Strm().WriteCharPtr( 282 msfilter::rtfutil::OutString(*pAuthor, m_eDefaultEncoding).getStr()); 283 Strm().WriteCharPtr(";}"); 284 } 285 Strm().WriteChar('}').WriteCharPtr(SAL_NEWLINE_STRING); 286 } 287 288 void RtfExport::WriteHeadersFooters(sal_uInt8 nHeadFootFlags, const SwFrameFormat& rFormat, 289 const SwFrameFormat& rLeftFormat, 290 const SwFrameFormat& rFirstPageFormat, sal_uInt8 /*nBreakCode*/) 291 { 292 // headers 293 if (nHeadFootFlags & nsHdFtFlags::WW8_HEADER_EVEN) 294 WriteHeaderFooter(rLeftFormat, true, OOO_STRING_SVTOOLS_RTF_HEADERL); 295 296 if (nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD) 297 WriteHeaderFooter(rFormat, true, OOO_STRING_SVTOOLS_RTF_HEADER); 298 299 if (nHeadFootFlags & nsHdFtFlags::WW8_HEADER_FIRST) 300 WriteHeaderFooter(rFirstPageFormat, true, OOO_STRING_SVTOOLS_RTF_HEADERF, true); 301 302 // footers 303 if (nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_EVEN) 304 WriteHeaderFooter(rLeftFormat, false, OOO_STRING_SVTOOLS_RTF_FOOTERL); 305 306 if (nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD) 307 WriteHeaderFooter(rFormat, false, OOO_STRING_SVTOOLS_RTF_FOOTER); 308 309 if (nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_FIRST) 310 WriteHeaderFooter(rFirstPageFormat, false, OOO_STRING_SVTOOLS_RTF_FOOTERF, true); 311 } 312 313 void RtfExport::OutputField(const SwField* pField, ww::eField eFieldType, const OUString& rFieldCmd, 314 FieldFlags nMode) 315 { 316 m_pAttrOutput->WriteField_Impl(pField, eFieldType, rFieldCmd, nMode); 317 } 318 319 void RtfExport::WriteFormData(const ::sw::mark::IFieldmark& /*rFieldmark*/) 320 { 321 SAL_INFO("sw.rtf", "TODO: " << __func__); 322 } 323 324 void RtfExport::WriteHyperlinkData(const ::sw::mark::IFieldmark& /*rFieldmark*/) 325 { 326 SAL_INFO("sw.rtf", "TODO: " << __func__); 327 } 328 329 void RtfExport::DoComboBox(const OUString& /*rName*/, const OUString& /*rHelp*/, 330 const OUString& /*rToolTip*/, const OUString& /*rSelected*/, 331 const uno::Sequence<OUString>& /*rListItems*/) 332 { 333 // this is handled in RtfAttributeOutput::OutputFlyFrame_Impl 334 } 335 336 void RtfExport::DoFormText(const SwInputField* pField) 337 { 338 OUString sResult = pField->ExpandField(true, nullptr); 339 const OUString& rHelp = pField->GetHelp(); 340 OUString sName = pField->GetPar2(); 341 const OUString& rStatus = pField->GetToolTip(); 342 m_pAttrOutput->RunText().append("{" OOO_STRING_SVTOOLS_RTF_FIELD 343 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FLDINST 344 "{ FORMTEXT }"); 345 m_pAttrOutput->RunText().append( 346 "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FORMFIELD 347 " {" OOO_STRING_SVTOOLS_RTF_FFTYPE "0"); 348 if (!rHelp.isEmpty()) 349 m_pAttrOutput->RunText().append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP); 350 if (!rStatus.isEmpty()) 351 m_pAttrOutput->RunText().append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT); 352 m_pAttrOutput->RunText().append(OOO_STRING_SVTOOLS_RTF_FFTYPETXT "0"); 353 354 if (!sName.isEmpty()) 355 m_pAttrOutput->RunText() 356 .append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFNAME " ") 357 .append(msfilter::rtfutil::OutString(sName, m_eDefaultEncoding)) 358 .append("}"); 359 if (!rHelp.isEmpty()) 360 m_pAttrOutput->RunText() 361 .append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFHELPTEXT " ") 362 .append(msfilter::rtfutil::OutString(rHelp, m_eDefaultEncoding)) 363 .append("}"); 364 m_pAttrOutput->RunText() 365 .append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFDEFTEXT " ") 366 .append(msfilter::rtfutil::OutString(sResult, m_eDefaultEncoding)) 367 .append("}"); 368 if (!rStatus.isEmpty()) 369 m_pAttrOutput->RunText() 370 .append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFSTATTEXT " ") 371 .append(msfilter::rtfutil::OutString(rStatus, m_eDefaultEncoding)) 372 .append("}"); 373 m_pAttrOutput->RunText().append("}}}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " "); 374 m_pAttrOutput->RunText() 375 .append(msfilter::rtfutil::OutString(sResult, m_eDefaultEncoding)) 376 .append("}}"); 377 } 378 379 sal_uLong RtfExport::ReplaceCr(sal_uInt8 /*nChar*/) 380 { 381 // Completely unused for Rtf export... only here for code sharing 382 // purpose with binary export 383 384 return 0; 385 } 386 387 void RtfExport::WriteFonts() 388 { 389 Strm() 390 .WriteCharPtr(SAL_NEWLINE_STRING) 391 .WriteChar('{') 392 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FONTTBL); 393 m_aFontHelper.WriteFontTable(*m_pAttrOutput); 394 Strm().WriteChar('}'); 395 } 396 397 void RtfExport::WriteStyles() 398 { 399 SAL_INFO("sw.rtf", __func__ << " start"); 400 m_pStyles->OutputStylesTable(); 401 SAL_INFO("sw.rtf", __func__ << " end"); 402 } 403 404 void RtfExport::WriteFootnoteSettings() 405 { 406 const SwPageFootnoteInfo& rFootnoteInfo = m_rDoc.GetPageDesc(0).GetFootnoteInfo(); 407 // Request a separator only in case the width is larger than zero. 408 bool bSeparator = double(rFootnoteInfo.GetWidth()) > 0; 409 410 Strm() 411 .WriteChar('{') 412 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE) 413 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FTNSEP); 414 if (bSeparator) 415 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_CHFTNSEP); 416 Strm().WriteChar('}'); 417 } 418 419 void RtfExport::WriteMainText() 420 { 421 SAL_INFO("sw.rtf", __func__ << " start"); 422 423 if (std::unique_ptr<SvxBrushItem> oBrush = getBackground(); oBrush) 424 { 425 Strm().WriteCharPtr(LO_STRING_SVTOOLS_RTF_VIEWBKSP).WriteChar('1'); 426 Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_BACKGROUND); 427 Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_SHP); 428 Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SHPINST); 429 430 std::vector<std::pair<OString, OString>> aProperties; 431 aProperties.push_back(std::make_pair<OString, OString>("shapeType", "1")); 432 aProperties.push_back(std::make_pair<OString, OString>( 433 "fillColor", OString::number(wwUtility::RGBToBGR(oBrush->GetColor())))); 434 for (const std::pair<OString, OString>& rPair : aProperties) 435 { 436 Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_SP "{"); 437 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SN " "); 438 Strm().WriteOString(rPair.first); 439 Strm().WriteCharPtr("}{" OOO_STRING_SVTOOLS_RTF_SV " "); 440 Strm().WriteOString(rPair.second); 441 Strm().WriteCharPtr("}}"); 442 } 443 Strm().WriteChar('}'); // shpinst 444 Strm().WriteChar('}'); // shp 445 Strm().WriteChar('}'); // background 446 } 447 448 SwTableNode* pTableNode = m_pCurPam->GetNode().FindTableNode(); 449 if (m_pWriter && m_pWriter->m_bWriteOnlyFirstTable && pTableNode != nullptr) 450 { 451 m_pCurPam->GetPoint()->nNode = *pTableNode; 452 m_pCurPam->GetMark()->nNode = *(pTableNode->EndOfSectionNode()); 453 } 454 else 455 { 456 m_pCurPam->GetPoint()->nNode 457 = m_rDoc.GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex(); 458 } 459 460 WriteText(); 461 462 SAL_INFO("sw.rtf", __func__ << " end"); 463 } 464 465 void RtfExport::WriteInfo() 466 { 467 OString aGenerator 468 = OUStringToOString(utl::DocInfoHelper::GetGeneratorString(), RTL_TEXTENCODING_UTF8); 469 Strm() 470 .WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_IGNORE LO_STRING_SVTOOLS_RTF_GENERATOR " ") 471 .WriteOString(aGenerator) 472 .WriteChar('}'); 473 Strm().WriteChar('{').WriteCharPtr(OOO_STRING_SVTOOLS_RTF_INFO); 474 475 SwDocShell* pDocShell(m_rDoc.GetDocShell()); 476 uno::Reference<document::XDocumentProperties> xDocProps; 477 if (pDocShell) 478 { 479 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(pDocShell->GetModel(), 480 uno::UNO_QUERY); 481 xDocProps.set(xDPS->getDocumentProperties()); 482 } 483 484 if (xDocProps.is()) 485 { 486 // Handle user-defined properties. 487 uno::Reference<beans::XPropertyContainer> xUserDefinedProperties 488 = xDocProps->getUserDefinedProperties(); 489 if (xUserDefinedProperties.is()) 490 { 491 uno::Reference<beans::XPropertySet> xPropertySet(xUserDefinedProperties, 492 uno::UNO_QUERY); 493 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo 494 = xPropertySet->getPropertySetInfo(); 495 // Do we have explicit markup in RTF for this property name? 496 if (xPropertySetInfo->hasPropertyByName("Company")) 497 { 498 OUString aValue; 499 xPropertySet->getPropertyValue("Company") >>= aValue; 500 OutUnicode(OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_COMPANY, aValue); 501 } 502 } 503 504 OutUnicode(OOO_STRING_SVTOOLS_RTF_TITLE, xDocProps->getTitle(), true); 505 OutUnicode(OOO_STRING_SVTOOLS_RTF_SUBJECT, xDocProps->getSubject()); 506 507 OutUnicode(OOO_STRING_SVTOOLS_RTF_KEYWORDS, 508 ::comphelper::string::convertCommaSeparated(xDocProps->getKeywords())); 509 OutUnicode(OOO_STRING_SVTOOLS_RTF_DOCCOMM, xDocProps->getDescription()); 510 511 OutUnicode(OOO_STRING_SVTOOLS_RTF_AUTHOR, xDocProps->getAuthor()); 512 OutDateTime(OOO_STRING_SVTOOLS_RTF_CREATIM, xDocProps->getCreationDate()); 513 514 OutUnicode(OOO_STRING_SVTOOLS_RTF_AUTHOR, xDocProps->getModifiedBy()); 515 OutDateTime(OOO_STRING_SVTOOLS_RTF_REVTIM, xDocProps->getModificationDate()); 516 517 OutDateTime(OOO_STRING_SVTOOLS_RTF_PRINTIM, xDocProps->getPrintDate()); 518 } 519 520 Strm().WriteChar('}'); 521 } 522 523 void RtfExport::WriteUserPropType(int nType) 524 { 525 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PROPTYPE); 526 OutULong(nType); 527 } 528 529 void RtfExport::WriteUserPropValue(const OUString& rValue) 530 { 531 Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_STATICVAL " "); 532 Strm().WriteOString(msfilter::rtfutil::OutString(rValue, m_eDefaultEncoding)); 533 Strm().WriteChar('}'); 534 } 535 536 void RtfExport::WriteUserProps() 537 { 538 Strm().WriteChar('{').WriteCharPtr( 539 OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_USERPROPS); 540 541 SwDocShell* pDocShell(m_rDoc.GetDocShell()); 542 uno::Reference<document::XDocumentProperties> xDocProps; 543 if (pDocShell) 544 { 545 uno::Reference<document::XDocumentPropertiesSupplier> xDPS(pDocShell->GetModel(), 546 uno::UNO_QUERY); 547 xDocProps.set(xDPS->getDocumentProperties()); 548 } 549 else 550 { 551 // Clipboard document, read metadata from the meta field manager. 552 sw::MetaFieldManager& rManager = m_rDoc.GetMetaFieldManager(); 553 xDocProps.set(rManager.getDocumentProperties()); 554 } 555 556 if (xDocProps.is()) 557 { 558 // Handle user-defined properties. 559 uno::Reference<beans::XPropertyContainer> xUserDefinedProperties 560 = xDocProps->getUserDefinedProperties(); 561 if (xUserDefinedProperties.is()) 562 { 563 uno::Reference<beans::XPropertySet> xPropertySet(xUserDefinedProperties, 564 uno::UNO_QUERY); 565 const uno::Sequence<beans::Property> aProperties 566 = xPropertySet->getPropertySetInfo()->getProperties(); 567 568 for (const beans::Property& rProperty : aProperties) 569 { 570 if (rProperty.Name.startsWith("Company")) 571 // We have explicit markup in RTF for this property. 572 continue; 573 574 // Property name. 575 Strm().WriteCharPtr("{" OOO_STRING_SVTOOLS_RTF_PROPNAME " "); 576 Strm().WriteCharPtr( 577 msfilter::rtfutil::OutString(rProperty.Name, m_eDefaultEncoding).getStr()); 578 Strm().WriteChar('}'); 579 580 // Property value. 581 OUString aValue; 582 double fValue; 583 bool bValue; 584 util::DateTime aDate; 585 uno::Any aAny = xPropertySet->getPropertyValue(rProperty.Name); 586 if (aAny >>= bValue) 587 { 588 WriteUserPropType(11); 589 WriteUserPropValue(OUString::number(static_cast<int>(bValue))); 590 } 591 else if (aAny >>= aValue) 592 { 593 WriteUserPropType(30); 594 WriteUserPropValue(aValue); 595 } 596 else if (aAny >>= fValue) 597 { 598 aValue = OUString::number(fValue); 599 if (aValue.indexOf('.') == -1) 600 { 601 // Integer. 602 WriteUserPropType(3); 603 WriteUserPropValue(aValue); 604 } 605 else 606 { 607 // Real number. 608 WriteUserPropType(5); 609 WriteUserPropValue(aValue); 610 } 611 } 612 else if (aAny >>= aDate) 613 { 614 WriteUserPropType(64); 615 // Format is 'YYYY. MM. DD.'. 616 aValue += OUString::number(aDate.Year) + ". "; 617 if (aDate.Month < 10) 618 aValue += "0"; 619 aValue += OUString::number(aDate.Month) + ". "; 620 if (aDate.Day < 10) 621 aValue += "0"; 622 aValue += OUString::number(aDate.Day) + "."; 623 WriteUserPropValue(aValue); 624 } 625 } 626 } 627 } 628 629 Strm().WriteChar('}'); 630 } 631 632 void RtfExport::WritePageDescTable() 633 { 634 // Write page descriptions (page styles) 635 std::size_t nSize = m_rDoc.GetPageDescCnt(); 636 if (!nSize) 637 return; 638 639 Strm().WriteCharPtr(SAL_NEWLINE_STRING); 640 m_bOutPageDescs = true; 641 Strm() 642 .WriteChar('{') 643 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE) 644 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PGDSCTBL); 645 for (std::size_t n = 0; n < nSize; ++n) 646 { 647 const SwPageDesc& rPageDesc = m_rDoc.GetPageDesc(n); 648 649 Strm() 650 .WriteCharPtr(SAL_NEWLINE_STRING) 651 .WriteChar('{') 652 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PGDSC); 653 OutULong(n).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PGDSCUSE); 654 OutULong(static_cast<sal_uLong>(rPageDesc.ReadUseOn())); 655 656 OutPageDescription(rPageDesc, false); 657 658 // search for the next page description 659 std::size_t i = nSize; 660 while (i) 661 if (rPageDesc.GetFollow() == &m_rDoc.GetPageDesc(--i)) 662 break; 663 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PGDSCNXT); 664 OutULong(i).WriteChar(' '); 665 Strm() 666 .WriteCharPtr( 667 msfilter::rtfutil::OutString(rPageDesc.GetName(), m_eDefaultEncoding).getStr()) 668 .WriteCharPtr(";}"); 669 } 670 Strm().WriteChar('}').WriteCharPtr(SAL_NEWLINE_STRING); 671 m_bOutPageDescs = false; 672 673 // reset table infos, otherwise the depth of the cells will be incorrect, 674 // in case the page style (header or footer) had tables 675 m_pTableInfo = std::make_shared<ww8::WW8TableInfo>(); 676 } 677 678 ErrCode RtfExport::ExportDocument_Impl() 679 { 680 // Make the header 681 Strm() 682 .WriteChar('{') 683 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_RTF) 684 .WriteChar('1') 685 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSI); 686 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_DEFF); 687 OutULong(m_aFontHelper.GetId(m_rDoc.GetAttrPool().GetDefaultItem(RES_CHRATR_FONT))); 688 // If this not exist, MS don't understand our ansi characters (0x80-0xff). 689 Strm().WriteCharPtr("\\adeflang1025"); 690 691 // Font table 692 WriteFonts(); 693 694 m_pStyles = std::make_unique<MSWordStyles>(*this); 695 // Color and stylesheet table 696 WriteStyles(); 697 698 // List table 699 BuildNumbering(); 700 WriteNumbering(); 701 702 WriteRevTab(); 703 704 WriteInfo(); 705 WriteUserProps(); 706 // Default TabSize 707 Strm() 708 .WriteOString(m_pAttrOutput->GetTabStop().makeStringAndClear()) 709 .WriteCharPtr(SAL_NEWLINE_STRING); 710 711 // Automatic hyphenation: it's a global setting in Word, it's a paragraph setting in Writer. 712 // Set it's value to "auto" and disable on paragraph level, if no hyphenation is used there. 713 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_HYPHAUTO); 714 OutULong(1); 715 716 // Zoom 717 SwViewShell* pViewShell(m_rDoc.getIDocumentLayoutAccess().GetCurrentViewShell()); 718 if (pViewShell && pViewShell->GetViewOptions()->GetZoomType() == SvxZoomType::PERCENT) 719 { 720 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_VIEWSCALE); 721 OutULong(pViewShell->GetViewOptions()->GetZoom()); 722 } 723 // Record changes? 724 if (RedlineFlags::On & m_nOrigRedlineFlags) 725 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_REVISIONS); 726 // Mirror margins? 727 if ((UseOnPage::Mirror & m_rDoc.GetPageDesc(0).ReadUseOn()) == UseOnPage::Mirror) 728 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MARGMIRROR); 729 // Init sections 730 m_pSections = new MSWordSections(*this); 731 732 // Page description 733 WritePageDescTable(); 734 735 // Enable form protection by default if needed, as there is no switch to 736 // enable it on a per-section basis. OTOH don't always enable it as it 737 // breaks moving of drawings - so write it only in case there is really a 738 // protected section in the document. 739 for (auto const& pSectionFormat : m_rDoc.GetSections()) 740 { 741 if (!pSectionFormat->IsInUndo() && pSectionFormat->GetProtect().IsContentProtected()) 742 { 743 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FORMPROT); 744 break; 745 } 746 } 747 748 // enable form field shading 749 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FORMSHADE); 750 751 // size and empty margins of the page 752 if (m_rDoc.GetPageDescCnt()) 753 { 754 // Seeking the first SwFormatPageDesc. If no set, the default is valid 755 const SwFormatPageDesc* pSttPgDsc = nullptr; 756 { 757 const SwNode& rSttNd 758 = *m_rDoc.GetNodes()[m_rDoc.GetNodes().GetEndOfExtras().GetIndex() + 2]; 759 const SfxItemSet* pSet = nullptr; 760 761 if (rSttNd.IsContentNode()) 762 pSet = &rSttNd.GetContentNode()->GetSwAttrSet(); 763 else if (rSttNd.IsTableNode()) 764 pSet = &rSttNd.GetTableNode()->GetTable().GetFrameFormat()->GetAttrSet(); 765 766 else if (rSttNd.IsSectionNode()) 767 pSet = &rSttNd.GetSectionNode()->GetSection().GetFormat()->GetAttrSet(); 768 769 if (pSet) 770 { 771 std::size_t nPosInDoc; 772 pSttPgDsc = &pSet->Get(RES_PAGEDESC); 773 if (!pSttPgDsc->GetPageDesc()) 774 pSttPgDsc = nullptr; 775 else if (m_rDoc.FindPageDesc(pSttPgDsc->GetPageDesc()->GetName(), &nPosInDoc)) 776 { 777 Strm() 778 .WriteChar('{') 779 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_IGNORE) 780 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PGDSCNO); 781 OutULong(nPosInDoc).WriteChar('}'); 782 } 783 } 784 } 785 const SwPageDesc& rPageDesc = pSttPgDsc ? *pSttPgDsc->GetPageDesc() : m_rDoc.GetPageDesc(0); 786 const SwFrameFormat& rFormatPage = rPageDesc.GetMaster(); 787 788 { 789 if (rPageDesc.GetLandscape()) 790 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LANDSCAPE); 791 792 const SwFormatFrameSize& rSz = rFormatPage.GetFrameSize(); 793 // Clipboard document is always created without a printer, then 794 // the size will be always LONG_MAX! Solution then is to use A4 795 if (LONG_MAX == rSz.GetHeight() || LONG_MAX == rSz.GetWidth()) 796 { 797 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PAPERH); 798 Size a4 = SvxPaperInfo::GetPaperSize(PAPER_A4); 799 OutULong(a4.Height()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PAPERW); 800 OutULong(a4.Width()); 801 } 802 else 803 { 804 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PAPERH); 805 OutULong(rSz.GetHeight()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_PAPERW); 806 OutULong(rSz.GetWidth()); 807 } 808 } 809 810 { 811 const SvxLRSpaceItem& rLR = rFormatPage.GetLRSpace(); 812 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MARGL); 813 OutLong(rLR.GetLeft()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MARGR); 814 OutLong(rLR.GetRight()); 815 } 816 817 { 818 const SvxULSpaceItem& rUL = rFormatPage.GetULSpace(); 819 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MARGT); 820 OutLong(rUL.GetUpper()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MARGB); 821 OutLong(rUL.GetLower()); 822 } 823 824 Strm() 825 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SECTD) 826 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SBKNONE); 827 m_pAttrOutput->SectFootnoteEndnotePr(); 828 // All sections are unlocked by default 829 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_SECTUNLOCKED); 830 OutLong(1); 831 OutPageDescription(rPageDesc, true); // Changed bCheckForFirstPage to true so headers 832 // following title page are correctly added - i13107 833 if (pSttPgDsc) 834 { 835 m_pCurrentPageDesc = &rPageDesc; 836 } 837 } 838 839 // line numbering 840 const SwLineNumberInfo& rLnNumInfo = m_rDoc.GetLineNumberInfo(); 841 if (rLnNumInfo.IsPaintLineNumbers()) 842 { 843 sal_uLong nLnNumRestartNo = 0; 844 if (const WW8_SepInfo* pSectionInfo = m_pSections->CurrentSectionInfo()) 845 nLnNumRestartNo = pSectionInfo->nLnNumRestartNo; 846 847 AttrOutput().SectionLineNumbering(nLnNumRestartNo, rLnNumInfo); 848 } 849 850 { 851 // write the footnotes and endnotes-out Info 852 const SwFootnoteInfo& rFootnoteInfo = m_rDoc.GetFootnoteInfo(); 853 854 const char* pOut = FTNPOS_CHAPTER == rFootnoteInfo.m_ePos ? OOO_STRING_SVTOOLS_RTF_ENDDOC 855 : OOO_STRING_SVTOOLS_RTF_FTNBJ; 856 Strm().WriteCharPtr(pOut).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_FTNSTART); 857 OutLong(rFootnoteInfo.m_nFootnoteOffset + 1); 858 859 switch (rFootnoteInfo.m_eNum) 860 { 861 case FTNNUM_PAGE: 862 pOut = OOO_STRING_SVTOOLS_RTF_FTNRSTPG; 863 break; 864 case FTNNUM_DOC: 865 pOut = OOO_STRING_SVTOOLS_RTF_FTNRSTCONT; 866 break; 867 default: 868 pOut = OOO_STRING_SVTOOLS_RTF_FTNRESTART; 869 break; 870 } 871 Strm().WriteCharPtr(pOut); 872 873 switch (rFootnoteInfo.m_aFormat.GetNumberingType()) 874 { 875 case SVX_NUM_CHARS_LOWER_LETTER: 876 case SVX_NUM_CHARS_LOWER_LETTER_N: 877 pOut = OOO_STRING_SVTOOLS_RTF_FTNNALC; 878 break; 879 case SVX_NUM_CHARS_UPPER_LETTER: 880 case SVX_NUM_CHARS_UPPER_LETTER_N: 881 pOut = OOO_STRING_SVTOOLS_RTF_FTNNAUC; 882 break; 883 case SVX_NUM_ROMAN_LOWER: 884 pOut = OOO_STRING_SVTOOLS_RTF_FTNNRLC; 885 break; 886 case SVX_NUM_ROMAN_UPPER: 887 pOut = OOO_STRING_SVTOOLS_RTF_FTNNRUC; 888 break; 889 case SVX_NUM_SYMBOL_CHICAGO: 890 pOut = OOO_STRING_SVTOOLS_RTF_FTNNCHI; 891 break; 892 default: 893 pOut = OOO_STRING_SVTOOLS_RTF_FTNNAR; 894 break; 895 } 896 Strm().WriteCharPtr(pOut); 897 898 const SwEndNoteInfo& rEndNoteInfo = m_rDoc.GetEndNoteInfo(); 899 900 Strm() 901 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_AENDDOC) 902 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_AFTNRSTCONT) 903 .WriteCharPtr(OOO_STRING_SVTOOLS_RTF_AFTNSTART); 904 OutLong(rEndNoteInfo.m_nFootnoteOffset + 1); 905 906 switch (rEndNoteInfo.m_aFormat.GetNumberingType()) 907 { 908 case SVX_NUM_CHARS_LOWER_LETTER: 909 case SVX_NUM_CHARS_LOWER_LETTER_N: 910 pOut = OOO_STRING_SVTOOLS_RTF_AFTNNALC; 911 break; 912 case SVX_NUM_CHARS_UPPER_LETTER: 913 case SVX_NUM_CHARS_UPPER_LETTER_N: 914 pOut = OOO_STRING_SVTOOLS_RTF_AFTNNAUC; 915 break; 916 case SVX_NUM_ROMAN_LOWER: 917 pOut = OOO_STRING_SVTOOLS_RTF_AFTNNRLC; 918 break; 919 case SVX_NUM_ROMAN_UPPER: 920 pOut = OOO_STRING_SVTOOLS_RTF_AFTNNRUC; 921 break; 922 case SVX_NUM_SYMBOL_CHICAGO: 923 pOut = OOO_STRING_SVTOOLS_RTF_AFTNNCHI; 924 break; 925 default: 926 pOut = OOO_STRING_SVTOOLS_RTF_AFTNNAR; 927 break; 928 } 929 Strm().WriteCharPtr(pOut); 930 } 931 932 if (!m_rDoc.getIDocumentSettingAccess().get(DocumentSettingId::PARA_SPACE_MAX)) 933 // RTF default is true, so write compat flag if this should be false. 934 Strm().WriteCharPtr(LO_STRING_SVTOOLS_RTF_HTMAUTSP); 935 936 Strm().WriteCharPtr(SAL_NEWLINE_STRING); 937 938 WriteFootnoteSettings(); 939 940 WriteMainText(); 941 942 Strm().WriteChar('}'); 943 944 return ERRCODE_NONE; 945 } 946 947 void RtfExport::PrepareNewPageDesc(const SfxItemSet* pSet, const SwNode& rNd, 948 const SwFormatPageDesc* pNewPgDescFormat, 949 const SwPageDesc* pNewPgDesc) 950 { 951 const SwSectionFormat* pFormat = GetSectionFormat(rNd); 952 const sal_uLong nLnNm = GetSectionLineNo(pSet, rNd); 953 954 OSL_ENSURE(pNewPgDescFormat || pNewPgDesc, "Neither page desc format nor page desc provided."); 955 956 if (pNewPgDescFormat) 957 m_pSections->AppendSection(*pNewPgDescFormat, rNd, pFormat, nLnNm); 958 else if (pNewPgDesc) 959 m_pSections->AppendSection(pNewPgDesc, rNd, pFormat, nLnNm); 960 961 // Don't insert a page break, when we're changing page style just because the next page has to be a different one. 962 if (!m_pAttrOutput->GetPrevPageDesc() 963 || m_pAttrOutput->GetPrevPageDesc()->GetFollow() != pNewPgDesc) 964 AttrOutput().SectionBreak(msword::PageBreak, false, m_pSections->CurrentSectionInfo()); 965 } 966 967 bool RtfExport::DisallowInheritingOutlineNumbering(const SwFormat& rFormat) 968 { 969 bool bRet(false); 970 971 if (SfxItemState::SET != rFormat.GetItemState(RES_PARATR_NUMRULE, false)) 972 { 973 if (const SwFormat* pParent = rFormat.DerivedFrom()) 974 { 975 if (static_cast<const SwTextFormatColl*>(pParent) 976 ->IsAssignedToListLevelOfOutlineStyle()) 977 { 978 // Level 9 disables the outline 979 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LEVEL).WriteInt32(9); 980 981 bRet = true; 982 } 983 } 984 } 985 986 return bRet; 987 } 988 989 void RtfExport::OutputEndNode(const SwEndNode& rEndNode) 990 { 991 if (TXT_MAINTEXT == m_nTextTyp && rEndNode.StartOfSectionNode()->IsTableNode()) 992 // End node of a table: see if a section break should be written after the table. 993 AttrOutput().SectionBreaks(rEndNode); 994 } 995 996 void RtfExport::OutputGrfNode(const SwGrfNode& /*rGrfNode*/) 997 { 998 /* noop, see RtfAttributeOutput::FlyFrameGraphic */ 999 } 1000 1001 void RtfExport::OutputOLENode(const SwOLENode& /*rOLENode*/) 1002 { 1003 /* noop, see RtfAttributeOutput::FlyFrameOLE */ 1004 } 1005 1006 void RtfExport::OutputLinkedOLE(const OUString& /*rLinked*/) {} 1007 1008 void RtfExport::OutputTextNode(SwTextNode& rNode) 1009 { 1010 m_nCurrentNodeIndex = rNode.GetIndex(); 1011 if (!m_bOutOutlineOnly || rNode.IsOutline()) 1012 MSWordExportBase::OutputTextNode(rNode); 1013 m_nCurrentNodeIndex = 0; 1014 } 1015 1016 void RtfExport::AppendSection(const SwPageDesc* pPageDesc, const SwSectionFormat* pFormat, 1017 sal_uLong nLnNum) 1018 { 1019 m_pSections->AppendSection(pPageDesc, pFormat, nLnNum); 1020 AttrOutput().SectionBreak(msword::PageBreak, false, m_pSections->CurrentSectionInfo()); 1021 } 1022 1023 RtfExport::RtfExport(RtfExportFilter* pFilter, SwDoc& rDocument, 1024 std::shared_ptr<SwUnoCursor>& pCurrentPam, SwPaM& rOriginalPam, 1025 Writer* pWriter, bool bOutOutlineOnly) 1026 : MSWordExportBase(rDocument, pCurrentPam, &rOriginalPam) 1027 , m_pFilter(pFilter) 1028 , m_pWriter(pWriter) 1029 , m_pSections(nullptr) 1030 , m_bOutOutlineOnly(bOutOutlineOnly) 1031 , m_eDefaultEncoding( 1032 rtl_getTextEncodingFromWindowsCharset(sw::ms::rtl_TextEncodingToWinCharset(DEF_ENCODING))) 1033 , m_eCurrentEncoding(m_eDefaultEncoding) 1034 , m_bRTFFlySyntax(false) 1035 , m_nCurrentNodeIndex(0) 1036 { 1037 m_bExportModeRTF = true; 1038 // the attribute output for the document 1039 m_pAttrOutput = std::make_unique<RtfAttributeOutput>(*this); 1040 // that just causes problems for RTF 1041 m_bSubstituteBullets = false; 1042 // needed to have a complete font table 1043 m_aFontHelper.bLoadAllFonts = true; 1044 // the related SdrExport 1045 m_pSdrExport = std::make_unique<RtfSdrExport>(*this); 1046 1047 if (!m_pWriter) 1048 m_pWriter = &m_pFilter->GetWriter(); 1049 } 1050 1051 RtfExport::~RtfExport() = default; 1052 1053 SvStream& RtfExport::Strm() 1054 { 1055 if (m_pStream) 1056 return *m_pStream; 1057 1058 return m_pWriter->Strm(); 1059 } 1060 1061 void RtfExport::setStream() { m_pStream = std::make_unique<SvMemoryStream>(); } 1062 1063 OString RtfExport::getStream() 1064 { 1065 OString aRet; 1066 1067 if (m_pStream) 1068 aRet = OString(static_cast<const char*>(m_pStream->GetData()), m_pStream->Tell()); 1069 1070 return aRet; 1071 } 1072 1073 void RtfExport::resetStream() { m_pStream.reset(); } 1074 1075 SvStream& RtfExport::OutULong(sal_uLong nVal) { return Writer::OutULong(Strm(), nVal); } 1076 1077 SvStream& RtfExport::OutLong(long nVal) { return Writer::OutLong(Strm(), nVal); } 1078 1079 void RtfExport::OutUnicode(const char* pToken, const OUString& rContent, bool bUpr) 1080 { 1081 if (rContent.isEmpty()) 1082 return; 1083 1084 if (!bUpr) 1085 { 1086 Strm().WriteChar('{').WriteCharPtr(pToken).WriteChar(' '); 1087 Strm().WriteCharPtr(msfilter::rtfutil::OutString(rContent, m_eCurrentEncoding).getStr()); 1088 Strm().WriteChar('}'); 1089 } 1090 else 1091 Strm().WriteCharPtr( 1092 msfilter::rtfutil::OutStringUpr(pToken, rContent, m_eCurrentEncoding).getStr()); 1093 } 1094 1095 void RtfExport::OutDateTime(const char* pStr, const util::DateTime& rDT) 1096 { 1097 Strm().WriteChar('{').WriteCharPtr(pStr).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_YR); 1098 OutULong(rDT.Year).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MO); 1099 OutULong(rDT.Month).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_DY); 1100 OutULong(rDT.Day).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_HR); 1101 OutULong(rDT.Hours).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_MIN); 1102 OutULong(rDT.Minutes).WriteChar('}'); 1103 } 1104 1105 sal_uInt16 RtfExport::GetColor(const Color& rColor) const 1106 { 1107 for (const auto& rEntry : m_aColTable) 1108 if (rEntry.second == rColor) 1109 { 1110 SAL_INFO("sw.rtf", __func__ << " returning " << rEntry.first << " (" << rColor.GetRed() 1111 << "," << rColor.GetGreen() << "," << rColor.GetBlue() 1112 << ")"); 1113 return rEntry.first; 1114 } 1115 OSL_FAIL("No such Color in m_aColTable!"); 1116 return 0; 1117 } 1118 1119 void RtfExport::InsColor(const Color& rCol) 1120 { 1121 sal_uInt16 n; 1122 bool bAutoColorInTable = false; 1123 for (const auto& rEntry : m_aColTable) 1124 { 1125 if (rEntry.second == rCol) 1126 return; // Already in the table 1127 if (rEntry.second == COL_AUTO) 1128 bAutoColorInTable = true; 1129 } 1130 if (rCol == COL_AUTO) 1131 // COL_AUTO gets value 0 1132 n = 0; 1133 else 1134 { 1135 // other colors get values >0 1136 n = m_aColTable.size(); 1137 if (!bAutoColorInTable) 1138 // reserve value "0" for COL_AUTO (if COL_AUTO wasn't inserted until now) 1139 n++; 1140 } 1141 m_aColTable.insert(std::pair<sal_uInt16, Color>(n, rCol)); 1142 } 1143 1144 void RtfExport::InsColorLine(const SvxBoxItem& rBox) 1145 { 1146 const editeng::SvxBorderLine* pLine = nullptr; 1147 1148 if (rBox.GetTop()) 1149 { 1150 pLine = rBox.GetTop(); 1151 InsColor(pLine->GetColor()); 1152 } 1153 if (rBox.GetBottom() && pLine != rBox.GetBottom()) 1154 { 1155 pLine = rBox.GetBottom(); 1156 InsColor(pLine->GetColor()); 1157 } 1158 if (rBox.GetLeft() && pLine != rBox.GetLeft()) 1159 { 1160 pLine = rBox.GetLeft(); 1161 InsColor(pLine->GetColor()); 1162 } 1163 if (rBox.GetRight() && pLine != rBox.GetRight()) 1164 InsColor(rBox.GetRight()->GetColor()); 1165 } 1166 1167 void RtfExport::OutColorTable() 1168 { 1169 // Build the table from rPool since the colors provided to 1170 // RtfAttributeOutput callbacks are too late. 1171 const SfxItemPool& rPool = m_rDoc.GetAttrPool(); 1172 1173 // MSO Word uses a default color table with 16 colors (which is used e.g. for highlighting) 1174 InsColor(COL_BLACK); 1175 InsColor(COL_LIGHTBLUE); 1176 InsColor(COL_LIGHTCYAN); 1177 InsColor(COL_LIGHTGREEN); 1178 InsColor(COL_LIGHTMAGENTA); 1179 InsColor(COL_LIGHTRED); 1180 InsColor(COL_YELLOW); 1181 InsColor(COL_WHITE); 1182 InsColor(COL_BLUE); 1183 InsColor(COL_CYAN); 1184 InsColor(COL_GREEN); 1185 InsColor(COL_MAGENTA); 1186 InsColor(COL_RED); 1187 InsColor(COL_BROWN); 1188 InsColor(COL_GRAY); 1189 InsColor(COL_LIGHTGRAY); 1190 1191 // char color 1192 { 1193 auto pCol = GetDfltAttr(RES_CHRATR_COLOR); 1194 InsColor(pCol->GetValue()); 1195 pCol = rPool.GetPoolDefaultItem(RES_CHRATR_COLOR); 1196 if (pCol) 1197 InsColor(pCol->GetValue()); 1198 for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(RES_CHRATR_COLOR)) 1199 { 1200 pCol = dynamic_cast<const SvxColorItem*>(pItem); 1201 if (pCol) 1202 InsColor(pCol->GetValue()); 1203 } 1204 1205 auto pUnder = GetDfltAttr(RES_CHRATR_UNDERLINE); 1206 InsColor(pUnder->GetColor()); 1207 for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(RES_CHRATR_UNDERLINE)) 1208 { 1209 pUnder = dynamic_cast<const SvxUnderlineItem*>(pItem); 1210 if (pUnder) 1211 InsColor(pUnder->GetColor()); 1212 } 1213 1214 auto pOver = GetDfltAttr(RES_CHRATR_OVERLINE); 1215 InsColor(pOver->GetColor()); 1216 for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(RES_CHRATR_OVERLINE)) 1217 { 1218 pOver = dynamic_cast<const SvxOverlineItem*>(pItem); 1219 if (pOver) 1220 InsColor(pOver->GetColor()); 1221 } 1222 } 1223 1224 // background color 1225 static const sal_uInt16 aBrushIds[] = { RES_BACKGROUND, RES_CHRATR_BACKGROUND, 0 }; 1226 1227 for (const sal_uInt16* pIds = aBrushIds; *pIds; ++pIds) 1228 { 1229 auto pBackground = static_cast<const SvxBrushItem*>(GetDfltAttr(*pIds)); 1230 InsColor(pBackground->GetColor()); 1231 pBackground = static_cast<const SvxBrushItem*>(rPool.GetPoolDefaultItem(*pIds)); 1232 if (pBackground) 1233 { 1234 InsColor(pBackground->GetColor()); 1235 } 1236 for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(*pIds)) 1237 { 1238 pBackground = static_cast<const SvxBrushItem*>(pItem); 1239 if (pBackground) 1240 { 1241 InsColor(pBackground->GetColor()); 1242 } 1243 } 1244 } 1245 1246 // shadow color 1247 { 1248 auto pShadow = GetDfltAttr(RES_SHADOW); 1249 InsColor(pShadow->GetColor()); 1250 pShadow = rPool.GetPoolDefaultItem(RES_SHADOW); 1251 if (nullptr != pShadow) 1252 { 1253 InsColor(pShadow->GetColor()); 1254 } 1255 for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(RES_SHADOW)) 1256 { 1257 pShadow = dynamic_cast<const SvxShadowItem*>(pItem); 1258 if (pShadow) 1259 { 1260 InsColor(pShadow->GetColor()); 1261 } 1262 } 1263 } 1264 1265 // frame border color 1266 { 1267 const SvxBoxItem* pBox = rPool.GetPoolDefaultItem(RES_BOX); 1268 if (nullptr != pBox) 1269 InsColorLine(*pBox); 1270 for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(RES_BOX)) 1271 { 1272 pBox = dynamic_cast<const SvxBoxItem*>(pItem); 1273 if (pBox) 1274 InsColorLine(*pBox); 1275 } 1276 } 1277 1278 { 1279 const SvxBoxItem* pCharBox = rPool.GetPoolDefaultItem(RES_CHRATR_BOX); 1280 if (pCharBox) 1281 InsColorLine(*pCharBox); 1282 for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(RES_CHRATR_BOX)) 1283 { 1284 pCharBox = dynamic_cast<const SvxBoxItem*>(pItem); 1285 if (pCharBox) 1286 InsColorLine(*pCharBox); 1287 } 1288 } 1289 1290 // TextFrame or paragraph background solid fill. 1291 for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(XATTR_FILLCOLOR)) 1292 { 1293 if (auto pColorItem = dynamic_cast<const XFillColorItem*>(pItem)) 1294 InsColor(pColorItem->GetColorValue()); 1295 } 1296 1297 for (std::size_t n = 0; n < m_aColTable.size(); ++n) 1298 { 1299 const Color& rCol = m_aColTable[n]; 1300 if (n || COL_AUTO != rCol) 1301 { 1302 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_RED); 1303 OutULong(rCol.GetRed()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_GREEN); 1304 OutULong(rCol.GetGreen()).WriteCharPtr(OOO_STRING_SVTOOLS_RTF_BLUE); 1305 OutULong(rCol.GetBlue()); 1306 } 1307 Strm().WriteChar(';'); 1308 } 1309 } 1310 1311 void RtfExport::InsStyle(sal_uInt16 nId, const OString& rStyle) 1312 { 1313 m_aStyTable.insert(std::pair<sal_uInt16, OString>(nId, rStyle)); 1314 } 1315 1316 OString* RtfExport::GetStyle(sal_uInt16 nId) 1317 { 1318 auto it = m_aStyTable.find(nId); 1319 if (it != m_aStyTable.end()) 1320 return &it->second; 1321 return nullptr; 1322 } 1323 1324 sal_uInt16 RtfExport::GetRedline(const OUString& rAuthor) 1325 { 1326 auto it = m_aRedlineTable.find(rAuthor); 1327 if (it != m_aRedlineTable.end()) 1328 return it->second; 1329 1330 const sal_uInt16 nId = m_aRedlineTable.size(); 1331 m_aRedlineTable.insert(std::pair<OUString, sal_uInt16>(rAuthor, nId)); 1332 return nId; 1333 } 1334 1335 const OUString* RtfExport::GetRedline(sal_uInt16 nId) 1336 { 1337 for (const auto& rEntry : m_aRedlineTable) 1338 if (rEntry.second == nId) 1339 return &rEntry.first; 1340 return nullptr; 1341 } 1342 1343 void RtfExport::OutPageDescription(const SwPageDesc& rPgDsc, bool bCheckForFirstPage) 1344 { 1345 SAL_INFO("sw.rtf", __func__ << " start"); 1346 const SwPageDesc* pSave = m_pCurrentPageDesc; 1347 1348 m_pCurrentPageDesc = &rPgDsc; 1349 if (bCheckForFirstPage && m_pCurrentPageDesc->GetFollow() 1350 && m_pCurrentPageDesc->GetFollow() != m_pCurrentPageDesc) 1351 m_pCurrentPageDesc = m_pCurrentPageDesc->GetFollow(); 1352 1353 if (m_pCurrentPageDesc->GetLandscape()) 1354 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_LNDSCPSXN); 1355 1356 const SwFormat* pFormat = &m_pCurrentPageDesc->GetMaster(); //GetLeft(); 1357 m_bOutPageDescs = true; 1358 if (m_pCurrentPageDesc != &rPgDsc) 1359 m_pFirstPageItemSet = &rPgDsc.GetMaster().GetAttrSet(); 1360 OutputFormat(*pFormat, true, false); 1361 m_pFirstPageItemSet = nullptr; 1362 m_bOutPageDescs = false; 1363 1364 // normal header / footer (without a style) 1365 const SfxPoolItem* pItem; 1366 if (m_pCurrentPageDesc->GetLeft().GetAttrSet().GetItemState(RES_HEADER, false, &pItem) 1367 == SfxItemState::SET) 1368 WriteHeaderFooter(*pItem, true); 1369 if (m_pCurrentPageDesc->GetLeft().GetAttrSet().GetItemState(RES_FOOTER, false, &pItem) 1370 == SfxItemState::SET) 1371 WriteHeaderFooter(*pItem, false); 1372 1373 // title page 1374 if (m_pCurrentPageDesc != &rPgDsc) 1375 { 1376 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_TITLEPG); 1377 m_pCurrentPageDesc = &rPgDsc; 1378 if (m_pCurrentPageDesc->GetMaster().GetAttrSet().GetItemState(RES_HEADER, false, &pItem) 1379 == SfxItemState::SET) 1380 WriteHeaderFooter(*pItem, true); 1381 if (m_pCurrentPageDesc->GetMaster().GetAttrSet().GetItemState(RES_FOOTER, false, &pItem) 1382 == SfxItemState::SET) 1383 WriteHeaderFooter(*pItem, false); 1384 } 1385 1386 // numbering type 1387 AttrOutput().SectionPageNumbering(m_pCurrentPageDesc->GetNumType().GetNumberingType(), 1388 std::nullopt); 1389 1390 m_pCurrentPageDesc = pSave; 1391 SAL_INFO("sw.rtf", __func__ << " end"); 1392 } 1393 1394 void RtfExport::WriteHeaderFooter(const SfxPoolItem& rItem, bool bHeader) 1395 { 1396 if (bHeader) 1397 { 1398 const auto& rHeader = static_cast<const SwFormatHeader&>(rItem); 1399 if (!rHeader.IsActive()) 1400 return; 1401 } 1402 else 1403 { 1404 const auto& rFooter = static_cast<const SwFormatFooter&>(rItem); 1405 if (!rFooter.IsActive()) 1406 return; 1407 } 1408 1409 SAL_INFO("sw.rtf", __func__ << " start"); 1410 1411 const char* pStr = (bHeader ? OOO_STRING_SVTOOLS_RTF_HEADER : OOO_STRING_SVTOOLS_RTF_FOOTER); 1412 /* is this a title page? */ 1413 if (m_pCurrentPageDesc->GetFollow() && m_pCurrentPageDesc->GetFollow() != m_pCurrentPageDesc) 1414 { 1415 Strm().WriteCharPtr(OOO_STRING_SVTOOLS_RTF_TITLEPG); 1416 pStr = (bHeader ? OOO_STRING_SVTOOLS_RTF_HEADERF : OOO_STRING_SVTOOLS_RTF_FOOTERF); 1417 } 1418 Strm().WriteChar('{').WriteCharPtr(pStr); 1419 WriteHeaderFooterText(m_pCurrentPageDesc->GetMaster(), bHeader); 1420 Strm().WriteChar('}'); 1421 1422 SAL_INFO("sw.rtf", __func__ << " end"); 1423 } 1424 1425 void RtfExport::WriteHeaderFooter(const SwFrameFormat& rFormat, bool bHeader, const char* pStr, 1426 bool bTitlepg) 1427 { 1428 SAL_INFO("sw.rtf", __func__ << " start"); 1429 1430 m_pAttrOutput->WriteHeaderFooter_Impl(rFormat, bHeader, pStr, bTitlepg); 1431 1432 SAL_INFO("sw.rtf", __func__ << " end"); 1433 } 1434 1435 namespace 1436 { 1437 /// Glue class to call RtfExport as an internal filter, needed by copy&paste support. 1438 class SwRTFWriter : public Writer 1439 { 1440 private: 1441 bool m_bOutOutlineOnly; 1442 1443 public: 1444 SwRTFWriter(const OUString& rFilterName, const OUString& rBaseURL); 1445 1446 ErrCode WriteStream() override; 1447 }; 1448 } 1449 1450 SwRTFWriter::SwRTFWriter(const OUString& rFilterName, const OUString& rBaseURL) 1451 { 1452 SetBaseURL(rBaseURL); 1453 // export outline nodes, only (send outline to clipboard/presentation) 1454 m_bOutOutlineOnly = rFilterName.startsWith("O"); 1455 } 1456 1457 ErrCode SwRTFWriter::WriteStream() 1458 { 1459 std::shared_ptr<SwUnoCursor> pCurPam(m_pDoc->CreateUnoCursor(*m_pCurrentPam->End(), false)); 1460 pCurPam->SetMark(); 1461 *pCurPam->GetPoint() = *m_pCurrentPam->Start(); 1462 RtfExport aExport(nullptr, *m_pDoc, pCurPam, *m_pCurrentPam, this, m_bOutOutlineOnly); 1463 aExport.ExportDocument(true); 1464 return ERRCODE_NONE; 1465 } 1466 1467 extern "C" SAL_DLLPUBLIC_EXPORT void ExportRTF(const OUString& rFltName, const OUString& rBaseURL, 1468 WriterRef& xRet) 1469 { 1470 xRet = new SwRTFWriter(rFltName, rBaseURL); 1471 } 1472 1473 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1474
