/* -*- 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 #include "rtfexportfilter.hxx" #include "rtfsdrexport.hxx" #include "rtfattributeoutput.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ww8par.hxx" #include #include #include #include #include #include #if OSL_DEBUG_LEVEL > 1 #include #endif using ::editeng::SvxBorderLine; using namespace ::comphelper; using namespace ::com::sun::star; using sw::mark::IMark; #if defined(UNX) const sal_Char RtfExport::sNewLine = '\012'; #else const sal_Char* const RtfExport::sNewLine = "\015\012"; #endif // 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 SwTxtNode& rNode, xub_StrLen nAktPos, xub_StrLen nLen ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); std::vector< OUString > aStarts; std::vector< OUString > aEnds; IMarkVector aMarks; if ( GetBookmarks( rNode, nAktPos, nAktPos + nLen, aMarks ) ) { for ( IMarkVector::const_iterator it = aMarks.begin(), end = aMarks.end(); it != end; ++it ) { IMark* pMark = (*it); xub_StrLen nStart = pMark->GetMarkStart().nContent.GetIndex(); xub_StrLen nEnd = pMark->GetMarkEnd().nContent.GetIndex(); if ( nStart == nAktPos ) aStarts.push_back( pMark->GetName() ); if ( nEnd == nAktPos ) aEnds.push_back( pMark->GetName() ); } } m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds ); } void RtfExport::AppendBookmark( const OUString& rName, bool /*bSkip*/ ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); std::vector aStarts; std::vector aEnds; aStarts.push_back(rName); aEnds.push_back(rName); m_pAttrOutput->WriteBookmarks_Impl(aStarts, aEnds); } //For i120928,to export graphic of bullet for RTF filter void RtfExport::ExportGrfBullet(const SwTxtNode&) { // Noop, would be too late, see WriteNumbering() instead. } void RtfExport::WriteChar( sal_Unicode ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); /* WriteChar() has nothing to do for rtf. */ } static bool IsExportNumRule( const SwNumRule& rRule, sal_uInt8* pEnd = 0 ) { sal_uInt8 nEnd = MAXLEVEL; while( nEnd-- && !rRule.GetNumFmt( nEnd )) ; ++nEnd; const SwNumFmt* pNFmt; sal_uInt8 nLvl; for( nLvl = 0; nLvl < nEnd; ++nLvl ) if( SVX_NUM_NUMBER_NONE != ( pNFmt = &rRule.Get( nLvl )) ->GetNumberingType() || !pNFmt->GetPrefix().isEmpty() || (!pNFmt->GetSuffix().isEmpty() && !pNFmt->GetSuffix().equals(aDotStr)) ) break; if( pEnd ) *pEnd = nEnd; return nLvl != nEnd; } void RtfExport::BuildNumbering() { const SwNumRuleTbl& rListTbl = pDoc->GetNumRuleTbl(); for( sal_uInt16 n = rListTbl.size()+1; n; ) { SwNumRule* pRule; --n; if( n == rListTbl.size() ) pRule = (SwNumRule*)pDoc->GetOutlineNumRule(); else { pRule = rListTbl[ n ]; if( !pDoc->IsUsed( *pRule )) continue; } if( IsExportNumRule( *pRule )) GetId( *pRule ); } } void RtfExport::WriteNumbering() { SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start"); if ( !pUsedNumTbl ) return; // no numbering is used Strm() << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << OOO_STRING_SVTOOLS_RTF_LISTTABLE; CollectGrfsOfBullets(); if (!m_vecBulletPic.empty()) Strm() << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << LO_STRING_SVTOOLS_RTF_LISTPICTURE; BulletDefinitions(); if (!m_vecBulletPic.empty()) Strm() << '}'; AbstractNumberingDefinitions(); Strm() << '}'; Strm() << '{' << OOO_STRING_SVTOOLS_RTF_LISTOVERRIDETABLE; NumberingDefinitions(); Strm() << '}'; SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end"); } void RtfExport::WriteRevTab() { SAL_INFO("sw.rtf", OSL_THIS_FUNC); int nRevAuthors = pDoc->GetRedlineTbl().size(); if (nRevAuthors < 1) return; // RTF always seems to use Unknown as the default first entry GetRedline(OUString("Unknown")); for( sal_uInt16 i = 0; i < pDoc->GetRedlineTbl().size(); ++i ) { const SwRedline* pRedl = pDoc->GetRedlineTbl()[ i ]; GetRedline(SW_MOD()->GetRedlineAuthor(pRedl->GetAuthor())); } // Now write the table Strm() << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << OOO_STRING_SVTOOLS_RTF_REVTBL << ' '; for(sal_uInt16 i = 0; i < m_aRedlineTbl.size(); ++i) { const String* pAuthor = GetRedline(i); Strm() << '{'; if (pAuthor) Strm() << msfilter::rtfutil::OutString(*pAuthor, eDefaultEncoding).getStr(); Strm() << ";}"; } Strm() << '}' << sNewLine; } void RtfExport::WriteHeadersFooters( sal_uInt8 nHeadFootFlags, const SwFrmFmt& rFmt, const SwFrmFmt& rLeftFmt, const SwFrmFmt& rFirstPageFmt, sal_uInt8 /*nBreakCode*/ ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); // headers if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_EVEN ) WriteHeaderFooter( rLeftFmt, true, OOO_STRING_SVTOOLS_RTF_HEADERL ); if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD ) WriteHeaderFooter( rFmt, true, OOO_STRING_SVTOOLS_RTF_HEADER ); if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_FIRST ) WriteHeaderFooter( rFirstPageFmt, true, OOO_STRING_SVTOOLS_RTF_HEADERF, true ); // footers if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_EVEN ) WriteHeaderFooter( rLeftFmt, false, OOO_STRING_SVTOOLS_RTF_FOOTERL ); if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD ) WriteHeaderFooter( rFmt, false, OOO_STRING_SVTOOLS_RTF_FOOTER ); if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_FIRST ) WriteHeaderFooter( rFirstPageFmt, false, OOO_STRING_SVTOOLS_RTF_FOOTERF, true ); } void RtfExport::OutputField( const SwField* pFld, ww::eField eFldType, const String& rFldCmd, sal_uInt8 nMode ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); m_pAttrOutput->WriteField_Impl( pFld, eFldType, rFldCmd, 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& /*rListItems*/) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); // this is handled in RtfAttributeOutput::OutputFlyFrame_Impl } void RtfExport::DoFormText(const SwInputField* pFld ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); OUString sResult = pFld->ExpandField(true); OUString sHelp( pFld->GetHelp() ); OUString sName = pFld->GetPar2(); OUString sStatus = pFld->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( !sHelp.isEmpty() ) m_pAttrOutput->RunText().append( OOO_STRING_SVTOOLS_RTF_FFOWNHELP ); if( !sStatus.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, eDefaultEncoding )).append( "}" ); if( !sHelp.isEmpty() ) m_pAttrOutput->RunText().append( "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFHELPTEXT " ").append( msfilter::rtfutil::OutString( sHelp, eDefaultEncoding )).append( "}" ); m_pAttrOutput->RunText().append( "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFDEFTEXT " ").append( msfilter::rtfutil::OutString( sResult, eDefaultEncoding )).append( "}" ); if( !sStatus.isEmpty() ) m_pAttrOutput->RunText().append( "{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFSTATTEXT " ").append( msfilter::rtfutil::OutString( sStatus, eDefaultEncoding )).append( "}"); m_pAttrOutput->RunText().append( "}}}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " " ); m_pAttrOutput->RunText().append( msfilter::rtfutil::OutString( sResult, eDefaultEncoding )).append( "}}" ); } sal_uLong RtfExport::ReplaceCr( sal_uInt8 ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); // Completely unused for Rtf export... only here for code sharing // purpose with binary export return 0; } void RtfExport::WriteFonts() { Strm() << sNewLine << '{' << OOO_STRING_SVTOOLS_RTF_FONTTBL; maFontHelper.WriteFontTable( *m_pAttrOutput ); Strm() << '}'; } void RtfExport::WriteStyles() { SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start"); pStyles->OutputStylesTable(); SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end"); } void RtfExport::WriteMainText() { SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start"); pCurPam->GetPoint()->nNode = pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex(); WriteText(); SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end"); } void RtfExport::WriteInfo() { SAL_INFO("sw.rtf", OSL_THIS_FUNC); Strm() << '{' << OOO_STRING_SVTOOLS_RTF_INFO; SwDocShell *pDocShell(pDoc->GetDocShell()); uno::Reference xDocProps; if (pDocShell) { uno::Reference xDPS( pDocShell->GetModel(), uno::UNO_QUERY); xDocProps.set(xDPS->getDocumentProperties()); } if (xDocProps.is()) { 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() << '{' << OOO_STRING_SVTOOLS_RTF_COMMENT << " "; Strm() << OUStringToOString( utl::ConfigManager::getProductName(), eCurrentEncoding).getStr() << "}{" << OOO_STRING_SVTOOLS_RTF_VERN; // The convention that we follow is that the version number // should be a non-negative 32-bit int #if LIBO_VERSION_MAJOR > 127 #error Major version number must be less than 128 #elif LIBO_VERSION_MINOR > 255 || LIBO_VERSION_MICRO > 255 || LIBO_VERSION_PATCH > 255 #error Minor, micro and patchlevel version numbers must be less than 256 #endif Strm().WriteNumber((sal_Int32) LIBO_VERSION_ENCODED_IN_32BITS) << '}'; Strm() << '}'; } void RtfExport::WritePageDescTable() { SAL_INFO("sw.rtf", OSL_THIS_FUNC); // Write page descriptions (page styles) sal_uInt16 nSize = pDoc->GetPageDescCnt(); if( !nSize ) return; Strm() << sNewLine; // a separator bOutPageDescs = sal_True; Strm() << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << OOO_STRING_SVTOOLS_RTF_PGDSCTBL; for( sal_uInt16 n = 0; n < nSize; ++n ) { const SwPageDesc& rPageDesc = pDoc->GetPageDesc( n ); Strm() << sNewLine << '{' << OOO_STRING_SVTOOLS_RTF_PGDSC; OutULong( n ) << OOO_STRING_SVTOOLS_RTF_PGDSCUSE; OutULong( rPageDesc.ReadUseOn() ); OutPageDescription( rPageDesc, false, false ); // search for the next page description sal_uInt16 i = nSize; while( i ) if( rPageDesc.GetFollow() == &pDoc->GetPageDesc( --i ) ) break; Strm() << OOO_STRING_SVTOOLS_RTF_PGDSCNXT; OutULong( i ) << ' '; Strm() << msfilter::rtfutil::OutString( rPageDesc.GetName(), eDefaultEncoding).getStr() << ";}"; } Strm() << '}' << sNewLine; bOutPageDescs = sal_False; // reset table infos, otherwise the depth of the cells will be incorrect, // in case the page style (header or footer) had tables mpTableInfo = ww8::WW8TableInfo::Pointer_t(new ww8::WW8TableInfo()); } void RtfExport::ExportDocument_Impl() { // Make the header Strm() << '{' << OOO_STRING_SVTOOLS_RTF_RTF << '1' << OOO_STRING_SVTOOLS_RTF_ANSI; Strm() << OOO_STRING_SVTOOLS_RTF_DEFF; OutULong( maFontHelper.GetId( (SvxFontItem&)pDoc->GetAttrPool().GetDefaultItem( RES_CHRATR_FONT ) )); // If this not exist, MS don't understand our ansi characters (0x80-0xff). Strm() << "\\adeflang1025"; // Font table WriteFonts(); pStyles = new MSWordStyles( *this ); // Color and stylesheet table WriteStyles(); // List table BuildNumbering(); WriteNumbering(); WriteRevTab(); WriteInfo(); // Default TabSize Strm() << m_pAttrOutput->m_aTabStop.makeStringAndClear().getStr() << sNewLine; // Zoom ViewShell *pViewShell(pDoc->GetCurrentViewShell()); if (pViewShell && pViewShell->GetViewOptions()->GetZoomType() == SVX_ZOOM_PERCENT) { Strm() << OOO_STRING_SVTOOLS_RTF_VIEWSCALE; OutULong(pViewShell->GetViewOptions()->GetZoom()); } // Record changes? if (nsRedlineMode_t::REDLINE_ON & mnRedlineMode) Strm() << OOO_STRING_SVTOOLS_RTF_REVISIONS; // 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 = pDoc->GetAttrPool(); sal_uInt32 const nMaxItem = rPool.GetItemCount2(RES_PROTECT); for (sal_uInt32 n = 0; n < nMaxItem; ++n) { const SvxProtectItem* pProtect = (const SvxProtectItem*)rPool.GetItem2(RES_PROTECT, n); if (pProtect && pProtect->IsCntntProtected()) { Strm() << OOO_STRING_SVTOOLS_RTF_FORMPROT; break; } } } // enable form field shading Strm() << OOO_STRING_SVTOOLS_RTF_FORMSHADE; // size and empty margins of the page if( pDoc->GetPageDescCnt() ) { // Seeking the first SwFmtPageDesc. If no set, the default is valid const SwFmtPageDesc* pSttPgDsc = 0; { const SwNode& rSttNd = *pDoc->GetNodes()[ pDoc->GetNodes().GetEndOfExtras().GetIndex() + 2 ]; const SfxItemSet* pSet = 0; if( rSttNd.IsCntntNode() ) pSet = &rSttNd.GetCntntNode()->GetSwAttrSet(); else if( rSttNd.IsTableNode() ) pSet = &rSttNd.GetTableNode()->GetTable(). GetFrmFmt()->GetAttrSet(); else if( rSttNd.IsSectionNode() ) pSet = &rSttNd.GetSectionNode()->GetSection(). GetFmt()->GetAttrSet(); if( pSet ) { sal_uInt16 nPosInDoc; pSttPgDsc = (SwFmtPageDesc*)&pSet->Get( RES_PAGEDESC ); if( !pSttPgDsc->GetPageDesc() ) pSttPgDsc = 0; else if( pDoc->FindPageDescByName( pSttPgDsc-> GetPageDesc()->GetName(), &nPosInDoc )) { Strm() << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << OOO_STRING_SVTOOLS_RTF_PGDSCNO; OutULong( nPosInDoc ) << '}'; } } } const SwPageDesc& rPageDesc = pSttPgDsc ? *pSttPgDsc->GetPageDesc() : pDoc->GetPageDesc( 0 ); const SwFrmFmt &rFmtPage = rPageDesc.GetMaster(); { if( rPageDesc.GetLandscape() ) Strm() << OOO_STRING_SVTOOLS_RTF_LANDSCAPE; const SwFmtFrmSize& rSz = rFmtPage.GetFrmSize(); // 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() << OOO_STRING_SVTOOLS_RTF_PAPERH; Size a4 = SvxPaperInfo::GetPaperSize(PAPER_A4); OutULong( a4.Height() ) << OOO_STRING_SVTOOLS_RTF_PAPERW; OutULong( a4.Width() ); } else { Strm() << OOO_STRING_SVTOOLS_RTF_PAPERH; OutULong( rSz.GetHeight() ) << OOO_STRING_SVTOOLS_RTF_PAPERW; OutULong( rSz.GetWidth() ); } } { const SvxLRSpaceItem& rLR = rFmtPage.GetLRSpace(); Strm() << OOO_STRING_SVTOOLS_RTF_MARGL; OutLong( rLR.GetLeft() ) << OOO_STRING_SVTOOLS_RTF_MARGR; OutLong( rLR.GetRight() ); } { const SvxULSpaceItem& rUL = rFmtPage.GetULSpace(); Strm() << OOO_STRING_SVTOOLS_RTF_MARGT; OutLong( rUL.GetUpper() ) << OOO_STRING_SVTOOLS_RTF_MARGB; OutLong( rUL.GetLower() ); } Strm() << OOO_STRING_SVTOOLS_RTF_SECTD << OOO_STRING_SVTOOLS_RTF_SBKNONE; // All sections are unlocked by default Strm() << OOO_STRING_SVTOOLS_RTF_SECTUNLOCKED; OutLong(1); OutPageDescription( rPageDesc, false, true ); // Changed bCheckForFirstPage to sal_True so headers // following title page are correctly added - i13107 if( pSttPgDsc ) { pAktPageDesc = &rPageDesc; } } // line numbering const SwLineNumberInfo& rLnNumInfo = pDoc->GetLineNumberInfo(); if ( rLnNumInfo.IsPaintLineNumbers() ) AttrOutput().SectionLineNumbering( 0, rLnNumInfo ); { // write the footnotes and endnotes-out Info const SwFtnInfo& rFtnInfo = pDoc->GetFtnInfo(); const char* pOut = FTNPOS_CHAPTER == rFtnInfo.ePos ? OOO_STRING_SVTOOLS_RTF_ENDDOC : OOO_STRING_SVTOOLS_RTF_FTNBJ; Strm() << pOut << OOO_STRING_SVTOOLS_RTF_FTNSTART; OutLong( rFtnInfo.nFtnOffset + 1 ); switch( rFtnInfo.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() << pOut; switch( rFtnInfo.aFmt.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() << pOut; const SwEndNoteInfo& rEndNoteInfo = pDoc->GetEndNoteInfo(); Strm() << OOO_STRING_SVTOOLS_RTF_AENDDOC << OOO_STRING_SVTOOLS_RTF_AFTNRSTCONT << OOO_STRING_SVTOOLS_RTF_AFTNSTART; OutLong( rEndNoteInfo.nFtnOffset + 1 ); switch( rEndNoteInfo.aFmt.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() << pOut; } Strm() << sNewLine; // Init sections m_pSections = new MSWordSections( *this ); WriteMainText(); Strm() << '}'; } void RtfExport::PrepareNewPageDesc( const SfxItemSet* pSet, const SwNode& rNd, const SwFmtPageDesc* pNewPgDescFmt, const SwPageDesc* pNewPgDesc ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); const SwSectionFmt* pFmt = GetSectionFormat( rNd ); const sal_uLong nLnNm = GetSectionLineNo( pSet, rNd ); OSL_ENSURE( pNewPgDescFmt || pNewPgDesc, "Neither page desc format nor page desc provided." ); if ( pNewPgDescFmt ) m_pSections->AppendSection( *pNewPgDescFmt, rNd, pFmt, nLnNm ); else if ( pNewPgDesc ) m_pSections->AppendSection( pNewPgDesc, rNd, pFmt, 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 SwFmt& rFmt ) { bool bRet( false ); SAL_INFO("sw.rtf", OSL_THIS_FUNC); if (SFX_ITEM_SET != rFmt.GetItemState(RES_PARATR_NUMRULE, false)) { if (const SwFmt *pParent = rFmt.DerivedFrom()) { if (((const SwTxtFmtColl*)pParent)->IsAssignedToListLevelOfOutlineStyle()) { // Level 9 disables the outline Strm() << OOO_STRING_SVTOOLS_RTF_LEVEL << sal_Int32(9); bRet = true; } } } return bRet; } void RtfExport::OutputGrfNode( const SwGrfNode& ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); /* noop, see RtfAttributeOutput::FlyFrameGraphic */ } void RtfExport::OutputOLENode( const SwOLENode& ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); /* noop, see RtfAttributeOutput::FlyFrameOLE */ } void RtfExport::OutputLinkedOLE( const OUString& ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); } void RtfExport::OutputTextNode( const SwTxtNode& rNode ) { if ( !m_bOutOutlineOnly || rNode.IsOutline( ) ) MSWordExportBase::OutputTextNode( rNode ); } void RtfExport::AppendSection( const SwPageDesc* pPageDesc, const SwSectionFmt* pFmt, sal_uLong nLnNum ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); m_pSections->AppendSection( pPageDesc, pFmt, 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_pAttrOutput( NULL ), m_pSections( NULL ), m_pSdrExport( NULL ), m_bOutOutlineOnly( bOutOutlineOnly ), eDefaultEncoding( rtl_getTextEncodingFromWindowsCharset( sw::ms::rtl_TextEncodingToWinCharset(DEF_ENCODING))), eCurrentEncoding(eDefaultEncoding), bRTFFlySyntax(false) { mbExportModeRTF = true; // the attribute output for the document m_pAttrOutput = new RtfAttributeOutput( *this ); // that just causes problems for RTF bSubstituteBullets = false; // needed to have a complete font table maFontHelper.bLoadAllFonts = true; // the related SdrExport m_pSdrExport = new RtfSdrExport( *this ); if (!m_pWriter) m_pWriter = &m_pFilter->m_aWriter; } RtfExport::~RtfExport() { delete m_pAttrOutput, m_pAttrOutput = NULL; delete m_pSdrExport, m_pSdrExport = NULL; } SvStream& RtfExport::Strm() { return m_pWriter->Strm(); } SvStream& RtfExport::OutULong( sal_uLong nVal ) { return m_pWriter->OutULong( Strm(), nVal ); } SvStream& RtfExport::OutLong( long nVal ) { return m_pWriter->OutLong( Strm(), nVal ); } void RtfExport::OutUnicode(const sal_Char *pToken, const String &rContent, bool bUpr) { if (rContent.Len()) { if (!bUpr) { Strm() << '{' << pToken << ' '; Strm() << msfilter::rtfutil::OutString( rContent, eCurrentEncoding ).getStr(); Strm() << '}'; } else Strm() << msfilter::rtfutil::OutStringUpr(pToken, rContent, eCurrentEncoding).getStr(); } } void RtfExport::OutDateTime(const sal_Char* pStr, const util::DateTime& rDT ) { Strm() << '{' << pStr << OOO_STRING_SVTOOLS_RTF_YR; OutULong( rDT.Year ) << OOO_STRING_SVTOOLS_RTF_MO; OutULong( rDT.Month ) << OOO_STRING_SVTOOLS_RTF_DY; OutULong( rDT.Day ) << OOO_STRING_SVTOOLS_RTF_HR; OutULong( rDT.Hours ) << OOO_STRING_SVTOOLS_RTF_MIN; OutULong( rDT.Minutes ) << '}'; } sal_uInt16 RtfExport::GetColor( const Color& rColor ) const { for (RtfColorTbl::const_iterator it=m_aColTbl.begin() ; it != m_aColTbl.end(); ++it ) if ((*it).second == rColor) { SAL_INFO("sw.rtf", OSL_THIS_FUNC << " returning " << (*it).first << " (" << rColor.GetRed() << "," << rColor.GetGreen() << "," << rColor.GetBlue() << ")"); return (*it).first; } OSL_FAIL( "No such Color in m_aColTbl!" ); return 0; } void RtfExport::InsColor( const Color& rCol ) { sal_uInt16 n; bool bAutoColorInTable = false; for (RtfColorTbl::iterator it=m_aColTbl.begin() ; it != m_aColTbl.end(); ++it ) if ((*it).second == rCol) return; // Already in the table else if ((*it).second == COL_AUTO) bAutoColorInTable = true; if (rCol.GetColor() == COL_AUTO) // COL_AUTO gets value 0 n = 0; else { // other colors get values >0 n = m_aColTbl.size(); if (!bAutoColorInTable) // reserve value "0" for COL_AUTO (if COL_AUTO wasn't inserted until now) n++; } m_aColTbl.insert(std::pair( n, rCol )); } void RtfExport::InsColorLine( const SvxBoxItem& rBox ) { const SvxBorderLine* pLine = 0; 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 = pDoc->GetAttrPool(); // char color { const SvxColorItem* pCol = (const SvxColorItem*)GetDfltAttr( RES_CHRATR_COLOR ); InsColor( pCol->GetValue() ); if( 0 != ( pCol = (const SvxColorItem*)rPool.GetPoolDefaultItem( RES_CHRATR_COLOR ) )) InsColor( pCol->GetValue() ); nMaxItem = rPool.GetItemCount2(RES_CHRATR_COLOR); for (sal_uInt32 n = 0; n < nMaxItem; ++n) { if( 0 != (pCol = (const SvxColorItem*)rPool.GetItem2( RES_CHRATR_COLOR, n ) ) ) InsColor( pCol->GetValue() ); } const SvxUnderlineItem* pUnder = (const SvxUnderlineItem*)GetDfltAttr( RES_CHRATR_UNDERLINE ); InsColor( pUnder->GetColor() ); nMaxItem = rPool.GetItemCount2(RES_CHRATR_UNDERLINE); for (sal_uInt32 n = 0; n < nMaxItem; ++n) { if( 0 != (pUnder = (const SvxUnderlineItem*)rPool.GetItem2( RES_CHRATR_UNDERLINE, n ) ) ) InsColor( pUnder->GetColor() ); } const SvxOverlineItem* pOver = (const SvxOverlineItem*)GetDfltAttr( RES_CHRATR_OVERLINE ); InsColor( pOver->GetColor() ); nMaxItem = rPool.GetItemCount2(RES_CHRATR_OVERLINE); for (sal_uInt32 n = 0; n < nMaxItem; ++n) { if( 0 != (pOver = (const SvxOverlineItem*)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 ) { const SvxBrushItem* pBkgrd = (const SvxBrushItem*)GetDfltAttr( *pIds ); InsColor( pBkgrd->GetColor() ); if( 0 != ( pBkgrd = (const SvxBrushItem*)rPool.GetPoolDefaultItem( *pIds ) )) { InsColor( pBkgrd->GetColor() ); } nMaxItem = rPool.GetItemCount2( *pIds ); for (sal_uInt32 n = 0; n < nMaxItem; ++n) { if( 0 != (pBkgrd = (const SvxBrushItem*)rPool.GetItem2( *pIds , n ) )) { InsColor( pBkgrd->GetColor() ); } } } // shadow color { const SvxShadowItem* pShadow = (const SvxShadowItem*)GetDfltAttr( RES_SHADOW ); InsColor( pShadow->GetColor() ); if( 0 != ( pShadow = (const SvxShadowItem*)rPool.GetPoolDefaultItem( RES_SHADOW ) )) { InsColor( pShadow->GetColor() ); } nMaxItem = rPool.GetItemCount2(RES_SHADOW); for (sal_uInt32 n = 0; n < nMaxItem; ++n) { if( 0 != (pShadow = (const SvxShadowItem*)rPool.GetItem2( RES_SHADOW, n ) ) ) { InsColor( pShadow->GetColor() ); } } } // frame border color { const SvxBoxItem* pBox; if( 0 != ( pBox = (const SvxBoxItem*)rPool.GetPoolDefaultItem( RES_BOX ) )) InsColorLine( *pBox ); nMaxItem = rPool.GetItemCount2(RES_BOX); for (sal_uInt32 n = 0; n < nMaxItem; ++n) { if( 0 != (pBox = (const SvxBoxItem*)rPool.GetItem2( RES_BOX, n ) )) InsColorLine( *pBox ); } } for (size_t n = 0; n < m_aColTbl.size(); ++n) { const Color& rCol = m_aColTbl[ n ]; if( n || COL_AUTO != rCol.GetColor() ) { Strm() << OOO_STRING_SVTOOLS_RTF_RED; OutULong( rCol.GetRed() ) << OOO_STRING_SVTOOLS_RTF_GREEN; OutULong( rCol.GetGreen() ) << OOO_STRING_SVTOOLS_RTF_BLUE; OutULong( rCol.GetBlue() ); } Strm() << ';'; } } void RtfExport::InsStyle( sal_uInt16 nId, const OString& rStyle ) { m_aStyTbl.insert(std::pair(nId, rStyle) ); } OString* RtfExport::GetStyle( sal_uInt16 nId ) { std::map::iterator i = m_aStyTbl.find(nId); if (i != m_aStyTbl.end()) return &i->second; return NULL; } sal_uInt16 RtfExport::GetRedline( const String& rAuthor ) { std::map::iterator i = m_aRedlineTbl.find(rAuthor); if (i != m_aRedlineTbl.end()) return i->second; else { int nId = m_aRedlineTbl.size(); m_aRedlineTbl.insert(std::pair(rAuthor,nId)); return nId; } } const String* RtfExport::GetRedline( sal_uInt16 nId ) { for(std::map::iterator aIter = m_aRedlineTbl.begin(); aIter != m_aRedlineTbl.end(); ++aIter) if ((*aIter).second == nId) return &(*aIter).first; return NULL; } void RtfExport::OutPageDescription( const SwPageDesc& rPgDsc, bool bWriteReset, bool bCheckForFirstPage ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start"); const SwPageDesc *pSave = pAktPageDesc; pAktPageDesc = &rPgDsc; if( bCheckForFirstPage && pAktPageDesc->GetFollow() && pAktPageDesc->GetFollow() != pAktPageDesc ) pAktPageDesc = pAktPageDesc->GetFollow(); if( bWriteReset ) { if( pCurPam->GetPoint()->nNode == pOrigPam->Start()->nNode ) Strm() << OOO_STRING_SVTOOLS_RTF_SECTD << OOO_STRING_SVTOOLS_RTF_SBKNONE; else Strm() << OOO_STRING_SVTOOLS_RTF_SECT << OOO_STRING_SVTOOLS_RTF_SECTD; } if( pAktPageDesc->GetLandscape() ) Strm() << OOO_STRING_SVTOOLS_RTF_LNDSCPSXN; const SwFmt *pFmt = &pAktPageDesc->GetMaster(); //GetLeft(); bOutPageDescs = true; OutputFormat(*pFmt, true, false); bOutPageDescs = false; // normal header / footer (without a style) const SfxPoolItem* pItem; if( pAktPageDesc->GetLeft().GetAttrSet().GetItemState( RES_HEADER, sal_False, &pItem ) == SFX_ITEM_SET) WriteHeaderFooter(*pItem, true); if( pAktPageDesc->GetLeft().GetAttrSet().GetItemState( RES_FOOTER, sal_False, &pItem ) == SFX_ITEM_SET) WriteHeaderFooter(*pItem, false); // title page if( pAktPageDesc != &rPgDsc ) { Strm() << OOO_STRING_SVTOOLS_RTF_TITLEPG; pAktPageDesc = &rPgDsc; if( pAktPageDesc->GetMaster().GetAttrSet().GetItemState( RES_HEADER, sal_False, &pItem ) == SFX_ITEM_SET ) WriteHeaderFooter(*pItem, true); if( pAktPageDesc->GetMaster().GetAttrSet().GetItemState( RES_FOOTER, sal_False, &pItem ) == SFX_ITEM_SET ) WriteHeaderFooter(*pItem, false); } // numbering type AttrOutput().SectionPageNumbering(pAktPageDesc->GetNumType().GetNumberingType(), 0); pAktPageDesc = pSave; SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end"); } void RtfExport::WriteHeaderFooter(const SfxPoolItem& rItem, bool bHeader) { if (bHeader) { const SwFmtHeader& rHeader = (const SwFmtHeader&)rItem; if (!rHeader.IsActive()) return; } else { const SwFmtFooter& rFooter = (const SwFmtFooter&)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( pAktPageDesc->GetFollow() && pAktPageDesc->GetFollow() != pAktPageDesc ) { Strm() << OOO_STRING_SVTOOLS_RTF_TITLEPG; pStr = (bHeader ? OOO_STRING_SVTOOLS_RTF_HEADERF : OOO_STRING_SVTOOLS_RTF_FOOTERF); } Strm() << '{' << pStr; WriteHeaderFooterText(pAktPageDesc->GetMaster(), bHeader); Strm() << '}'; SAL_INFO("sw.rtf", OSL_THIS_FUNC << " end"); } void RtfExport::WriteHeaderFooter(const SwFrmFmt& rFmt, bool bHeader, const sal_Char* pStr, bool bTitlepg) { SAL_INFO("sw.rtf", OSL_THIS_FUNC << " start"); m_pAttrOutput->WriteHeaderFooter_Impl( rFmt, 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 String& rFilterName, const String& rBaseURL ); virtual ~SwRTFWriter(); virtual sal_uLong WriteStream(); }; SwRTFWriter::SwRTFWriter( const String& rFltName, const String & rBaseURL ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); SetBaseURL( rBaseURL ); // export outline nodes, only (send outline to clipboard/presentation) m_bOutOutlineOnly = 'O' == rFltName.GetChar( 0 ); } SwRTFWriter::~SwRTFWriter() {} sal_uLong SwRTFWriter::WriteStream() { SAL_INFO("sw.rtf", OSL_THIS_FUNC); SwPaM aPam(*pCurPam->End(), *pCurPam->Start()); RtfExport aExport( NULL, pDoc, &aPam, pCurPam, this, m_bOutOutlineOnly ); aExport.ExportDocument( true ); return 0; } extern "C" SAL_DLLPUBLIC_EXPORT void SAL_CALL ExportRTF( const String& rFltName, const String& rBaseURL, WriterRef& xRet ) { SAL_INFO("sw.rtf", OSL_THIS_FUNC); xRet = new SwRTFWriter( rFltName, rBaseURL ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */