From db6af6a208ed578625ef2df23f50ec982b562ca6 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Fri, 17 Sep 2010 12:22:16 +0200 Subject: cws-vmiklos01.diff: Better RTF export filter --- sw/source/filter/rtf/makefile.mk | 9 +- sw/source/filter/rtf/rtfnum.cxx | 3 +- sw/source/filter/rtf/swparrtf.cxx | 6 + sw/source/filter/rtf/swparrtf.hxx | 2 + sw/source/filter/ww8/README-rtf.txt | 226 ++ sw/source/filter/ww8/docxexport.cxx | 125 - sw/source/filter/ww8/docxexport.hxx | 22 - sw/source/filter/ww8/docxexportfilter.cxx | 53 +- sw/source/filter/ww8/makefile.mk | 14 +- sw/source/filter/ww8/rtfattributeoutput.cxx | 3356 +++++++++++++++++++++++++++ sw/source/filter/ww8/rtfattributeoutput.hxx | 573 +++++ sw/source/filter/ww8/rtfexport.cxx | 1240 ++++++++++ sw/source/filter/ww8/rtfexport.hxx | 211 ++ sw/source/filter/ww8/rtfexportfilter.cxx | 136 ++ sw/source/filter/ww8/rtfexportfilter.hxx | 84 + sw/source/filter/ww8/rtfimportfilter.cxx | 134 ++ sw/source/filter/ww8/rtfimportfilter.hxx | 74 + sw/source/filter/ww8/rtfsdrexport.cxx | 577 +++++ sw/source/filter/ww8/rtfsdrexport.hxx | 111 + sw/source/filter/ww8/wrtw8esh.cxx | 66 +- sw/source/filter/ww8/wrtw8nds.cxx | 147 +- sw/source/filter/ww8/wrtw8num.cxx | 3 + sw/source/filter/ww8/wrtw8sty.cxx | 36 + sw/source/filter/ww8/wrtww8.cxx | 2 +- sw/source/filter/ww8/wrtww8.hxx | 93 +- sw/source/filter/ww8/ww8atr.cxx | 2 +- sw/util/msword.map | 3 + 27 files changed, 7062 insertions(+), 246 deletions(-) create mode 100644 sw/source/filter/ww8/README-rtf.txt create mode 100644 sw/source/filter/ww8/rtfattributeoutput.cxx create mode 100644 sw/source/filter/ww8/rtfattributeoutput.hxx create mode 100644 sw/source/filter/ww8/rtfexport.cxx create mode 100644 sw/source/filter/ww8/rtfexport.hxx create mode 100644 sw/source/filter/ww8/rtfexportfilter.cxx create mode 100644 sw/source/filter/ww8/rtfexportfilter.hxx create mode 100644 sw/source/filter/ww8/rtfimportfilter.cxx create mode 100644 sw/source/filter/ww8/rtfimportfilter.hxx create mode 100644 sw/source/filter/ww8/rtfsdrexport.cxx create mode 100644 sw/source/filter/ww8/rtfsdrexport.hxx diff --git a/sw/source/filter/rtf/makefile.mk b/sw/source/filter/rtf/makefile.mk index 2ff764d730..e7310f2d0f 100644 --- a/sw/source/filter/rtf/makefile.mk +++ b/sw/source/filter/rtf/makefile.mk @@ -46,18 +46,15 @@ CDEFS=$(CDEFS) -Dmydebug EXCEPTIONSFILES= \ $(SLO)$/rtffly.obj \ $(SLO)$/rtfnum.obj \ - $(SLO)$/swparrtf.obj \ - $(SLO)$/wrtrtf.obj + $(SLO)$/swparrtf.obj -SLOFILES = \ - $(SLO)$/rtfatr.obj \ +SLOFILES = \ $(SLO)$/rtffld.obj \ $(SLO)$/rtffly.obj \ $(SLO)$/rtfnum.obj \ $(SLO)$/rtftbl.obj \ - $(SLO)$/swparrtf.obj \ - $(SLO)$/wrtrtf.obj + $(SLO)$/swparrtf.obj # --- Tagets ------------------------------------------------------- diff --git a/sw/source/filter/rtf/rtfnum.cxx b/sw/source/filter/rtf/rtfnum.cxx index c8aa3987c3..07b2076c95 100644 --- a/sw/source/filter/rtf/rtfnum.cxx +++ b/sw/source/filter/rtf/rtfnum.cxx @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -1102,6 +1101,7 @@ BOOL lcl_IsExportNumRule( const SwNumRule& rRule, BYTE* pEnd = 0 ) return nLvl != nEnd; } +#if 0 void SwRTFWriter::OutRTFListTab() { ByteString sOverrideList; @@ -1430,3 +1430,4 @@ BOOL SwRTFWriter::OutListNum( const SwTxtNode& rNd ) } return bRet; } +#endif diff --git a/sw/source/filter/rtf/swparrtf.cxx b/sw/source/filter/rtf/swparrtf.cxx index fccac64848..196ac0406a 100644 --- a/sw/source/filter/rtf/swparrtf.cxx +++ b/sw/source/filter/rtf/swparrtf.cxx @@ -179,6 +179,12 @@ ULONG RtfReader::Read( SwDoc &rDoc, const String& rBaseURL, SwPaM &rPam, const S return nRet; } +ULONG RtfReader::Read(SvStream* pStream, SwDoc& rDoc, const String& rBaseURL, SwPaM& rPam) +{ + pStrm = pStream; + return Read(rDoc, rBaseURL, rPam, rBaseURL); +} + SwRTFParser::SwRTFParser(SwDoc* pD, uno::Reference i_xDocProps, const SwPaM& rCrsr, SvStream& rIn, const String& rBaseURL, diff --git a/sw/source/filter/rtf/swparrtf.hxx b/sw/source/filter/rtf/swparrtf.hxx index a5a943fa46..8ff6878d3f 100644 --- a/sw/source/filter/rtf/swparrtf.hxx +++ b/sw/source/filter/rtf/swparrtf.hxx @@ -81,6 +81,8 @@ struct SvxRTFPictureType; class RtfReader: public Reader { virtual ULONG Read( SwDoc &, const String& rBaseURL, SwPaM &,const String &); +public: + virtual ULONG Read( SvStream* pStrm, SwDoc &, const String& rBaseURL, SwPaM &); }; class SwNodeIdx : public SvxNodeIdx diff --git a/sw/source/filter/ww8/README-rtf.txt b/sw/source/filter/ww8/README-rtf.txt new file mode 100644 index 0000000000..661813abc9 --- /dev/null +++ b/sw/source/filter/ww8/README-rtf.txt @@ -0,0 +1,226 @@ + +--------------------------------------------------------------------- + +Summary of new features in RtfExport + +--------------------------------------------------------------------- + +Miklos Vajna + + +--------------------------------------------------------------------- + +Table of Contents + +1. Introduction + + 1.1. Terminology + 1.2. General + +2. List if fixed bugs +3. List of new features + + 3.1. Nested tables + 3.2. Character properties + 3.3. Sections + 3.4. Graphics + 3.5. Bookmarks + 3.6. Fields + 3.7. Drawing + 3.8. Form fields + 3.9. OLE objects + +4. Changes in the source code outside RTF + + +--------------------------------------------------------------------- + +1. Introduction + +--------------------------------------------------------------------- + +The biggest difference is that the new exporter is an UNO component, +and it?s based on the MSWord base classes, the vision here is that +this way much less code can achieve the same set of features, +reducing the amount of duplicated code. + + +1.1. Terminology + +-------------- + + * The "MSO OK, OOo KO" and similar abbreviations describe if the + given new feature is supported by the OOo RTF importer or it can + be tested using Microsoft Office. + * RtfExport refers to the new UNO-based exporter, RtfWriter refers + to the old built-in one. + + +1.2. General + +-------------- + +RtfWriter sometimes created documents where the first { is closed in +the middle of the document. MSO ignores this problem, but OOo stops +parsing the rest of the document if this happens, in other words +everything after such a bug is ignored. This can be reproduced by for +example parprops.odt, but it?s triggered in several other cases as +well. RtfExport has no automatic prevention for this, either - but +during development I primarily test the output with OOo, so hopefully +the bug will pop up less frequently. + + +--------------------------------------------------------------------- + +2. List if fixed bugs + +--------------------------------------------------------------------- + + * http://www.openoffice.org/issues/show_bug.cgi?id=51469 postit + fields + * http://www.openoffice.org/issues/show_bug.cgi?id=66619 page + margins + * http://www.openoffice.org/issues/show_bug.cgi?id=69856 page + numbers + * http://www.openoffice.org/issues/show_bug.cgi?id=81569 { and } in + document title + * http://www.openoffice.org/issues/show_bug.cgi?id=84703 redlines + * http://www.openoffice.org/issues/show_bug.cgi?id=91166 russian + chars + * http://www.openoffice.org/issues/show_bug.cgi?id=92673 bookmarks + across tables + * http://www.openoffice.org/issues/show_bug.cgi?id=100507 ole + object export + * http://www.openoffice.org/issues/show_bug.cgi?id=103993 same as # + 81569 just for doc comments + * http://www.openoffice.org/issues/show_bug.cgi?id=106677 + listoverride index starts at zero + * http://www.openoffice.org/issues/show_bug.cgi?id=38344 enhanced + character space + + +--------------------------------------------------------------------- + +3. List of new features + +--------------------------------------------------------------------- + + +3.1. Nested tables + +-------------- + +This was new in Word2000 and it?s now supported by RtfExport (MSO OK, +OOo KO) + + +3.2. Character properties + +-------------- + +The followings are now supported: + + * blinking (MSO OK, OOo KO) + * expanded spacing (MSO OK, OOo OK) + * pair kerning (MSO OK, OOo OK) + + +3.3. Sections + +-------------- + +RtfExport writes: + + * column breaks (MSO OK, OOo OK) + * special breaks (when the next page should be an odd or an even + page; MSO OK, OOo KO) + * the write-protected property of sections is experted properly + (MSO OK, OOo KO) + * better page numbers (inherited type from page styles, restarts; + MSO OK, OOo KO) + * line numbering (MSO OK, OOo KO) + + +3.4. Graphics + +-------------- + +PNG graphics are exported in WMF format as well, so that not only MSO +and OOo can display graphics from the output document, but Wordpad as +well. + + +3.5. Bookmarks + +-------------- + +Implicit bookmarks like reference to a footnote did not work in OOo +(one got an Error: Reference source not found message when opening +the result), this now works as expected. (MSO OK - the importer +previously autocorrected this as well, OO OK) + + +3.6. Fields + +-------------- + + * Table of contents is now written as a field, so it?s properly + read-only (MSO OK, OOo KO) + * Postit comments are now exported. (MSO OK, OOo KO) + + +3.7. Drawing + +-------------- + +Drawing objects for Word 97 through Word 2007 (shapes) are now +implemented: + + * basic shapes (rectangle, ellipse, etc.) + * lines, including free-form ones + * texts, including vertical ones and their (paragraph and + character) formatting + +(MSO OK, OOo KO) + + +3.8. Form fields + +-------------- + +All types supported by the RTF format are exported, namely: + + * text boxes + * check boxes + * list boxes + +(MSO OK, OOo KO) + + +3.9. OLE objects + +-------------- + +Their result is exported as a picture - RtfWriter did not export +anything. (MSO OK, OOo OK) + +For math, the native data is written as well, so you can edit the +object, too. (MSO OK, OOo KO) + + +--------------------------------------------------------------------- + +4. Changes in the source code outside RTF + +--------------------------------------------------------------------- + +These are refactorings I needed for RTF. To my best knowledge they do +not change the output of other filters from a user?s point of view. + + * The code that splits runs according to bookmarks is moved from + DocxExport to MSWordExportBase + * WW8_SdrAttrIter has been refactored to MSWord_SdrAttrIter + * MSWordExportBase::SubstituteBullet can avoid replacing bullets + * wwFontHelper::InitFontTable can really load all fonts + * An obvious typo in WW8AttributeOutput::CharTwoLines has been + fixed diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index 07e2b54f63..1bb810c608 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -116,131 +116,6 @@ bool DocxExport::CollapseScriptsforWordOk( USHORT nScript, USHORT nWhich ) return true; } -bool DocxExport::GetBookmarks( const SwTxtNode& rNd, xub_StrLen nStt, - xub_StrLen nEnd, IMarkVector& rArr ) -{ - IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); - ULONG nNd = rNd.GetIndex( ); - - const sal_Int32 nMarks = pMarkAccess->getMarksCount(); - for ( sal_Int32 i = 0; i < nMarks; i++ ) - { - IMark* pMark = ( pMarkAccess->getMarksBegin() + i )->get(); - - // Only keep the bookmarks starting or ending in this node - if ( pMark->GetMarkStart().nNode == nNd || - pMark->GetMarkEnd().nNode == nNd ) - { - xub_StrLen nBStart = pMark->GetMarkStart().nContent.GetIndex(); - xub_StrLen nBEnd = pMark->GetMarkEnd().nContent.GetIndex(); - - // Keep only the bookmars starting or ending in the snippet - bool bIsStartOk = ( nBStart >= nStt ) && ( nBStart <= nEnd ); - bool bIsEndOk = ( nBEnd >= nStt ) && ( nBEnd <= nEnd ); - - if ( bIsStartOk || bIsEndOk ) - rArr.push_back( pMark ); - } - } - return ( rArr.size() > 0 ); -} - -class CompareMarksEnd : public std::binary_function < const IMark *, const IMark *, bool > -{ -public: - inline bool operator() ( const IMark * pOneB, const IMark * pTwoB ) const - { - xub_StrLen nOEnd = pOneB->GetMarkEnd().nContent.GetIndex(); - xub_StrLen nTEnd = pTwoB->GetMarkEnd().nContent.GetIndex(); - - return nOEnd < nTEnd; - } -}; - -bool DocxExport::NearestBookmark( xub_StrLen& rNearest ) -{ - bool bHasBookmark = false; - - if ( m_rSortedMarksStart.size( ) > 0 ) - { - IMark* pMarkStart = m_rSortedMarksStart.front(); - rNearest = pMarkStart->GetMarkStart().nContent.GetIndex(); - bHasBookmark = true; - } - - if ( m_rSortedMarksEnd.size( ) > 0 ) - { - IMark* pMarkEnd = m_rSortedMarksEnd[0]; - if ( !bHasBookmark ) - rNearest = pMarkEnd->GetMarkEnd().nContent.GetIndex(); - else - rNearest = std::min( rNearest, pMarkEnd->GetMarkEnd().nContent.GetIndex() ); - bHasBookmark = true; - } - - return bHasBookmark; -} - -xub_StrLen DocxExport::GetNextPos( SwAttrIter* pAttrIter, const SwTxtNode& rNode, xub_StrLen nAktPos ) -{ - // Get the bookmarks for the normal run - xub_StrLen nNextPos = MSWordExportBase::GetNextPos( pAttrIter, rNode, nAktPos ); - - GetSortedBookmarks( rNode, nAktPos, nNextPos - nAktPos ); - - xub_StrLen nNextBookmark = nNextPos; - NearestBookmark( nNextPos ); - - return std::min( nNextPos, nNextBookmark ); -} - -void DocxExport::UpdatePosition( SwAttrIter* pAttrIter, xub_StrLen nAktPos, xub_StrLen nEnd ) -{ - xub_StrLen nNextPos; - - // either no bookmark, or it is not at the current position - if ( !NearestBookmark( nNextPos ) || nNextPos > nAktPos ) - { - MSWordExportBase::UpdatePosition( pAttrIter, nAktPos, nEnd ); - } -} - -void DocxExport::GetSortedBookmarks( const SwTxtNode& rNode, xub_StrLen nAktPos, xub_StrLen nLen ) -{ - IMarkVector aMarksStart; - if ( GetBookmarks( rNode, nAktPos, nAktPos + nLen, aMarksStart ) ) - { - IMarkVector aSortedEnd; - IMarkVector aSortedStart; - for ( IMarkVector::const_iterator it = aMarksStart.begin(), end = aMarksStart.end(); - it < end; ++it ) - { - IMark* pMark = (*it); - - // Remove the positions egals to the current pos - xub_StrLen nStart = pMark->GetMarkStart().nContent.GetIndex(); - xub_StrLen nEnd = pMark->GetMarkEnd().nContent.GetIndex(); - - if ( nStart > nAktPos ) - aSortedStart.push_back( pMark ); - - if ( nEnd > nAktPos ) - aSortedEnd.push_back( pMark ); - } - - // Sort the bookmarks by end position - std::sort( aSortedEnd.begin(), aSortedEnd.end(), CompareMarksEnd() ); - - m_rSortedMarksStart.swap( aSortedStart ); - m_rSortedMarksEnd.swap( aSortedEnd ); - } - else - { - m_rSortedMarksStart.clear( ); - m_rSortedMarksEnd.clear( ); - } -} - void DocxExport::AppendBookmarks( const SwTxtNode& rNode, xub_StrLen nAktPos, xub_StrLen nLen ) { std::vector< OUString > aStarts; diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx index 5873f955d3..1bf9e22fbc 100644 --- a/sw/source/filter/ww8/docxexport.hxx +++ b/sw/source/filter/ww8/docxexport.hxx @@ -76,11 +76,6 @@ class DocxExport : public MSWordExportBase /// Footer counter. sal_Int32 m_nFooters; - /// Used to split the runs according to the bookmarks start and ends - typedef std::vector< ::sw::mark::IMark* > IMarkVector; - IMarkVector m_rSortedMarksStart; - IMarkVector m_rSortedMarksEnd; - /// Exporter of the VML shapes. oox::vml::VMLExport *m_pVMLExport; @@ -163,24 +158,7 @@ protected: const SwFmtPageDesc* pNewPgDescFmt = 0, const SwPageDesc* pNewPgDesc = 0 ); - /// Get the next position in the text node to output - virtual xub_StrLen GetNextPos( SwAttrIter* pAttrIter, const SwTxtNode& rNode, xub_StrLen nAktPos ); - - /// Update the information for GetNextPos(). - virtual void UpdatePosition( SwAttrIter* pAttrIter, xub_StrLen nAktPos, xub_StrLen nEnd ); - private: - /// Find the nearest bookmark from the current position. - /// - /// Returns false when there is no bookmark. - bool NearestBookmark( xub_StrLen& rNearest ); - - void GetSortedBookmarks( const SwTxtNode& rNd, xub_StrLen nAktPos, - xub_StrLen nLen ); - - bool GetBookmarks( const SwTxtNode& rNd, xub_StrLen nStt, xub_StrLen nEnd, - IMarkVector& rArr ); - /// Setup pStyles and write styles.xml void InitStyles(); diff --git a/sw/source/filter/ww8/docxexportfilter.cxx b/sw/source/filter/ww8/docxexportfilter.cxx index 7004f0853e..bdf6616a0b 100644 --- a/sw/source/filter/ww8/docxexportfilter.cxx +++ b/sw/source/filter/ww8/docxexportfilter.cxx @@ -1,7 +1,7 @@ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * + * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite @@ -26,6 +26,8 @@ ************************************************************************/ #include "docxexportfilter.hxx" +#include "rtfexportfilter.hxx" +#include "rtfimportfilter.hxx" #include "docxexport.hxx" #include @@ -136,7 +138,7 @@ SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL component_writeInfo( void* /* pServiceMan try { uno::Reference< registry::XRegistryKey > xNewKey1( - static_cast< registry::XRegistryKey* >( pRegistryKey )->createKey( + static_cast< registry::XRegistryKey* >( pRegistryKey )->createKey( OUString::createFromAscii( IMPL_NAME "/UNO/SERVICES/" ) ) ); xNewKey1->createKey( DocxExport_getSupportedServiceNames().getConstArray()[0] ); @@ -144,7 +146,35 @@ SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL component_writeInfo( void* /* pServiceMan } catch( registry::InvalidRegistryException& ) { - OSL_ENSURE( sal_False, "### InvalidRegistryException!" ); + OSL_ENSURE( sal_False, "### InvalidRegistryException (docx)!" ); + } + + try + { + uno::Reference< registry::XRegistryKey > xNewKey1( + static_cast< registry::XRegistryKey* >( pRegistryKey )->createKey( + OUString::createFromAscii( IMPL_NAME_RTFEXPORT "/UNO/SERVICES/" ) ) ); + xNewKey1->createKey( RtfExport_getSupportedServiceNames().getConstArray()[0] ); + + bRet = sal_True; + } + catch( registry::InvalidRegistryException& ) + { + OSL_ENSURE( sal_False, "### InvalidRegistryException (rtfexport)!" ); + } + + try + { + uno::Reference< registry::XRegistryKey > xNewKey1( + static_cast< registry::XRegistryKey* >( pRegistryKey )->createKey( + OUString::createFromAscii( IMPL_NAME_RTFIMPORT "/UNO/SERVICES/" ) ) ); + xNewKey1->createKey( RtfExport_getSupportedServiceNames().getConstArray()[0] ); + + bRet = sal_True; + } + catch( registry::InvalidRegistryException& ) + { + OSL_ENSURE( sal_False, "### InvalidRegistryException (rtfimport)!" ); } } @@ -157,6 +187,7 @@ SAL_DLLPUBLIC_EXPORT sal_Bool SAL_CALL component_writeInfo( void* /* pServiceMan SAL_DLLPUBLIC_EXPORT void* SAL_CALL component_getFactory( const sal_Char* pImplName, void* pServiceManager, void* /* pRegistryKey */ ) { + OSL_TRACE("%s, pImplName is '%s'", OSL_THIS_FUNC, pImplName); uno::Reference< lang::XSingleServiceFactory > xFactory; void* pRet = 0; @@ -169,6 +200,22 @@ SAL_DLLPUBLIC_EXPORT void* SAL_CALL component_getFactory( const sal_Char* pImplN DocxExport_getImplementationName(), DocxExport_createInstance, DocxExport_getSupportedServiceNames() ) ); + } else if ( rtl_str_compare( pImplName, IMPL_NAME_RTFEXPORT ) == 0 ) { + const OUString aServiceName( OUString::createFromAscii( IMPL_NAME_RTFEXPORT ) ); + + xFactory = uno::Reference< lang::XSingleServiceFactory >( ::cppu::createSingleFactory( + reinterpret_cast< lang::XMultiServiceFactory* >( pServiceManager ), + RtfExport_getImplementationName(), + RtfExport_createInstance, + RtfExport_getSupportedServiceNames() ) ); + } else if ( rtl_str_compare( pImplName, IMPL_NAME_RTFIMPORT ) == 0 ) { + const OUString aServiceName( OUString::createFromAscii( IMPL_NAME_RTFIMPORT ) ); + + xFactory = uno::Reference< lang::XSingleServiceFactory >( ::cppu::createSingleFactory( + reinterpret_cast< lang::XMultiServiceFactory* >( pServiceManager ), + RtfImport_getImplementationName(), + RtfImport_createInstance, + RtfImport_getSupportedServiceNames() ) ); } if ( xFactory.is() ) diff --git a/sw/source/filter/ww8/makefile.mk b/sw/source/filter/ww8/makefile.mk index 653c36fbef..f3638e28a9 100644 --- a/sw/source/filter/ww8/makefile.mk +++ b/sw/source/filter/ww8/makefile.mk @@ -68,7 +68,12 @@ EXCEPTIONSFILES = \ $(SLO)$/WW8TableInfo.obj \ $(SLO)$/WW8FFData.obj \ $(SLO)$/WW8Sttbf.obj \ - $(SLO)$/WW8FibData.obj + $(SLO)$/WW8FibData.obj \ + $(SLO)$/rtfexportfilter.obj \ + $(SLO)$/rtfimportfilter.obj \ + $(SLO)$/rtfattributeoutput.obj \ + $(SLO)$/rtfsdrexport.obj \ + $(SLO)$/rtfexport.obj SLOFILES = \ @@ -100,7 +105,12 @@ SLOFILES = \ $(SLO)$/WW8TableInfo.obj \ $(SLO)$/WW8FFData.obj \ $(SLO)$/WW8Sttbf.obj \ - $(SLO)$/WW8FibData.obj + $(SLO)$/WW8FibData.obj \ + $(SLO)$/rtfexportfilter.obj \ + $(SLO)$/rtfimportfilter.obj \ + $(SLO)$/rtfattributeoutput.obj \ + $(SLO)$/rtfsdrexport.obj \ + $(SLO)$/rtfexport.obj # --- Tagets ------------------------------------------------------- diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx new file mode 100644 index 0000000000..c5ac3b15f0 --- /dev/null +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -0,0 +1,3356 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Miklos Vajna. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "rtfattributeoutput.hxx" +#include "rtfexport.hxx" +#include "rtfsdrexport.hxx" +#include "writerwordglue.hxx" +#include "wrtww8.hxx" +#include "ww8par.hxx" +#include "fmtcntnt.hxx" +#include "fmtsrnd.hxx" +#include "fchrfmt.hxx" +#include "tgrditem.hxx" +#include "fmtruby.hxx" +#include "charfmt.hxx" +#include "breakit.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 +#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 +#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 +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +using rtl::OString; +using rtl::OStringBuffer; +using rtl::OUString; +using rtl::OUStringBuffer; +using rtl::OUStringToOString; + +using namespace nsSwDocInfoSubType; +using namespace nsFieldFlags; +using namespace sw::util; +using namespace ::com::sun::star; + +static OString OutTBLBorderLine(RtfExport &rExport, const SvxBorderLine* pLine, const sal_Char* pStr) +{ + OStringBuffer aRet; + aRet.append(pStr); + if( pLine->GetInWidth() ) + { + // double line + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRDB); + switch( pLine->GetInWidth() ) + { + case DEF_LINE_WIDTH_0: + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRW "15"); + break; + case DEF_LINE_WIDTH_1: + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRW "30"); + break; + case DEF_LINE_WIDTH_2: + case DEF_LINE_WIDTH_3: + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRW "45"); + break; + } + } + else + { + // single line + if( DEF_LINE_WIDTH_1 >= pLine->GetOutWidth() ) + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRS OOO_STRING_SVTOOLS_RTF_BRDRW).append((sal_Int32)pLine->GetOutWidth()); + else + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRTH OOO_STRING_SVTOOLS_RTF_BRDRW).append((sal_Int32)pLine->GetOutWidth() / 2); + } + + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRCF); + aRet.append((sal_Int32)rExport.GetColor(pLine->GetColor())); + return aRet.makeStringAndClear(); +} + +static OString OutBorderLine(RtfExport &rExport, const SvxBorderLine* pLine, + const sal_Char* pStr, USHORT nDist) +{ + OStringBuffer aRet; + aRet.append(OutTBLBorderLine(rExport, pLine, pStr)); + aRet.append(OOO_STRING_SVTOOLS_RTF_BRSP); + aRet.append((sal_Int32)nDist); + return aRet.makeStringAndClear(); +} + +static OString OutBorderLine( RtfExport &rExport, const SvxBorderLine* pLine, + const char* pStr ) +{ + OStringBuffer aRet; + aRet.append(pStr); + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDLNCOL); + aRet.append((sal_Int32)rExport.GetColor( pLine->GetColor() ) ); + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDLNIN); + aRet.append((sal_Int32)pLine->GetInWidth()); + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDLNOUT); + aRet.append((sal_Int32)pLine->GetOutWidth()); + aRet.append(OOO_STRING_SVTOOLS_RTF_BRDLNDIST); + aRet.append((sal_Int32)pLine->GetDistance()); + return aRet.makeStringAndClear(); +} + +void RtfAttributeOutput::RTLAndCJKState( bool bIsRTL, sal_uInt16 nScript ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + /* + You would have thought that + m_rExport.Strm() << (bIsRTL ? OOO_STRING_SVTOOLS_RTF_RTLCH : OOO_STRING_SVTOOLS_RTF_LTRCH); would be sufficent here , + but looks like word needs to see the other directional token to be + satisified that all is kosher, otherwise it seems in ver 2003 to go and + semi-randomlyly stick strike through about the place. Perhaps + strikethrough is some ms developers "something is wrong signal" debugging + code that we're triggering ? + */ + if (bIsRTL) { + m_aStylesEnd.append(OOO_STRING_SVTOOLS_RTF_LTRCH); + m_aStylesEnd.append(' '); + m_aStylesEnd.append(OOO_STRING_SVTOOLS_RTF_RTLCH); + } else { + m_aStylesEnd.append(OOO_STRING_SVTOOLS_RTF_RTLCH); + m_aStylesEnd.append(' '); + m_aStylesEnd.append(OOO_STRING_SVTOOLS_RTF_LTRCH); + } + + switch (nScript) { + case i18n::ScriptType::LATIN: + m_aStylesEnd.append(OOO_STRING_SVTOOLS_RTF_LOCH); + break; + case i18n::ScriptType::ASIAN: + m_aStylesEnd.append(OOO_STRING_SVTOOLS_RTF_DBCH); + break; + case i18n::ScriptType::COMPLEX: + /* noop */ + break; + default: + /* should not happen? */ + break; + } +} + +void RtfAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + // Output table/table row/table cell starts if needed + if ( pTextNodeInfo.get() ) + { + sal_uInt32 nRow = pTextNodeInfo->getRow(); + sal_uInt32 nCell = pTextNodeInfo->getCell(); + + // New cell/row? + if ( m_nTableDepth > 0 && !m_bTableCellOpen ) + { + ww8::WW8TableNodeInfoInner::Pointer_t pDeepInner( pTextNodeInfo->getInnerForDepth( m_nTableDepth ) ); + if ( pDeepInner->getCell() == 0 ) + StartTableRow( pDeepInner ); + + StartTableCell( pDeepInner ); + } + + if ( nRow == 0 && nCell == 0 ) + { + // Do we have to start the table? + // [If we are at the rigth depth already, it means that we + // continue the table cell] + sal_uInt32 nCurrentDepth = pTextNodeInfo->getDepth(); + + if ( nCurrentDepth > m_nTableDepth ) + { + // Start all the tables that begin here + for ( sal_uInt32 nDepth = m_nTableDepth + 1; nDepth <= pTextNodeInfo->getDepth(); ++nDepth ) + { + ww8::WW8TableNodeInfoInner::Pointer_t pInner( pTextNodeInfo->getInnerForDepth( nDepth ) ); + + StartTable( pInner ); + StartTableRow( pInner ); + StartTableCell( pInner ); + } + + m_nTableDepth = nCurrentDepth; + } + } + } + + OSL_ENSURE(m_aRun.getLength() == 0, "m_aRun is not empty"); +} + +void RtfAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + FinishTableRowCell( pTextNodeInfoInner ); + + OStringBuffer aParagraph; + + aParagraph.append(m_aRun.makeStringAndClear()); + aParagraph.append(m_aAfterRuns.makeStringAndClear()); + if (m_bTblAfterCell) + m_bTblAfterCell = false; + else + { + aParagraph.append(m_rExport.sNewLine); + aParagraph.append(OOO_STRING_SVTOOLS_RTF_PAR); + aParagraph.append(' '); + } + if (m_nColBreakNeeded) + { + aParagraph.append(OOO_STRING_SVTOOLS_RTF_COLUMN); + m_nColBreakNeeded = false; + } + + if (!m_bBufferSectionHeaders) + m_rExport.Strm() << aParagraph.makeStringAndClear(); + else + m_aSectionHeaders.append(aParagraph.makeStringAndClear()); +} + +void RtfAttributeOutput::EmptyParagraph() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << m_rExport.sNewLine << OOO_STRING_SVTOOLS_RTF_PAR << ' '; +} + +void RtfAttributeOutput::StartParagraphProperties( const SwTxtNode& rNode ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + OSL_ENSURE(m_aStyles.getLength() == 0, "m_aStyles is not empty"); + + // output page/section breaks + SwNodeIndex aNextIndex( rNode, 1 ); + m_rExport.Strm() << m_aSectionBreaks.makeStringAndClear(); + m_bBufferSectionBreaks = true; + + // output section headers / footers + if (!m_bBufferSectionHeaders) + m_rExport.Strm() << m_aSectionHeaders.makeStringAndClear(); + + if ( aNextIndex.GetNode().IsTxtNode() ) + { + const SwTxtNode* pTxtNode = static_cast< SwTxtNode* >( &aNextIndex.GetNode() ); + m_rExport.OutputSectionBreaks( pTxtNode->GetpSwAttrSet(), *pTxtNode ); + } + else if ( aNextIndex.GetNode().IsTableNode() ) + { + const SwTableNode* pTableNode = static_cast< SwTableNode* >( &aNextIndex.GetNode() ); + const SwFrmFmt *pFmt = pTableNode->GetTable().GetFrmFmt(); + m_rExport.OutputSectionBreaks( &(pFmt->GetAttrSet()), *pTableNode ); + } + m_bBufferSectionBreaks = false; + + OStringBuffer aPar; + if (!m_rExport.bRTFFlySyntax) + { + aPar.append(OOO_STRING_SVTOOLS_RTF_PARD); + aPar.append(OOO_STRING_SVTOOLS_RTF_PLAIN); + aPar.append(' '); + } + if (!m_bBufferSectionHeaders) + m_rExport.Strm() << aPar.makeStringAndClear(); + else + m_aSectionHeaders.append(aPar.makeStringAndClear()); +} + +void RtfAttributeOutput::EndParagraphProperties() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + m_aStyles.append(m_aStylesEnd.makeStringAndClear()); + m_rExport.Strm() << m_aStyles.makeStringAndClear(); +} + +void RtfAttributeOutput::StartRun( const SwRedlineData* pRedlineData ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aRun.append('{'); + + // if there is some redlining in the document, output it + Redline( pRedlineData ); + + OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty"); +} + +void RtfAttributeOutput::EndRun() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + m_aRun.append(m_rExport.sNewLine); + m_aRun.append(m_aRunText.makeStringAndClear()); + m_aRun.append('}'); +} + +void RtfAttributeOutput::StartRunProperties() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + OSL_ENSURE(m_aStyles.getLength() == 0, "m_aStyles is not empty"); +} + +void RtfAttributeOutput::EndRunProperties( const SwRedlineData* /*pRedlineData*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + m_aStyles.append(m_aStylesEnd.makeStringAndClear()); + m_aRun.append(m_aStyles.makeStringAndClear()); +} + +void RtfAttributeOutput::RunText( const String& rText, rtl_TextEncoding eCharSet ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + RawText( rText, 0, eCharSet ); +} + +OStringBuffer& RtfAttributeOutput::RunText() +{ + return m_aRunText; +} + +OStringBuffer& RtfAttributeOutput::Styles() +{ + return m_aStyles; +} + +void RtfAttributeOutput::RawText( const String& rText, bool /*bForceUnicode*/, rtl_TextEncoding eCharSet ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + m_aRunText.append(m_rExport.OutString(rText, eCharSet)); +} + +void RtfAttributeOutput::StartRuby( const SwTxtNode& /*rNode*/, const SwFmtRuby& /*rRuby*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::EndRuby() +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +bool RtfAttributeOutput::StartURL( const String& rUrl, const String& rTarget ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append('{'); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FIELD); + m_aStyles.append('{'); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_IGNORE); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FLDINST); + m_aStyles.append(" HYPERLINK "); + + String sURL( rUrl ); + if( sURL.Len() ) + { + m_aStyles.append("\""); + m_aStyles.append(m_rExport.OutString( sURL, m_rExport.eCurrentEncoding)); + m_aStyles.append("\" "); + } + + if( rTarget.Len() ) + { + m_aStyles.append("\\\\t \""); + m_aStyles.append(m_rExport.OutString( rTarget, m_rExport.eCurrentEncoding)); + m_aStyles.append("\" "); + } + + m_aStyles.append("}"); + return true; +} + +bool RtfAttributeOutput::EndURL() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + // close the fldrslt group + m_aRunText.append('}'); + // close the field group + m_aRunText.append('}'); + return true; +} + +void RtfAttributeOutput::FieldVanish( const String& /*rTxt*/, ww::eField /*eType*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::Redline( const SwRedlineData* pRedline ) +{ + if (!pRedline) + return; + + OSL_TRACE("%s", OSL_THIS_FUNC); + + if (pRedline->GetType() == nsRedlineType_t::REDLINE_INSERT) + { + m_aRun.append(OOO_STRING_SVTOOLS_RTF_REVISED); + m_aRun.append(OOO_STRING_SVTOOLS_RTF_REVAUTH); + m_aRun.append((sal_Int32)m_rExport.GetRedline(SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor()))); + m_aRun.append(OOO_STRING_SVTOOLS_RTF_REVDTTM); + } + else if(pRedline->GetType() == nsRedlineType_t::REDLINE_DELETE) + { + m_aRun.append(OOO_STRING_SVTOOLS_RTF_DELETED); + m_aRun.append(OOO_STRING_SVTOOLS_RTF_REVAUTHDEL); + m_aRun.append((sal_Int32)m_rExport.GetRedline(SW_MOD()->GetRedlineAuthor(pRedline->GetAuthor()))); + m_aRun.append(OOO_STRING_SVTOOLS_RTF_REVDTTMDEL); + } + m_aRun.append((sal_Int32)sw::ms::DateTime2DTTM(pRedline->GetTimeStamp())); + m_aRun.append(' '); +} + +void RtfAttributeOutput::FormatDrop( const SwTxtNode& /*rNode*/, const SwFmtDrop& /*rSwFmtDrop*/, USHORT /*nStyle*/, ww8::WW8TableNodeInfo::Pointer_t /*pTextNodeInfo*/, ww8::WW8TableNodeInfoInner::Pointer_t /*pTextNodeInfoInner*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::ParagraphStyle( USHORT nStyle ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + OString *pStyle = m_rExport.GetStyle(nStyle); + OStringBuffer aStyle; + aStyle.append(OOO_STRING_SVTOOLS_RTF_S); + aStyle.append((sal_Int32)nStyle); + if (pStyle) + aStyle.append(pStyle->getStr()); + if (!m_bBufferSectionHeaders) + m_rExport.Strm() << aStyle.makeStringAndClear(); + else + m_aSectionHeaders.append(aStyle.makeStringAndClear()); +} + +void RtfAttributeOutput::TableInfoCell( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_INTBL); + if ( m_nTableDepth > 1 ) + { + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ITAP); + m_aStyles.append((sal_Int32)m_nTableDepth); + } +} + +void RtfAttributeOutput::TableInfoRow( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfo*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* noop */ +} + +void RtfAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( !m_pTableWrt ) + InitTableHelper( pTableTextNodeInfoInner ); + + const SwTableBox *pTblBox = pTableTextNodeInfoInner->getTableBox( ); + SwFrmFmt *pFmt = pTblBox->GetFrmFmt( ); + + m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TROWD); + TableOrientation( pTableTextNodeInfoInner ); + TableBidi( pTableTextNodeInfoInner ); + TableHeight( pTableTextNodeInfoInner ); + TableCanSplit( pTableTextNodeInfoInner ); + + // Cell margins + const SvxBoxItem& rBox = pFmt->GetBox( ); + static const USHORT aBorders[] = + { + BOX_LINE_TOP, BOX_LINE_LEFT, BOX_LINE_BOTTOM, BOX_LINE_RIGHT + }; + + static const char* aRowPadNames[] = + { + OOO_STRING_SVTOOLS_RTF_TRPADDT, OOO_STRING_SVTOOLS_RTF_TRPADDL, OOO_STRING_SVTOOLS_RTF_TRPADDB, OOO_STRING_SVTOOLS_RTF_TRPADDR + }; + + static const char* aRowPadUnits[] = + { + OOO_STRING_SVTOOLS_RTF_TRPADDFT, OOO_STRING_SVTOOLS_RTF_TRPADDFL, OOO_STRING_SVTOOLS_RTF_TRPADDFB, OOO_STRING_SVTOOLS_RTF_TRPADDFR + }; + + for (int i = 0; i < 4; ++i) + { + m_aRowDefs.append(aRowPadUnits[i]); + m_aRowDefs.append((sal_Int32)3); + m_aRowDefs.append(aRowPadNames[i]); + m_aRowDefs.append((sal_Int32)rBox.GetDistance(aBorders[i])); + } + + // The cell-dependent properties + const SwWriteTableRows& aRows = m_pTableWrt->GetRows( ); + SwWriteTableRow *pRow = aRows[ pTableTextNodeInfoInner->getRow( ) ]; + SwTwips nSz = 0; + Point aPt; + SwRect aRect( pFmt->FindLayoutRect( false, &aPt )); + SwTwips nPageSize = aRect.Width(); + SwTwips nTblSz = pFmt->GetFrmSize().GetWidth(); + for( USHORT i = 0; i < pRow->GetCells().Count(); i++ ) + { + SwWriteTableCell *pCell = pRow->GetCells( )[ i ]; + const SwFrmFmt *pCellFmt = pCell->GetBox()->GetFrmFmt(); + + pTableTextNodeInfoInner->setCell( i ); + TableCellProperties(pTableTextNodeInfoInner); + + // Right boundary: this can't be in TableCellProperties as the old + // value of nSz is needed. + nSz += pCellFmt->GetFrmSize().GetWidth(); + m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CELLX); + SwTwips nCalc = nSz; + nCalc *= nPageSize; + nCalc /= nTblSz; + m_aRowDefs.append( (sal_Int32)(pFmt->GetLRSpace().GetLeft() + nCalc) ); + } +} + +void RtfAttributeOutput::TableDefaultBorders( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* + * The function name is a bit misleading: given that we write borders + * before each row, we just have borders, not default ones. Additionally, + * this function actually writes borders for a specific cell only and is + * called for each cell. + */ + + const SwTableBox *pTblBox = pTableTextNodeInfoInner->getTableBox( ); + SwFrmFmt *pFmt = pTblBox->GetFrmFmt( ); + const SvxBoxItem& rDefault = pFmt->GetBox( ); + const SwWriteTableRows& aRows = m_pTableWrt->GetRows( ); + SwWriteTableRow *pRow = aRows[ pTableTextNodeInfoInner->getRow( ) ]; + SwWriteTableCell *pCell = pRow->GetCells( )[ pTableTextNodeInfoInner->getCell( ) ]; + const SwFrmFmt *pCellFmt = pCell->GetBox()->GetFrmFmt(); + const SfxPoolItem* pItem; + if (SFX_ITEM_SET == pCellFmt->GetAttrSet().GetItemState(RES_BOX, TRUE, &pItem)) + { + const SvxBoxItem& rBox = (SvxBoxItem&)*pItem; + static const USHORT aBorders[] = + { + BOX_LINE_TOP, BOX_LINE_LEFT, BOX_LINE_BOTTOM, BOX_LINE_RIGHT + }; + static const char* aBorderNames[] = + { + OOO_STRING_SVTOOLS_RTF_CLBRDRT, OOO_STRING_SVTOOLS_RTF_CLBRDRL, OOO_STRING_SVTOOLS_RTF_CLBRDRB, OOO_STRING_SVTOOLS_RTF_CLBRDRR + }; + //Yes left and top are swapped with eachother for cell padding! Because + //that's what the thunderingly annoying rtf export/import word xp does. + static const char* aCellPadNames[] = + { + OOO_STRING_SVTOOLS_RTF_CLPADL, OOO_STRING_SVTOOLS_RTF_CLPADT, OOO_STRING_SVTOOLS_RTF_CLPADB, OOO_STRING_SVTOOLS_RTF_CLPADR + }; + static const char* aCellPadUnits[] = + { + OOO_STRING_SVTOOLS_RTF_CLPADFL, OOO_STRING_SVTOOLS_RTF_CLPADFT, OOO_STRING_SVTOOLS_RTF_CLPADFB, OOO_STRING_SVTOOLS_RTF_CLPADFR + }; + for (int i = 0; i < 4; ++i) + { + if (const SvxBorderLine* pLn = rBox.GetLine(aBorders[i])) + m_aRowDefs.append(OutTBLBorderLine(m_rExport, pLn, aBorderNames[i])); + if (rDefault.GetDistance(aBorders[i]) != + rBox.GetDistance(aBorders[i])) + { + m_aRowDefs.append(aCellPadUnits[i]); + m_aRowDefs.append((sal_Int32)3); + m_aRowDefs.append(aCellPadNames[i]); + m_aRowDefs.append((sal_Int32)rBox.GetDistance(aBorders[i])); + } + } + } +} + +void RtfAttributeOutput::TableBackgrounds( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const SwWriteTableRows& aRows = m_pTableWrt->GetRows( ); + SwWriteTableRow *pRow = aRows[ pTableTextNodeInfoInner->getRow( ) ]; + SwWriteTableCell *pCell = pRow->GetCells( )[ pTableTextNodeInfoInner->getCell( ) ]; + const SwFrmFmt *pCellFmt = pCell->GetBox()->GetFrmFmt(); + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pCellFmt->GetAttrSet().GetItemState( + RES_BACKGROUND, TRUE, &pItem )) + { + const SvxBrushItem& rBack = (SvxBrushItem&)*pItem; + if( !rBack.GetColor().GetTransparency() ) + { + m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLCBPAT); + m_aRowDefs.append((sal_Int32)m_rExport.GetColor(rBack.GetColor())); + } + } +} + +void RtfAttributeOutput::TableHeight( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox(); + const SwTableLine * pTabLine = pTabBox->GetUpper(); + const SwFrmFmt * pLineFmt = pTabLine->GetFrmFmt(); + const SwFmtFrmSize& rLSz = pLineFmt->GetFrmSize(); + + if ( ATT_VAR_SIZE != rLSz.GetHeightSizeType() && rLSz.GetHeight() ) + { + sal_Int32 nHeight = 0; + + switch ( rLSz.GetHeightSizeType() ) + { + case ATT_FIX_SIZE: nHeight = -rLSz.GetHeight(); break; + case ATT_MIN_SIZE: nHeight = rLSz.GetHeight(); break; + default: break; + } + + if ( nHeight ) + { + m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TRRH); + m_aRowDefs.append(nHeight); + } + } +} + +void RtfAttributeOutput::TableCanSplit( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const SwTableBox * pTabBox = pTableTextNodeInfoInner->getTableBox(); + const SwTableLine * pTabLine = pTabBox->GetUpper(); + const SwFrmFmt * pLineFmt = pTabLine->GetFrmFmt(); + const SwFmtRowSplit& rSplittable = pLineFmt->GetRowSplit( ); + + // The rtf default is to allow a row to break + if (rSplittable.GetValue() == 0) + m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_TRKEEP); +} + +void RtfAttributeOutput::TableBidi( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const SwTable * pTable = pTableTextNodeInfoInner->getTable(); + const SwFrmFmt * pFrmFmt = pTable->GetFrmFmt(); + + if ( m_rExport.TrueFrameDirection( *pFrmFmt ) != FRMDIR_HORI_RIGHT_TOP ) + m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_LTRROW); + else + m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_RTLROW); +} + +void RtfAttributeOutput::TableVerticalCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const SwWriteTableRows& aRows = m_pTableWrt->GetRows( ); + SwWriteTableRow *pRow = aRows[ pTableTextNodeInfoInner->getRow( ) ]; + SwWriteTableCell *pCell = pRow->GetCells( )[ pTableTextNodeInfoInner->getCell( ) ]; + const SwFrmFmt *pCellFmt = pCell->GetBox()->GetFrmFmt(); + const SfxPoolItem* pItem; + + // vertical merges + if (pCell->GetRowSpan() > 1) + m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVMGF); + else if (pCell->GetRowSpan() == 0) + m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVMRG); + + // vertical alignment + if( SFX_ITEM_SET == pCellFmt->GetAttrSet().GetItemState( + RES_VERT_ORIENT, TRUE, &pItem ) ) + switch( ((SwFmtVertOrient*)pItem)->GetVertOrient() ) + { + case text::VertOrientation::CENTER: m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALC); break; + case text::VertOrientation::BOTTOM: m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALB); break; + default: m_aRowDefs.append(OOO_STRING_SVTOOLS_RTF_CLVERTALT); break; + } +} + +void RtfAttributeOutput::TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t /*pNodeInfo*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* noop */ +} + +void RtfAttributeOutput::TableNodeInfoInner( ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + // This is called when the nested table ends in a cell, and there's no + // paragraph benhind that; so we must check for the ends of cell, rows, + // and tables + // ['true' to write an empty paragraph, MS Word insists on that] + FinishTableRowCell( pNodeInfoInner, true ); +} + +void RtfAttributeOutput::TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const SwTable *pTable = pTableTextNodeInfoInner->getTable(); + SwFrmFmt *pFmt = pTable->GetFrmFmt( ); + + OStringBuffer aTblAdjust( OOO_STRING_SVTOOLS_RTF_TRQL ); + switch (pFmt->GetHoriOrient().GetHoriOrient()) + { + case text::HoriOrientation::CENTER: + aTblAdjust.setLength(0); + aTblAdjust.append(OOO_STRING_SVTOOLS_RTF_TRQC); + break; + case text::HoriOrientation::RIGHT: + aTblAdjust.setLength(0); + aTblAdjust.append(OOO_STRING_SVTOOLS_RTF_TRQR); + break; + case text::HoriOrientation::NONE: + case text::HoriOrientation::LEFT_AND_WIDTH: + aTblAdjust.append(OOO_STRING_SVTOOLS_RTF_TRLEFT); + aTblAdjust.append((sal_Int32)pFmt->GetLRSpace().GetLeft()); + break; + default: + break; + } + + m_aRowDefs.append(aTblAdjust.makeStringAndClear()); +} + +void RtfAttributeOutput::TableSpacing( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::TableRowEnd( sal_uInt32 /*nDepth*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* noop, see EndTableRow() */ +} + +/* + * Our private table methods. + */ + +void RtfAttributeOutput::InitTableHelper( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + sal_uInt32 nPageSize = 0; + bool bRelBoxSize = false; + + // Create the SwWriteTable instance to use col spans + GetTablePageSize( pTableTextNodeInfoInner.get(), nPageSize, bRelBoxSize ); + + const SwTable* pTable = pTableTextNodeInfoInner->getTable( ); + const SwFrmFmt *pFmt = pTable->GetFrmFmt( ); + SwTwips nTblSz = pFmt->GetFrmSize( ).GetWidth( ); + + const SwHTMLTableLayout *pLayout = pTable->GetHTMLTableLayout(); + if( pLayout && pLayout->IsExportable() ) + m_pTableWrt = new SwWriteTable( pLayout ); + else + m_pTableWrt = new SwWriteTable( pTable->GetTabLines(), (USHORT)nPageSize, + (USHORT)nTblSz, false); +} + +void RtfAttributeOutput::StartTable( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* noop */ +} + +void RtfAttributeOutput::StartTableRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + sal_uInt32 nCurrentDepth = pTableTextNodeInfoInner->getDepth(); + OSL_TRACE("%s, (depth is %d)", OSL_THIS_FUNC, (int)nCurrentDepth); + + TableDefinition(pTableTextNodeInfoInner); + + // We'll write the table definition for nested tables later + if ( nCurrentDepth > 1 ) + return; + m_rExport.Strm() << m_aRowDefs.makeStringAndClear(); +} + +void RtfAttributeOutput::StartTableCell( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_bTableCellOpen = true; +} + +void RtfAttributeOutput::TableCellProperties( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + TableDefaultBorders(pTableTextNodeInfoInner); + TableBackgrounds(pTableTextNodeInfoInner); + TableVerticalCell(pTableTextNodeInfoInner); +} + +void RtfAttributeOutput::EndTableCell( ) +{ + OSL_TRACE("%s, (depth is %d)", OSL_THIS_FUNC, (int)m_nTableDepth); + + if ( m_nTableDepth > 1 ) + m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_NESTCELL); + else + m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_CELL); + + m_bTableCellOpen = false; + m_bTblAfterCell = true; +} + +void RtfAttributeOutput::EndTableRow( ) +{ + OSL_TRACE("%s, (depth is %d)", OSL_THIS_FUNC, (int)m_nTableDepth); + + if ( m_nTableDepth > 1 ) + { + m_aAfterRuns.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_NESTTABLEPROPRS); + m_aAfterRuns.append(m_aRowDefs.makeStringAndClear()); + m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_NESTROW "}" "{" OOO_STRING_SVTOOLS_RTF_NONESTTABLES OOO_STRING_SVTOOLS_RTF_PAR "}"); + } + else + m_aAfterRuns.append(OOO_STRING_SVTOOLS_RTF_ROW); +} + +void RtfAttributeOutput::EndTable() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( m_nTableDepth > 0 ) + m_nTableDepth--; + + // We closed the table; if it is a nested table, the cell that contains it + // still continues + m_bTableCellOpen = true; + + // Cleans the table helper + delete m_pTableWrt, m_pTableWrt = NULL; +} + +void RtfAttributeOutput::FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointer_t pInner, bool /*bForceEmptyParagraph*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( pInner.get() ) + { + // Where are we in the table + sal_uInt32 nRow = pInner->getRow( ); + + const SwTable *pTable = pInner->getTable( ); + const SwTableLines& rLines = pTable->GetTabLines( ); + USHORT nLinesCount = rLines.Count( ); + + if ( pInner->isEndOfCell() ) + EndTableCell(); + + // This is a line end + if ( pInner->isEndOfLine() ) + EndTableRow(); + + // This is the end of the table + if ( pInner->isEndOfLine( ) && ( nRow + 1 ) == nLinesCount ) + EndTable(); + } +} + +void RtfAttributeOutput::StartStyles() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + m_rExport.Strm() << m_rExport.sNewLine << '{' << OOO_STRING_SVTOOLS_RTF_COLORTBL; + m_rExport.OutColorTable(); + OSL_ENSURE(m_aStylesheet.getLength() == 0, "m_aStylesheet is not empty"); + m_aStylesheet.append(m_rExport.sNewLine); + m_aStylesheet.append('{'); + m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_STYLESHEET); +} + +void RtfAttributeOutput::EndStyles( USHORT /*nNumberOfStyles*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + m_rExport.Strm() << '}'; + m_rExport.Strm() << m_aStylesheet.makeStringAndClear(); + m_rExport.Strm() << '}'; +} + +void RtfAttributeOutput::DefaultStyle( USHORT /*nStyle*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* noop, the default style is always 0 in RTF */ +} + +void RtfAttributeOutput::StartStyle( const String& rName, bool bPapFmt, + USHORT nBase, USHORT nNext, USHORT /*nWwId*/, USHORT nId ) +{ + OSL_TRACE("%s, rName = '%s'", OSL_THIS_FUNC, + OUStringToOString( OUString( rName ), m_rExport.eCurrentEncoding ).getStr()); + + m_aStylesheet.append('{'); + if (bPapFmt) + m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_S); + else + m_aStylesheet.append( OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_CS); + m_aStylesheet.append( (sal_Int32)nId ); + + if ( nBase != 0x0FFF ) + { + m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_SBASEDON); + m_aStylesheet.append((sal_Int32)nBase); + } + + m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_SNEXT); + m_aStylesheet.append((sal_Int32)nNext); + + m_rStyleName = rName; + m_nStyleId = nId; +} + +void RtfAttributeOutput::EndStyle() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + m_aStyles.append(m_aStylesEnd.makeStringAndClear()); + OString aStyles = m_aStyles.makeStringAndClear(); + m_rExport.InsStyle(m_nStyleId, aStyles); + m_aStylesheet.append(aStyles); + m_aStylesheet.append(' '); + m_aStylesheet.append(OUStringToOString( OUString( m_rStyleName ), m_rExport.eCurrentEncoding )); + m_aStylesheet.append(";}"); + m_aStylesheet.append(m_rExport.sNewLine); +} + +void RtfAttributeOutput::StartStyleProperties( bool /*bParProp*/, USHORT /*nStyle*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + /* noop */ +} + +void RtfAttributeOutput::EndStyleProperties( bool /*bParProp*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + /* noop */ +} + +void RtfAttributeOutput::OutlineNumbering( BYTE nLvl, const SwNumFmt& /*rNFmt*/, const SwFmt& /*rFmt*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( nLvl >= WW8ListManager::nMaxLevel ) + nLvl = WW8ListManager::nMaxLevel - 1; + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ILVL); + m_aStyles.append((sal_Int32)nLvl); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_OUTLINELEVEL); + m_aStyles.append((sal_Int32)nLvl); +} + +void RtfAttributeOutput::PageBreakBefore( bool bBreak ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if (bBreak) + { + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_PAGEBB; + } +} + +void RtfAttributeOutput::SectionBreak( BYTE nC, const WW8_SepInfo* pSectionInfo ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + switch (nC) + { + case msword::ColumnBreak: + m_nColBreakNeeded = true; + break; + case msword::PageBreak: + if ( pSectionInfo ) + m_rExport.SectionProperties( *pSectionInfo ); + break; + } +} + +void RtfAttributeOutput::StartSection() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_SECT OOO_STRING_SVTOOLS_RTF_SECTD); + if (!m_bBufferSectionBreaks) + m_rExport.Strm() << m_aSectionBreaks.makeStringAndClear(); +} + +void RtfAttributeOutput::EndSection() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* + * noop, \sect must go to StartSection or Word won't notice multiple + * columns... + */ +} + +void RtfAttributeOutput::SectionFormProtection( bool bProtected ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_SECTUNLOCKED); + m_aSectionBreaks.append((sal_Int32)!bProtected); +} + +void RtfAttributeOutput::SectionLineNumbering( ULONG /*nRestartNo*/, const SwLineNumberInfo& rLnNumInfo ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LINEMOD; + m_rExport.OutLong(rLnNumInfo.GetCountBy()); + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LINEX; + m_rExport.OutLong(rLnNumInfo.GetPosFromLeft()); + if (!rLnNumInfo.IsRestartEachPage()) + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LINECONT; +} + +void RtfAttributeOutput::SectionTitlePage() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* + * noop, handled in RtfExport::WriteHeaderFooter() + */ +} + +void RtfAttributeOutput::SectionPageBorders( const SwFrmFmt* pFmt, const SwFrmFmt* /*pFirstPageFmt*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const SvxBoxItem& rBox = pFmt->GetBox(); + const SvxBorderLine *pLine = rBox.GetTop(); + if(pLine) + m_aSectionBreaks.append(OutBorderLine( m_rExport, pLine, + OOO_STRING_SVTOOLS_RTF_PGBRDRT, + rBox.GetDistance(BOX_LINE_TOP) )); + pLine = rBox.GetBottom(); + if(pLine) + m_aSectionBreaks.append(OutBorderLine( m_rExport, pLine, + OOO_STRING_SVTOOLS_RTF_PGBRDRB, + rBox.GetDistance(BOX_LINE_BOTTOM) )); + pLine = rBox.GetLeft(); + if(pLine) + m_aSectionBreaks.append(OutBorderLine( m_rExport, pLine, + OOO_STRING_SVTOOLS_RTF_PGBRDRL, + rBox.GetDistance(BOX_LINE_LEFT) )); + pLine = rBox.GetRight(); + if(pLine) + m_aSectionBreaks.append(OutBorderLine( m_rExport, pLine, + OOO_STRING_SVTOOLS_RTF_PGBRDRR, + rBox.GetDistance(BOX_LINE_RIGHT) )); +} + +void RtfAttributeOutput::SectionBiDi( bool bBiDi ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << (bBiDi ? OOO_STRING_SVTOOLS_RTF_RTLSECT : OOO_STRING_SVTOOLS_RTF_LTRSECT); +} + +void RtfAttributeOutput::SectionPageNumbering( USHORT nNumType, USHORT nPageRestartNumber ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if (nPageRestartNumber > 0) + { + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGNSTARTS); + m_aSectionBreaks.append((sal_Int32)nPageRestartNumber); + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGNRESTART); + } + + const char* pStr = 0; + switch ( nNumType ) + { + case SVX_NUM_CHARS_UPPER_LETTER: + case SVX_NUM_CHARS_UPPER_LETTER_N: pStr = OOO_STRING_SVTOOLS_RTF_PGNUCLTR; break; + case SVX_NUM_CHARS_LOWER_LETTER: + case SVX_NUM_CHARS_LOWER_LETTER_N: pStr = OOO_STRING_SVTOOLS_RTF_PGNLCLTR; break; + case SVX_NUM_ROMAN_UPPER: pStr = OOO_STRING_SVTOOLS_RTF_PGNUCRM; break; + case SVX_NUM_ROMAN_LOWER: pStr = OOO_STRING_SVTOOLS_RTF_PGNLCRM; break; + + case SVX_NUM_ARABIC: pStr = OOO_STRING_SVTOOLS_RTF_PGNDEC; break; + } + if (pStr) + m_aSectionBreaks.append(pStr); +} + +void RtfAttributeOutput::SectionType( BYTE nBreakCode ) +{ + OSL_TRACE("%s, nBreakCode = %d", OSL_THIS_FUNC, nBreakCode); + + /* + * break code: 0 No break, 1 New column + * 2 New page, 3 Even page, 4 Odd page + */ + const char* sType = NULL; + switch ( nBreakCode ) + { + case 1: sType = OOO_STRING_SVTOOLS_RTF_SBKCOL; break; + case 2: sType = OOO_STRING_SVTOOLS_RTF_SBKPAGE; break; + case 3: sType = OOO_STRING_SVTOOLS_RTF_SBKEVEN; break; + case 4: sType = OOO_STRING_SVTOOLS_RTF_SBKODD; break; + default: sType = OOO_STRING_SVTOOLS_RTF_SBKNONE; break; + } + m_aSectionBreaks.append(sType); + if (!m_bBufferSectionBreaks) + m_rExport.Strm() << m_aSectionBreaks.makeStringAndClear(); +} + +void RtfAttributeOutput::NumberingDefinition( USHORT nId, const SwNumRule &/*rRule*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << '{' << OOO_STRING_SVTOOLS_RTF_LISTOVERRIDE; + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LISTID; + m_rExport.OutULong(nId); + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LISTOVERRIDECOUNT << '0'; + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LS; + m_rExport.OutULong(nId) << '}'; +} + +void RtfAttributeOutput::StartAbstractNumbering( USHORT nId ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << '{' << OOO_STRING_SVTOOLS_RTF_LIST << OOO_STRING_SVTOOLS_RTF_LISTTEMPLATEID; + m_rExport.OutULong( nId ); + m_nListId = nId; +} + +void RtfAttributeOutput::EndAbstractNumbering() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LISTID; + m_rExport.OutULong( m_nListId ) << '}' << m_rExport.sNewLine; +} + +void RtfAttributeOutput::NumberingLevel( BYTE nLevel, + USHORT nStart, + USHORT nNumberingType, + SvxAdjust eAdjust, + const BYTE * pNumLvlPos, + BYTE /*nFollow*/, + const wwFont * pFont, + const SfxItemSet * pOutSet, + sal_Int16 nIndentAt, + sal_Int16 nFirstLineIndex, + sal_Int16 /*nListTabPos*/, + const String &rNumberingString ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << m_rExport.sNewLine; + if( nLevel > 8 ) // RTF knows only 9 levels + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_IGNORE << OOO_STRING_SVTOOLS_RTF_SOUTLVL; + + m_rExport.Strm() << '{' << OOO_STRING_SVTOOLS_RTF_LISTLEVEL; + + USHORT nVal = 0; + switch( nNumberingType ) + { + case SVX_NUM_ROMAN_UPPER: nVal = 1; break; + case SVX_NUM_ROMAN_LOWER: nVal = 2; break; + case SVX_NUM_CHARS_UPPER_LETTER: + case SVX_NUM_CHARS_UPPER_LETTER_N: nVal = 3; break; + case SVX_NUM_CHARS_LOWER_LETTER: + case SVX_NUM_CHARS_LOWER_LETTER_N: nVal = 4; break; + + case SVX_NUM_BITMAP: + case SVX_NUM_CHAR_SPECIAL: nVal = 23; break; + } + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LEVELNFC; + m_rExport.OutULong( nVal ); + + switch( eAdjust ) + { + case SVX_ADJUST_CENTER: nVal = 1; break; + case SVX_ADJUST_RIGHT: nVal = 2; break; + default: nVal = 0; break; + } + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LEVELJC; + m_rExport.OutULong( nVal ); + + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LEVELSTARTAT; + m_rExport.OutULong( nStart ); + + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_LEVELFOLLOW << "0"; + + // leveltext group + m_rExport.Strm() << '{' << OOO_STRING_SVTOOLS_RTF_LEVELTEXT << ' '; + + if( SVX_NUM_CHAR_SPECIAL == nNumberingType || + SVX_NUM_BITMAP == nNumberingType ) + { + m_rExport.Strm() << "\\'01"; + sal_Unicode cChar = rNumberingString.GetChar(0); + m_rExport.Strm() << "\\u"; + m_rExport.OutULong(cChar); + m_rExport.Strm() << " ?"; + } + else + { + m_rExport.Strm() << "\\'" << m_rExport.OutHex( rNumberingString.Len(), 2 ); + m_rExport.Strm() << m_rExport.OutString( rNumberingString, m_rExport.eDefaultEncoding ); + } + + m_rExport.Strm() << ";}"; + + // write the levelnumbers + m_rExport.Strm() << "{" << OOO_STRING_SVTOOLS_RTF_LEVELNUMBERS; + for( BYTE i = 0; i <= nLevel && pNumLvlPos[ i ]; ++i ) + { + m_rExport.Strm() << "\\'" << m_rExport.OutHex(pNumLvlPos[ i ], 2).getStr(); + } + m_rExport.Strm() << ";}"; + + if( pOutSet ) + { + if (pFont) + { + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_F; + m_rExport.OutULong(m_rExport.maFontHelper.GetId(*pFont)); + } + m_rExport.OutputItemSet( *pOutSet, false, true, i18n::ScriptType::LATIN ); + m_rExport.Strm() << m_aStyles.makeStringAndClear(); + } + + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_FI; + m_rExport.OutLong( nFirstLineIndex ) << OOO_STRING_SVTOOLS_RTF_LI; + m_rExport.OutLong( nIndentAt ); + + m_rExport.Strm() << '}'; + if( nLevel > 8 ) + m_rExport.Strm() << '}'; +} + +void RtfAttributeOutput::WriteField_Impl( const SwField* pFld, ww::eField /*eType*/, const String& rFldCmd, BYTE /*nMode*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + // NEEDSWORK this has beeen tested only with page numbers + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_FIELD); + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FLDINST " "); + m_aRunText.append(m_rExport.OutString(rFldCmd, m_rExport.eCurrentEncoding)); + m_aRunText.append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " "); + if (pFld) + m_aRunText.append(m_rExport.OutString(pFld->GetCntnt(), m_rExport.eDefaultEncoding)); + m_aRunText.append("}}"); +} + +void RtfAttributeOutput::WriteBookmarks_Impl( std::vector< rtl::OUString >& rStarts, std::vector< rtl::OUString >& rEnds ) +{ + for ( std::vector< OUString >::const_iterator it = rStarts.begin(), end = rStarts.end(); it < end; ++it ) + { + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_BKMKSTART " "); + m_aRun.append(m_rExport.OutString(*it, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + } + rStarts.clear(); + + for ( std::vector< OUString >::const_iterator it = rEnds.begin(), end = rEnds.end(); it < end; ++it ) + { + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_BKMKEND " "); + m_aRun.append(m_rExport.OutString(*it, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + } + rEnds.clear(); +} + +void RtfAttributeOutput::WriteHeaderFooter_Impl( const SwFrmFmt& rFmt, bool bHeader, const sal_Char* pStr ) +{ + OStringBuffer aSectionBreaks = m_aSectionBreaks; + m_aSectionBreaks.setLength(0); + OStringBuffer aRun = m_aRun; + m_aRun.setLength(0); + + m_aSectionHeaders.append(bHeader ? OOO_STRING_SVTOOLS_RTF_HEADERY : OOO_STRING_SVTOOLS_RTF_FOOTERY); + m_aSectionHeaders.append((sal_Int32)m_rExport.pAktPageDesc->GetMaster().GetULSpace().GetUpper()); + m_aSectionHeaders.append('{'); + m_aSectionHeaders.append(pStr); + m_bBufferSectionHeaders = true; + m_rExport.WriteHeaderFooterText(rFmt, bHeader); + m_bBufferSectionHeaders = false; + m_aSectionHeaders.append('}'); + + m_aSectionBreaks = aSectionBreaks; + m_aRun = aRun; +} + +void RtfAttributeOutput::OutputFlyFrame_Impl( const sw::Frame& rFrame, const Point& /*rNdTopLeft*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const SwNode *pNode = rFrame.GetContent(); + const SwGrfNode *pGrfNode = pNode ? pNode->GetGrfNode() : 0; + + switch ( rFrame.GetWriterType() ) + { + case sw::Frame::eTxtBox: + OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty"); + m_rExport.mpParentFrame = &rFrame; + m_rExport.bOutFlyFrmAttrs = m_rExport.bRTFFlySyntax = true; + m_rExport.OutputFormat( rFrame.GetFrmFmt(), false, false, true ); + m_rExport.Strm() << m_aRunText.makeStringAndClear(); + m_rExport.Strm() << m_aStyles.makeStringAndClear(); + m_rExport.bOutFlyFrmAttrs = m_rExport.bRTFFlySyntax = false; + m_rExport.Strm() << "{" OOO_STRING_SVTOOLS_RTF_IGNORE; + m_rExport.OutputFormat( rFrame.GetFrmFmt(), false, false, true ); + m_rExport.Strm() << m_aRunText.makeStringAndClear(); + m_rExport.Strm() << m_aStyles.makeStringAndClear(); + m_rExport.Strm() << '}'; + + { + /* + * Save m_aRun as we should not loose the opening brace. + * OTOH, just drop the contents of m_aRunText in case something + * would be there, causing a problem later. + */ + OString aSave = m_aRun.makeStringAndClear(); + m_rExport.bRTFFlySyntax = true; + m_rExport.OutContent(*rFrame.GetContent()); + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_PARD; + m_rExport.bRTFFlySyntax = false; + m_aRun.append(aSave); + m_aRunText.setLength(0); + } + + m_rExport.mpParentFrame = NULL; + m_rExport.Strm() << RtfExport::sNewLine; + break; + case sw::Frame::eGraphic: + if (!rFrame.IsInline()) + { + m_rExport.mpParentFrame = &rFrame; + m_rExport.bRTFFlySyntax = true; + m_rExport.OutputFormat( rFrame.GetFrmFmt(), false, false, true ); + m_rExport.bRTFFlySyntax = false; + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE); + m_rExport.OutputFormat( rFrame.GetFrmFmt(), false, false, true ); + m_aRunText.append('}'); + m_rExport.mpParentFrame = NULL; + } + + if ( pGrfNode ) + FlyFrameGraphic( *pGrfNode, rFrame.GetLayoutSize() ); + break; + case sw::Frame::eDrawing: + { + const SdrObject* pSdrObj = rFrame.GetFrmFmt().FindRealSdrObject(); + if ( pSdrObj ) + { + bool bSwapInPage = false; + if ( !pSdrObj->GetPage() ) + { + if ( SdrModel* pModel = m_rExport.pDoc->GetDrawModel() ) + { + if ( SdrPage *pPage = pModel->GetPage( 0 ) ) + { + bSwapInPage = true; + const_cast< SdrObject* >( pSdrObj )->SetPage( pPage ); + } + } + } + + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_FIELD "{"); + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_IGNORE); + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_FLDINST); + m_aRunText.append(" SHAPE "); + m_aRunText.append("}" "{" OOO_STRING_SVTOOLS_RTF_FLDRSLT); + + m_rExport.SdrExporter().AddSdrObject( *pSdrObj ); + + m_aRunText.append('}'); + m_aRunText.append('}'); + + if ( bSwapInPage ) + const_cast< SdrObject* >( pSdrObj )->SetPage( 0 ); + } + } + break; + case sw::Frame::eFormControl: + { + const SwFrmFmt &rFrmFmt = rFrame.GetFrmFmt(); + const SdrObject *pObject = rFrmFmt.FindRealSdrObject(); + + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_FIELD); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FLDINST); + + if (pObject && pObject->GetObjInventor() == FmFormInventor) + { + if (SdrUnoObj *pFormObj = PTR_CAST(SdrUnoObj,pObject)) + { + uno::Reference< awt::XControlModel > xControlModel = + pFormObj->GetUnoControlModel(); + uno::Reference< lang::XServiceInfo > xInfo(xControlModel, uno::UNO_QUERY); + uno::Reference xPropSet(xControlModel, uno::UNO_QUERY); + uno::Reference xPropSetInfo = xPropSet->getPropertySetInfo(); + OUString sName; + if (xInfo->supportsService(C2U("com.sun.star.form.component.CheckBox"))) + { + + m_aRun.append(OUStringToOString(OUString(FieldString(ww::eFORMCHECKBOX)), m_rExport.eCurrentEncoding)); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FORMFIELD "{"); + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFTYPE "1"); // 1 = checkbox + // checkbox size in half points, this seems to be always 20, see WW8Export::DoCheckBox() + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFHPS "20"); + + OUString aStr; + sName = C2U("Name"); + if (xPropSetInfo->hasPropertyByName(sName)) + { + xPropSet->getPropertyValue(sName) >>= aStr; + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFNAME " "); + m_aRun.append(OUStringToOString(aStr, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + } + + sName = C2U("HelpText"); + if (xPropSetInfo->hasPropertyByName(sName)) + { + xPropSet->getPropertyValue(sName) >>= aStr; + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFHELPTEXT " "); + m_aRun.append(OUStringToOString(aStr, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + } + + sName = C2U("HelpF1Text"); + if (xPropSetInfo->hasPropertyByName(sName)) + { + xPropSet->getPropertyValue(sName) >>= aStr; + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFSTATTEXT " "); + m_aRun.append(OUStringToOString(aStr, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + } + + sal_Int16 nTemp = 0; + xPropSet->getPropertyValue(C2U("DefaultState")) >>= nTemp; + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFDEFRES); + m_aRun.append((sal_Int32)nTemp); + xPropSet->getPropertyValue(C2U("State")) >>= nTemp; + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFRES); + m_aRun.append((sal_Int32)nTemp); + + m_aRun.append("}}"); + + // field result is empty, ffres already contains the form result + m_aRun.append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " "); + } + else if (xInfo->supportsService(C2U("com.sun.star.form.component.TextField"))) + { + OStringBuffer aBuf; + OString aStr; + OUString aTmp; + const sal_Char* pStr; + + m_aRun.append(OUStringToOString(OUString(FieldString(ww::eFORMTEXT)), m_rExport.eCurrentEncoding)); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_DATAFIELD " "); + for (int i = 0; i < 8; i++) aBuf.append((sal_Char)0x00); + xPropSet->getPropertyValue(C2U("Name")) >>= aTmp; + aStr = OUStringToOString(aTmp, m_rExport.eCurrentEncoding); + aBuf.append((sal_Char)aStr.getLength()); + aBuf.append(aStr); + aBuf.append((sal_Char)0x00); + xPropSet->getPropertyValue(C2U("DefaultText")) >>= aTmp; + aStr = OUStringToOString(aTmp, m_rExport.eCurrentEncoding); + aBuf.append((sal_Char)aStr.getLength()); + aBuf.append(aStr); + for (int i = 0; i < 11; i++) aBuf.append((sal_Char)0x00); + aStr = aBuf.makeStringAndClear(); + pStr = aStr.getStr(); + for (int i = 0; i < aStr.getLength(); i++, pStr++) + m_aRun.append(m_rExport.OutHex(*pStr, 2)); + m_aRun.append('}'); + m_aRun.append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " "); + xPropSet->getPropertyValue(C2U("Text")) >>= aTmp; + m_aRun.append(OUStringToOString(aTmp, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FORMFIELD "{"); + sName = C2U("HelpText"); + if (xPropSetInfo->hasPropertyByName(sName)) + { + xPropSet->getPropertyValue(sName) >>= aTmp; + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFHELPTEXT " "); + m_aRun.append(OUStringToOString(aTmp, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + } + + sName = C2U("HelpF1Text"); + if (xPropSetInfo->hasPropertyByName(sName)) + { + xPropSet->getPropertyValue(sName) >>= aTmp; + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFSTATTEXT " "); + m_aRun.append(OUStringToOString(aTmp, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + } + m_aRun.append("}"); + } + else if (xInfo->supportsService(C2U("com.sun.star.form.component.ListBox"))) + { + OUString aStr; + uno::Sequence aIntSeq; + uno::Sequence aStrSeq; + + m_aRun.append(OUStringToOString(OUString(FieldString(ww::eFORMDROPDOWN)), m_rExport.eCurrentEncoding)); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FORMFIELD "{"); + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFTYPE "2"); // 2 = list + + xPropSet->getPropertyValue(C2U("DefaultSelection")) >>= aIntSeq; + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFDEFRES); + // a dropdown list can have only one 'selected item by default' + m_aRun.append((sal_Int32)aIntSeq[0]); + + xPropSet->getPropertyValue(C2U("SelectedItems")) >>= aIntSeq; + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFRES); + // a dropdown list can have only one 'currently selected item' + m_aRun.append((sal_Int32)aIntSeq[0]); + + sName = C2U("Name"); + if (xPropSetInfo->hasPropertyByName(sName)) + { + xPropSet->getPropertyValue(sName) >>= aStr; + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFNAME " "); + m_aRun.append(OUStringToOString(aStr, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + } + + sName = C2U("HelpText"); + if (xPropSetInfo->hasPropertyByName(sName)) + { + xPropSet->getPropertyValue(sName) >>= aStr; + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFOWNHELP); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFHELPTEXT " "); + m_aRun.append(OUStringToOString(aStr, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + } + + sName = C2U("HelpF1Text"); + if (xPropSetInfo->hasPropertyByName(sName)) + { + xPropSet->getPropertyValue(sName) >>= aStr; + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFOWNSTAT); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFSTATTEXT " "); + m_aRun.append(OUStringToOString(aStr, m_rExport.eCurrentEncoding)); + m_aRun.append('}'); + } + + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FFHASLISTBOX); + + xPropSet->getPropertyValue(C2U("StringItemList")) >>= aStrSeq; + sal_uInt32 nListItems = aStrSeq.getLength(); + for (sal_uInt32 i = 0; i < nListItems; i++) + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FFL " ") + .append(OUStringToOString(aStrSeq[i], m_rExport.eCurrentEncoding)).append('}'); + + m_aRun.append("}}"); + + // field result is empty, ffres already contains the form result + m_aRun.append("}{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " "); + } + else + OSL_TRACE("%s unhandled form control: '%s'", OSL_THIS_FUNC, + OUStringToOString(xInfo->getImplementationName(), m_rExport.eCurrentEncoding).getStr()); + m_aRun.append('}'); + } + } + + m_aRun.append('}'); + } + break; + case sw::Frame::eOle: + { + const SwFrmFmt &rFrmFmt = rFrame.GetFrmFmt(); + const SdrObject *pSdrObj = rFrmFmt.FindRealSdrObject(); + if ( pSdrObj ) + { + SwNodeIndex aIdx(*rFrmFmt.GetCntnt().GetCntntIdx(), 1); + SwOLENode& rOLENd = *aIdx.GetNode().GetOLENode(); + FlyFrameOLE(rOLENd, rFrame.GetLayoutSize()); + } + } + break; + default: + OSL_TRACE("%s: unknown type (%d)", OSL_THIS_FUNC, rFrame.GetWriterType()); + break; + } +} + +void RtfAttributeOutput::CharCaseMap( const SvxCaseMapItem& rCaseMap ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + switch ( rCaseMap.GetValue() ) + { + case SVX_CASEMAP_KAPITAELCHEN: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SCAPS); + break; + case SVX_CASEMAP_VERSALIEN: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CAPS); + break; + default: // Something that rtf does not support + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SCAPS); + m_aStyles.append((sal_Int32)0); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CAPS); + m_aStyles.append((sal_Int32)0); + break; + } +} + +void RtfAttributeOutput::CharColor( const SvxColorItem& rColor ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const Color aColor( rColor.GetValue() ); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CF); + m_aStyles.append( (sal_Int32)m_rExport.GetColor( aColor )); +} + +void RtfAttributeOutput::CharContour( const SvxContourItem& rContour ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_OUTL); + if ( !rContour.GetValue() ) + m_aStyles.append((sal_Int32)0); +} + +void RtfAttributeOutput::CharCrossedOut( const SvxCrossedOutItem& rCrossedOut ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + switch ( rCrossedOut.GetStrikeout() ) + { + case STRIKEOUT_NONE: + if (!m_bStrikeDouble) + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKE); + else + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKED); + m_aStyles.append((sal_Int32)0); + break; + case STRIKEOUT_DOUBLE: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKED); + m_aStyles.append((sal_Int32)1); + break; + default: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_STRIKE); + break; + } +} + +void RtfAttributeOutput::CharEscapement( const SvxEscapementItem& rEsc ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const char * pUpDn; + + SwTwips nH = ((SvxFontHeightItem&)m_rExport.GetItem( RES_CHRATR_FONTSIZE )).GetHeight(); + + if( 0 < rEsc.GetEsc() ) + pUpDn = OOO_STRING_SVTOOLS_RTF_UP; + else if( 0 > rEsc.GetEsc() ) + { + pUpDn = OOO_STRING_SVTOOLS_RTF_DN; + nH = -nH; + } + else + return; + + short nEsc = rEsc.GetEsc(); + short nProp = rEsc.GetProp() * 100; + if( DFLT_ESC_AUTO_SUPER == nEsc ) + { + nEsc = 100 - rEsc.GetProp(); + ++nProp; + } + else if( DFLT_ESC_AUTO_SUB == nEsc ) + { + nEsc = - 100 + rEsc.GetProp(); + ++nProp; + } + + m_aStyles.append('{'); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_IGNORE); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_UPDNPROP); + m_aStyles.append( (sal_Int32)nProp ); + m_aStyles.append('}'); + m_aStyles.append(pUpDn); + + /* + * Calculate the act. FontSize and the percentage of the displacement; + * RTF file expects half points, while internally it's in twips. + * Formally : (FontSize * 1/20 ) pts x * 2 + * ----------------------- = ------------ + * 100% Escapement + */ + + m_aStyles.append( (sal_Int32) ( (long( nEsc ) * nH) + 500L ) / 1000L ); + // 500L to round !! +} + +void RtfAttributeOutput::CharFont( const SvxFontItem& rFont) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStylesEnd.append(OOO_STRING_SVTOOLS_RTF_LOCH); + m_aStylesEnd.append(OOO_STRING_SVTOOLS_RTF_F); + m_aStylesEnd.append((sal_Int32)m_rExport.maFontHelper.GetId(rFont)); + m_rExport.eCurrentEncoding = rtl_getTextEncodingFromWindowsCharset(sw::ms::rtl_TextEncodingToWinCharset(rFont.GetCharSet())); +} + +void RtfAttributeOutput::CharFontSize( const SvxFontHeightItem& rFontSize) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + switch ( rFontSize.Which() ) + { + case RES_CHRATR_FONTSIZE: + m_aStylesEnd.append(OOO_STRING_SVTOOLS_RTF_FS); + m_aStylesEnd.append((sal_Int32)(rFontSize.GetHeight() / 10 )); + break; + case RES_CHRATR_CJK_FONTSIZE: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FS); + m_aStyles.append((sal_Int32)(rFontSize.GetHeight() / 10 )); + break; + case RES_CHRATR_CTL_FONTSIZE: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_AFS); + m_aStyles.append((sal_Int32)(rFontSize.GetHeight() / 10 )); + break; + } +} + +void RtfAttributeOutput::CharKerning( const SvxKerningItem& rKerning ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + // in quater points then in twips + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_EXPND); + m_aStyles.append((sal_Int32)(rKerning.GetValue() / 5)); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_EXPNDTW); + m_aStyles.append((sal_Int32)(rKerning.GetValue())); +} + +void RtfAttributeOutput::CharLanguage( const SvxLanguageItem& rLanguage ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + switch (rLanguage.Which()) + { + case RES_CHRATR_LANGUAGE: + m_aStylesEnd.append(OOO_STRING_SVTOOLS_RTF_LANG); + m_aStylesEnd.append((sal_Int32)rLanguage.GetLanguage()); + break; + case RES_CHRATR_CJK_LANGUAGE: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LANGFE); + m_aStyles.append((sal_Int32)rLanguage.GetLanguage()); + break; + case RES_CHRATR_CTL_LANGUAGE: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LANG); + m_aStyles.append((sal_Int32)rLanguage.GetLanguage()); + break; + } +} + +void RtfAttributeOutput::CharPosture( const SvxPostureItem& rPosture ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_I); + if ( rPosture.GetPosture() == ITALIC_NONE ) + m_aStyles.append((sal_Int32)0); +} + +void RtfAttributeOutput::CharShadow( const SvxShadowedItem& rShadow ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SHAD); + if ( !rShadow.GetValue() ) + m_aStyles.append((sal_Int32)0); +} + +void RtfAttributeOutput::CharUnderline( const SvxUnderlineItem& rUnderline ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const char* pStr = 0; + const SfxPoolItem* pItem = m_rExport.HasItem( RES_CHRATR_WORDLINEMODE ); + bool bWord = false; + if (pItem) + bWord = ((const SvxWordLineModeItem*)pItem)->GetValue() ? true : false; + switch(rUnderline.GetLineStyle() ) + { + case UNDERLINE_SINGLE: + pStr = bWord ? OOO_STRING_SVTOOLS_RTF_ULW : OOO_STRING_SVTOOLS_RTF_UL; + break; + case UNDERLINE_DOUBLE: + pStr = OOO_STRING_SVTOOLS_RTF_ULDB; + break; + case UNDERLINE_NONE: + pStr = OOO_STRING_SVTOOLS_RTF_ULNONE; + break; + case UNDERLINE_DOTTED: + pStr = OOO_STRING_SVTOOLS_RTF_ULD; + break; + case UNDERLINE_DASH: + pStr = OOO_STRING_SVTOOLS_RTF_ULDASH; + break; + case UNDERLINE_DASHDOT: + pStr = OOO_STRING_SVTOOLS_RTF_ULDASHD; + break; + case UNDERLINE_DASHDOTDOT: + pStr = OOO_STRING_SVTOOLS_RTF_ULDASHDD; + break; + case UNDERLINE_BOLD: + pStr = OOO_STRING_SVTOOLS_RTF_ULTH; + break; + case UNDERLINE_WAVE: + pStr = OOO_STRING_SVTOOLS_RTF_ULWAVE; + break; + case UNDERLINE_BOLDDOTTED: + pStr = OOO_STRING_SVTOOLS_RTF_ULTHD; + break; + case UNDERLINE_BOLDDASH: + pStr = OOO_STRING_SVTOOLS_RTF_ULTHDASH; + break; + case UNDERLINE_LONGDASH: + pStr = OOO_STRING_SVTOOLS_RTF_ULLDASH; + break; + case UNDERLINE_BOLDLONGDASH: + pStr = OOO_STRING_SVTOOLS_RTF_ULTHLDASH; + break; + case UNDERLINE_BOLDDASHDOT: + pStr = OOO_STRING_SVTOOLS_RTF_ULTHDASHD; + break; + case UNDERLINE_BOLDDASHDOTDOT: + pStr = OOO_STRING_SVTOOLS_RTF_ULTHDASHDD; + break; + case UNDERLINE_BOLDWAVE: + pStr = OOO_STRING_SVTOOLS_RTF_ULHWAVE; + break; + case UNDERLINE_DOUBLEWAVE: + pStr = OOO_STRING_SVTOOLS_RTF_ULULDBWAVE; + break; + default: + break; + } + + if( pStr ) + { + m_aStyles.append(pStr); + // NEEDSWORK looks like here rUnderline.GetColor() is always black, + // even if the color in the odt is for example green... + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ULC); + m_aStyles.append( (sal_Int32)m_rExport.GetColor(rUnderline.GetColor()) ); + } +} + +void RtfAttributeOutput::CharWeight( const SvxWeightItem& rWeight ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_B); + if ( rWeight.GetWeight() != WEIGHT_BOLD ) + m_aStyles.append((sal_Int32)0); +} + +void RtfAttributeOutput::CharAutoKern( const SvxAutoKernItem& rAutoKern) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KERNING); + m_aStyles.append((sal_Int32) (rAutoKern.GetValue() ? 1 : 0)); +} + +void RtfAttributeOutput::CharAnimatedText( const SvxBlinkItem& rBlink ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ANIMTEXT); + m_aStyles.append((sal_Int32) (rBlink.GetValue() ? 2 : 0)); +} + +void RtfAttributeOutput::CharBackground( const SvxBrushItem& rBrush ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if( !rBrush.GetColor().GetTransparency() ) + { + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CHCBPAT); + m_aStyles.append((sal_Int32)m_rExport.GetColor(rBrush.GetColor())); + } +} + +void RtfAttributeOutput::CharFontCJK( const SvxFontItem& rFont ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HICH); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_AF); + m_aStyles.append((sal_Int32)m_rExport.maFontHelper.GetId(rFont)); +} + +void RtfAttributeOutput::CharFontSizeCJK( const SvxFontHeightItem& rFontSize ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + CharFontSize( rFontSize ); +} + +void RtfAttributeOutput::CharLanguageCJK( const SvxLanguageItem& rLanguageItem ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + CharLanguage( rLanguageItem ); +} + +void RtfAttributeOutput::CharPostureCJK( const SvxPostureItem& rPosture ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_I); + if ( rPosture.GetPosture() == ITALIC_NONE ) + m_aStyles.append((sal_Int32)0); +} + +void RtfAttributeOutput::CharWeightCJK( const SvxWeightItem& rWeight ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_B); + if ( rWeight.GetWeight() != WEIGHT_BOLD ) + m_aStyles.append((sal_Int32)0); +} + +void RtfAttributeOutput::CharFontCTL( const SvxFontItem& rFont ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_DBCH); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_AF); + m_aStyles.append((sal_Int32)m_rExport.maFontHelper.GetId(rFont)); +} + +void RtfAttributeOutput::CharFontSizeCTL( const SvxFontHeightItem& rFontSize ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + CharFontSize( rFontSize ); +} + +void RtfAttributeOutput::CharLanguageCTL( const SvxLanguageItem& rLanguageItem ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + CharLanguage( rLanguageItem ); +} + +void RtfAttributeOutput::CharPostureCTL( const SvxPostureItem& rPosture) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_AI); + if ( rPosture.GetPosture() == ITALIC_NONE ) + m_aStyles.append((sal_Int32)0); +} + +void RtfAttributeOutput::CharWeightCTL( const SvxWeightItem& rWeight ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_AB); + if ( rWeight.GetWeight() != WEIGHT_BOLD ) + m_aStyles.append((sal_Int32)0); +} + +void RtfAttributeOutput::CharRotate( const SvxCharRotateItem& rRotate) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HORZVERT); + m_aStyles.append((sal_Int32)(rRotate.IsFitToLine() ? 1 : 0)); +} + +void RtfAttributeOutput::CharEmphasisMark( const SvxEmphasisMarkItem& rEmphasisMark ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const sal_Char* pStr; + switch( rEmphasisMark.GetEmphasisMark()) + { + case EMPHASISMARK_NONE: pStr = OOO_STRING_SVTOOLS_RTF_ACCNONE; break; + case EMPHASISMARK_SIDE_DOTS: pStr = OOO_STRING_SVTOOLS_RTF_ACCCOMMA; break; + default: pStr = OOO_STRING_SVTOOLS_RTF_ACCDOT; break; + } + m_aStyles.append(pStr); +} + +void RtfAttributeOutput::CharTwoLines( const SvxTwoLinesItem& rTwoLines ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if( rTwoLines.GetValue() ) + { + sal_Unicode cStart = rTwoLines.GetStartBracket(); + sal_Unicode cEnd = rTwoLines.GetEndBracket(); + + USHORT nType; + if( !cStart && !cEnd ) + nType = 0; + else if( '{' == cStart || '}' == cEnd ) + nType = 4; + else if( '<' == cStart || '>' == cEnd ) + nType = 3; + else if( '[' == cStart || ']' == cEnd ) + nType = 2; + else // all other kind of brackets + nType = 1; + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TWOINONE); + m_aStyles.append((sal_Int32)nType); + } +} + +void RtfAttributeOutput::CharScaleWidth( const SvxCharScaleWidthItem& rScaleWidth ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CHARSCALEX); + m_aStyles.append((sal_Int32)rScaleWidth.GetValue()); +} + +void RtfAttributeOutput::CharRelief( const SvxCharReliefItem& rRelief ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const sal_Char* pStr; + switch (rRelief.GetValue()) + { + case RELIEF_EMBOSSED: + pStr = OOO_STRING_SVTOOLS_RTF_EMBO; + break; + case RELIEF_ENGRAVED: + pStr = OOO_STRING_SVTOOLS_RTF_IMPR; + break; + default: + pStr = 0; + break; + } + + if (pStr) + m_aStyles.append(pStr); +} + +void RtfAttributeOutput::CharHidden( const SvxCharHiddenItem& rHidden ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_V); + if ( !rHidden.GetValue() ) + m_aStyles.append((sal_Int32)0); +} + +void RtfAttributeOutput::TextINetFormat( const SwFmtINetFmt& rURL ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if( rURL.GetValue().Len() ) + { + const SwCharFmt* pFmt; + const SwTxtINetFmt* pTxtAtr = rURL.GetTxtINetFmt(); + + m_aStyles.append("{" OOO_STRING_SVTOOLS_RTF_FLDRSLT " "); + if( pTxtAtr && 0 != ( pFmt = pTxtAtr->GetCharFmt() )) + { + USHORT nStyle = m_rExport.GetId( *pFmt ); + OString* pString = m_rExport.GetStyle(nStyle); + if (pString) + m_aStyles.append(*pString); + } + } +} + +void RtfAttributeOutput::TextCharFormat( const SwFmtCharFmt& rCharFmt ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + USHORT nStyle = m_rExport.GetId( *rCharFmt.GetCharFmt() ); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_CS); + m_aStyles.append((sal_Int32)nStyle); + OString* pString = m_rExport.GetStyle(nStyle); + if (pString) + m_aStyles.append(*pString); +} + +void RtfAttributeOutput::WriteTextFootnoteNumStr(const SwFmtFtn& rFootnote) +{ + if (!rFootnote.GetNumStr().Len()) + m_aRun.append(OOO_STRING_SVTOOLS_RTF_CHFTN); + else + m_aRun.append(m_rExport.OutString(rFootnote.GetNumStr(), m_rExport.eCurrentEncoding)); +} + +void RtfAttributeOutput::TextFootnote_Impl( const SwFmtFtn& rFootnote ) +{ + OSL_TRACE("%s start", OSL_THIS_FUNC); + + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_SUPER " "); + WriteTextFootnoteNumStr(rFootnote); + m_aRun.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_FOOTNOTE); + if( rFootnote.IsEndNote() ) + m_aRun.append(OOO_STRING_SVTOOLS_RTF_FTNALT); + m_aRun.append(' '); + WriteTextFootnoteNumStr(rFootnote); + + /* + * The footnote contains a whole paragraph, so we have to: + * 1) Reset, then later restore the contents of our run buffer. + * 2) Buffer the output of the whole paragraph, as we do so for section headers already. + */ + const SwNodeIndex* pIndex = rFootnote.GetTxtFtn()->GetStartNode(); + OStringBuffer aRun = m_aRun; + m_aRun.setLength(0); + m_bBufferSectionHeaders = true; + m_rExport.WriteSpecialText( pIndex->GetIndex() + 1, + pIndex->GetNode().EndOfSectionIndex(), + !rFootnote.IsEndNote() ? TXT_FTN : TXT_EDN); + m_bBufferSectionHeaders = false; + m_aRun = aRun; + m_aRun.append(m_aSectionHeaders.makeStringAndClear()); + + m_aRun.append("}"); + m_aRun.append("}"); + + OSL_TRACE("%s end", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::ParaLineSpacing_Impl( short nSpace, short nMulti ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SL); + m_aStyles.append((sal_Int32)nSpace); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SLMULT); + m_aStyles.append((sal_Int32)nMulti); + +} + +void RtfAttributeOutput::ParaAdjust( const SvxAdjustItem& rAdjust ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + switch ( rAdjust.GetAdjust() ) + { + case SVX_ADJUST_LEFT: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QL); + break; + case SVX_ADJUST_RIGHT: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QR); + break; + case SVX_ADJUST_BLOCKLINE: + case SVX_ADJUST_BLOCK: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QJ); + break; + case SVX_ADJUST_CENTER: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_QC); + break; + default: + break; + } +} + +void RtfAttributeOutput::ParaSplit( const SvxFmtSplitItem& rSplit ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if( !rSplit.GetValue() ) + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KEEP); +} + +void RtfAttributeOutput::ParaWidows( const SvxWidowsItem& rWidows ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if (rWidows.GetValue()) + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_WIDCTLPAR); + else + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOWIDCTLPAR); +} + +void RtfAttributeOutput::ParaTabStop( const SvxTabStopItem& rTabStop ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + long nOffset = ((SvxLRSpaceItem&)m_rExport.GetItem( RES_LR_SPACE )).GetTxtLeft(); + for( USHORT n = 0; n < rTabStop.Count(); n++ ) + { + const SvxTabStop & rTS = rTabStop[ n ]; + if( SVX_TAB_ADJUST_DEFAULT != rTS.GetAdjustment() ) + { + const char* pFill = 0; + switch( rTS.GetFill() ) + { + case cDfltFillChar: + break; + + case '.': pFill = OOO_STRING_SVTOOLS_RTF_TLDOT; break; + case '_': pFill = OOO_STRING_SVTOOLS_RTF_TLUL; break; + case '-': pFill = OOO_STRING_SVTOOLS_RTF_TLTH; break; + case '=': pFill = OOO_STRING_SVTOOLS_RTF_TLEQ; break; + default: + break; + } + if( pFill ) + m_aStyles.append(pFill); + + const sal_Char* pAdjStr = 0; + switch (rTS.GetAdjustment()) + { + case SVX_TAB_ADJUST_RIGHT: + pAdjStr = OOO_STRING_SVTOOLS_RTF_TQR; + break; + case SVX_TAB_ADJUST_DECIMAL: + pAdjStr = OOO_STRING_SVTOOLS_RTF_TQDEC; + break; + case SVX_TAB_ADJUST_CENTER: + pAdjStr = OOO_STRING_SVTOOLS_RTF_TQC; + break; + default: + break; + } + if (pAdjStr) + m_aStyles.append(pAdjStr); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TX); + m_aStyles.append((sal_Int32)(rTS.GetTabPos() + nOffset)); + } + else + { + m_aTabStop.append( OOO_STRING_SVTOOLS_RTF_DEFTAB ); + m_aTabStop.append( (sal_Int32)rTabStop[0].GetTabPos() ); + } + } +} + +void RtfAttributeOutput::ParaHyphenZone( const SvxHyphenZoneItem& rHyphenZone ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + sal_Int32 nFlags = rHyphenZone.IsHyphen() ? 1 : 0; + if( rHyphenZone.IsPageEnd() ) + nFlags += 2; + m_aStyles.append('{'); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_IGNORE); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HYPHEN); + m_aStyles.append((sal_Int32)nFlags); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HYPHLEAD); + m_aStyles.append((sal_Int32)rHyphenZone.GetMinLead()); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HYPHTRAIL); + m_aStyles.append((sal_Int32)rHyphenZone.GetMinTrail()); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_HYPHMAX); + m_aStyles.append((sal_Int32)rHyphenZone.GetMaxHyphens()); + m_aStyles.append('}'); +} + +void RtfAttributeOutput::ParaNumRule_Impl( const SwTxtNode* pTxtNd, sal_Int32 nLvl, sal_Int32 nNumId ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( USHRT_MAX == nNumId || 0 == nNumId || 0 == pTxtNd) + return; + + const SwNumRule* pRule = pTxtNd->GetNumRule(); + + // --> OD 2008-03-18 #refactorlists# + // if( pRule && MAXLEVEL > pTxtNd->GetActualListLevel() ) + if( pRule && pTxtNd->IsInList() ) + // <-- + { + // --> OD 2008-03-18 #refactorlists# + ASSERT( pTxtNd->GetActualListLevel() >= 0 && pTxtNd->GetActualListLevel() < MAXLEVEL, + " - text node does not have valid list level. Serious defect -> please inform OD" ); + // <-- + + const bool bExportNumRule = USHRT_MAX != nNumId; + const SwNumFmt* pFmt = pRule->GetNumFmt( nLvl ); + if( !pFmt ) + pFmt = &pRule->Get( nLvl ); + + const SfxItemSet& rNdSet = pTxtNd->GetSwAttrSet(); + + if ( bExportNumRule ) { + m_aStyles.append('{'); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LISTTEXT); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_PARD); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_PLAIN); + m_aStyles.append(' '); + } + + SvxLRSpaceItem aLR( (SvxLRSpaceItem&)rNdSet.Get( RES_LR_SPACE ) ); + aLR.SetTxtLeft( aLR.GetTxtLeft() + pFmt->GetIndentAt() ); + aLR.SetTxtFirstLineOfst( pFmt->GetFirstLineOffset() ); + + USHORT nStyle = m_rExport.GetId( *pFmt->GetCharFmt() ); + OString* pString = m_rExport.GetStyle(nStyle); + if (pString) + m_aStyles.append(*pString); + + { + String sTxt; + if( SVX_NUM_CHAR_SPECIAL == pFmt->GetNumberingType() || SVX_NUM_BITMAP == pFmt->GetNumberingType() ) + sTxt = pFmt->GetBulletChar(); + else + sTxt = pTxtNd->GetNumString(); + + m_aStyles.append(' '); + + if (sTxt.Len()) + { + m_aStyles.append(m_rExport.OutString(sTxt, m_rExport.eDefaultEncoding)); + } + + if( bExportNumRule ) + { + if( OUTLINE_RULE != pRule->GetRuleType() ) + { + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TAB); + m_aStyles.append('}'); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ILVL); + if( nLvl > 8 ) // RTF knows only 9 levels + { + m_aStyles.append((sal_Int32)8); + m_aStyles.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SOUTLVL); + m_aStyles.append((sal_Int32)nLvl); + m_aStyles.append('}'); + } + else + m_aStyles.append((sal_Int32)nLvl); + } + else + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TAB "}"); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LS); + m_aStyles.append((sal_Int32)m_rExport.GetId(*pRule)+1); + m_aStyles.append(' '); + } + else if( sTxt.Len() ) + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_TAB); + } + FormatLRSpace(aLR); + } +} + +void RtfAttributeOutput::ParaScriptSpace( const SfxBoolItem& rScriptSpace ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if (!rScriptSpace.GetValue( )) + return; + switch ( rScriptSpace.Which( ) ) + { + case RES_PARATR_SCRIPTSPACE: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_ASPALPHA); + break; + /* Is this needed? + case RES_PARATR_HANGINGPUNCTUATION: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOOVERFLOW); + break; + case RES_PARATR_FORBIDDEN_RULES: + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOCWRAP); + break;*/ + default: + break; + } +} + +void RtfAttributeOutput::ParaVerticalAlign( const SvxParaVertAlignItem& rAlign ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const char* pStr; + switch ( rAlign.GetValue() ) + { + case SvxParaVertAlignItem::TOP: pStr = OOO_STRING_SVTOOLS_RTF_FAHANG; break; + case SvxParaVertAlignItem::BOTTOM: pStr = OOO_STRING_SVTOOLS_RTF_FAVAR; break; + case SvxParaVertAlignItem::CENTER: pStr = OOO_STRING_SVTOOLS_RTF_FACENTER; break; + case SvxParaVertAlignItem::BASELINE: pStr = OOO_STRING_SVTOOLS_RTF_FAROMAN; break; + // default == SvxParaVertAlignItem::AUTOMATIC + default: pStr = OOO_STRING_SVTOOLS_RTF_FAAUTO; break; + } + m_aStyles.append(pStr); +} + +void RtfAttributeOutput::ParaSnapToGrid( const SvxParaGridItem& /*rGrid*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::FormatFrameSize( const SwFmtFrmSize& rSize ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( m_rExport.bOutFlyFrmAttrs && m_rExport.bRTFFlySyntax ) + { + if( rSize.GetWidth() ) + { + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_ABSW); + m_aRunText.append((sal_Int32)rSize.GetWidth()); + } + + if( rSize.GetHeight() ) + { + long nH = rSize.GetHeight(); + if( ATT_FIX_SIZE == rSize.GetHeightSizeType() ) + nH = -nH; + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_ABSH); + m_aRunText.append((sal_Int32)nH); + } + } + else if (m_rExport.bOutPageDescs) + { + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGWSXN); + m_aSectionBreaks.append((sal_Int32)rSize.GetWidth()); + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_PGHSXN); + m_aSectionBreaks.append((sal_Int32)rSize.GetHeight()); + if (!m_bBufferSectionBreaks) + m_rExport.Strm() << m_aSectionBreaks.makeStringAndClear(); + } +} + +void RtfAttributeOutput::FormatPaperBin( const SvxPaperBinItem& ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::FormatLRSpace( const SvxLRSpaceItem& rLRSpace ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( !m_rExport.bOutFlyFrmAttrs ) + { + if( m_rExport.bOutPageDescs ) + { + if( rLRSpace.GetLeft() ) + { + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGLSXN); + m_aSectionBreaks.append((sal_Int32)rLRSpace.GetLeft()); + } + if( rLRSpace.GetRight() ) + { + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGRSXN); + m_aSectionBreaks.append((sal_Int32)rLRSpace.GetRight()); + } + if (!m_bBufferSectionBreaks) + m_rExport.Strm() << m_aSectionBreaks.makeStringAndClear(); + } + else + { + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LI); + m_aStyles.append( (sal_Int32) rLRSpace.GetTxtLeft() ); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RI); + m_aStyles.append( (sal_Int32) rLRSpace.GetRight() ); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LIN); + m_aStyles.append( (sal_Int32) rLRSpace.GetTxtLeft() ); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RIN); + m_aStyles.append( (sal_Int32) rLRSpace.GetRight() ); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_FI); + m_aStyles.append( (sal_Int32) rLRSpace.GetTxtFirstLineOfst() ); + } + } + else if (rLRSpace.GetLeft() == rLRSpace.GetRight() && m_rExport.bRTFFlySyntax) + { + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_DFRMTXTX; + m_rExport.OutLong( rLRSpace.GetLeft() ); + } +} + +void RtfAttributeOutput::FormatULSpace( const SvxULSpaceItem& rULSpace ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( !m_rExport.bOutFlyFrmAttrs ) + { + if( m_rExport.bOutPageDescs ) + { + if( rULSpace.GetUpper() ) + { + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGTSXN); + m_aSectionBreaks.append((sal_Int32)rULSpace.GetUpper()); + } + if( rULSpace.GetLower() ) + { + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_MARGBSXN); + m_aSectionBreaks.append((sal_Int32)rULSpace.GetLower()); + } + if (!m_bBufferSectionBreaks) + m_rExport.Strm() << m_aSectionBreaks.makeStringAndClear(); + } + else + { + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SB); + m_aStyles.append( (sal_Int32) rULSpace.GetUpper() ); + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_SA); + m_aStyles.append( (sal_Int32) rULSpace.GetLower() ); + } + } + else if (rULSpace.GetUpper() == rULSpace.GetLower() && m_rExport.bRTFFlySyntax) + { + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_DFRMTXTY; + m_rExport.OutLong( rULSpace.GetLower() ); + } +} + +void RtfAttributeOutput::FormatSurround( const SwFmtSurround& rSurround ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( m_rExport.bOutFlyFrmAttrs && !m_rExport.bRTFFlySyntax ) + { + SwSurround eSurround = rSurround.GetSurround(); + BOOL bGold = SURROUND_IDEAL == eSurround; + if( bGold ) + eSurround = SURROUND_PARALLEL; + RTFSurround aMC( bGold, static_cast< BYTE >(eSurround) ); + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_FLYMAINCNT); + m_aRunText.append( (sal_Int32) aMC.GetValue() ); + } +} + +void RtfAttributeOutput::FormatVertOrientation( const SwFmtVertOrient& rFlyVert ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( m_rExport.bOutFlyFrmAttrs && m_rExport.bRTFFlySyntax ) + { + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_PVPARA); + + switch (rFlyVert.GetVertOrient()) + { + case text::VertOrientation::TOP: + case text::VertOrientation::LINE_TOP: + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_POSYT); + break; + case text::VertOrientation::BOTTOM: + case text::VertOrientation::LINE_BOTTOM: + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_POSYB); + break; + case text::VertOrientation::CENTER: + case text::VertOrientation::LINE_CENTER: + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_POSYC); + break; + case text::VertOrientation::NONE: + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_POSY); + m_aRunText.append((sal_Int32)rFlyVert.GetPos()); + break; + default: + break; + } + } + else if ( !m_rExport.bRTFFlySyntax ) + { + RTFVertOrient aVO( static_cast< USHORT >(rFlyVert.GetVertOrient()), static_cast< USHORT >(rFlyVert.GetRelationOrient()) ); + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_FLYVERT); + m_aRunText.append((sal_Int32)aVO.GetValue()); + } +} + +void RtfAttributeOutput::FormatHorizOrientation( const SwFmtHoriOrient& rFlyHori ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( m_rExport.bOutFlyFrmAttrs && m_rExport.bRTFFlySyntax ) + { + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_PHCOL); + + const char* pS = 0; + switch(rFlyHori.GetHoriOrient()) + { + case text::HoriOrientation::RIGHT: + pS = rFlyHori.IsPosToggle() ? OOO_STRING_SVTOOLS_RTF_POSXO : OOO_STRING_SVTOOLS_RTF_POSXR; + break; + case text::HoriOrientation::LEFT: + pS = rFlyHori.IsPosToggle() ? OOO_STRING_SVTOOLS_RTF_POSXI : OOO_STRING_SVTOOLS_RTF_POSXL; + break; + case text::HoriOrientation::CENTER: + pS = OOO_STRING_SVTOOLS_RTF_POSXC; + break; + case text::HoriOrientation::NONE: + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_POSX); + m_aRunText.append((sal_Int32)rFlyHori.GetPos()); + break; + default: + break; + } + if (pS) + m_aRunText.append(pS); + } else if ( !m_rExport.bRTFFlySyntax ) + { + RTFHoriOrient aHO( static_cast< USHORT >(rFlyHori.GetHoriOrient()), + static_cast< USHORT >(rFlyHori.GetRelationOrient()) ); + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_FLYHORZ); + m_aRunText.append((sal_Int32)aHO.GetValue()); + } +} + +void RtfAttributeOutput::FormatAnchor( const SwFmtAnchor& rAnchor ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( !m_rExport.bRTFFlySyntax ) + { + USHORT nId = static_cast< USHORT >(rAnchor.GetAnchorId()); + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_FLYANCHOR); + m_aRunText.append((sal_Int32)nId); + switch( nId ) + { + case FLY_AT_PAGE: + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_FLYPAGE); + m_aRunText.append((sal_Int32)rAnchor.GetPageNum()); + break; + case FLY_AT_PARA: + case FLY_AS_CHAR: + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_FLYCNTNT); + break; + } + } +} + +void RtfAttributeOutput::FormatBackground( const SvxBrushItem& rBrush ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if( !rBrush.GetColor().GetTransparency() ) + { + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_CHCBPAT); + m_aStyles.append((sal_Int32)m_rExport.GetColor(rBrush.GetColor())); + } +} + +void RtfAttributeOutput::FormatBox( const SvxBoxItem& rBox ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + static USHORT __READONLY_DATA aBorders[] = { + BOX_LINE_TOP, BOX_LINE_LEFT, BOX_LINE_BOTTOM, BOX_LINE_RIGHT }; + static const sal_Char* aBorderNames[] = { + OOO_STRING_SVTOOLS_RTF_BRDRT, OOO_STRING_SVTOOLS_RTF_BRDRL, OOO_STRING_SVTOOLS_RTF_BRDRB, OOO_STRING_SVTOOLS_RTF_BRDRR }; + + USHORT nDist = rBox.GetDistance(); + + if ( m_rExport.bRTFFlySyntax ) + return; + + if( rBox.GetTop() && rBox.GetBottom() && + rBox.GetLeft() && rBox.GetRight() && + *rBox.GetTop() == *rBox.GetBottom() && + *rBox.GetTop() == *rBox.GetLeft() && + *rBox.GetTop() == *rBox.GetRight() && + nDist == rBox.GetDistance( BOX_LINE_TOP ) && + nDist == rBox.GetDistance( BOX_LINE_LEFT ) && + nDist == rBox.GetDistance( BOX_LINE_BOTTOM ) && + nDist == rBox.GetDistance( BOX_LINE_RIGHT )) + m_aSectionBreaks.append(OutBorderLine( m_rExport, rBox.GetTop(), OOO_STRING_SVTOOLS_RTF_BOX, nDist )); + else + { + const USHORT* pBrd = aBorders; + const sal_Char** pBrdNms = (const sal_Char**)aBorderNames; + for(int i = 0; i < 4; ++i, ++pBrd, ++pBrdNms) + { + if (const SvxBorderLine* pLn = rBox.GetLine(*pBrd)) + { + m_aSectionBreaks.append(OutBorderLine(m_rExport, pLn, *pBrdNms, + rBox.GetDistance(*pBrd))); + } + } + } + + const USHORT* pBrd = aBorders; + const sal_Char** pBrdNms = (const sal_Char**)aBorderNames; + for( int i = 0; i < 4; ++i, ++pBrd, ++pBrdNms ) + { + const SvxBorderLine* pLn = rBox.GetLine( *pBrd ); + if( pLn ) + { + m_aSectionBreaks.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE); + m_aSectionBreaks.append(OutBorderLine( m_rExport, pLn, *pBrdNms )); + m_aSectionBreaks.append("}" OOO_STRING_SVTOOLS_RTF_BRSP); + m_aSectionBreaks.append((sal_Int32)rBox.GetDistance( *pBrd )); + } + } + + if (!m_bBufferSectionBreaks) + m_aStyles.append(m_aSectionBreaks.makeStringAndClear()); +} + +void RtfAttributeOutput::FormatColumns_Impl( USHORT nCols, const SwFmtCol& rCol, bool bEven, SwTwips nPageSize ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_COLS; + m_rExport.OutLong( nCols ); + + if( bEven ) + { + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_COLSX; + m_rExport.OutLong( rCol.GetGutterWidth( TRUE ) ); + } + else + { + const SwColumns & rColumns = rCol.GetColumns( ); + for( USHORT n = 0; n < nCols; ) + { + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_COLNO; + m_rExport.OutLong( n+1 ); + + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_COLW; + m_rExport.OutLong( rCol.CalcPrtColWidth( n, nPageSize ) ); + + if( ++n != nCols ) + { + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_COLSR; + m_rExport.OutLong( rColumns[ n-1 ]->GetRight() + + rColumns[ n ]->GetLeft() ); + } + } + } +} + +void RtfAttributeOutput::FormatKeep( const SvxFmtKeepItem& rItem ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if( rItem.GetValue() ) + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_KEEPN); +} + +void RtfAttributeOutput::FormatTextGrid( const SwTextGridItem& /*rGrid*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::FormatLineNumbering( const SwFmtLineNumber& rNumbering ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( !rNumbering.IsCount( ) ) + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_NOLINE); +} + +void RtfAttributeOutput::FormatFrameDirection( const SvxFrameDirectionItem& rDirection ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if (!m_rExport.bOutPageDescs) + { + if (rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP) + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_RTLPAR); + else + m_aStyles.append(OOO_STRING_SVTOOLS_RTF_LTRPAR); + } +} + +void RtfAttributeOutput::WriteExpand( const SwField* /*pFld*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::RefField( const SwField& /*rFld*/, const String& /*rRef*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::HiddenField( const SwField& /*rFld*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::SetField( const SwField& /*rFld*/, ww::eField /*eType*/, const String& /*rCmd*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfAttributeOutput::PostitField( const SwField* pFld ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + const SwPostItField& rPFld = *(SwPostItField*)pFld; + + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATNID " "); + m_aRunText.append(OUStringToOString(OUString(rPFld.GetPar1()), m_rExport.eCurrentEncoding)); + m_aRunText.append("}"); + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATNAUTHOR " "); + m_aRunText.append(OUStringToOString(OUString(rPFld.GetPar1()), m_rExport.eCurrentEncoding)); + m_aRunText.append("}"); + m_aRunText.append(OOO_STRING_SVTOOLS_RTF_CHATN); + + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ANNOTATION); + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_ATNDATE " "); + m_aRunText.append((sal_Int32)sw::ms::DateTime2DTTM(rPFld.GetDate())); + m_aRunText.append('}'); + m_aRunText.append(OUStringToOString(OUString(rPFld.GetTxt()), m_rExport.eCurrentEncoding)); + m_aRunText.append('}'); +} + +bool RtfAttributeOutput::DropdownField( const SwField* /*pFld*/ ) +{ + // this is handled in OutputFlyFrame_Impl() + return true; +} + +RtfAttributeOutput::RtfAttributeOutput( RtfExport &rExport ) + : m_rExport( rExport ), + m_pTableWrt( NULL ), + m_bTableCellOpen( false ), + m_nTableDepth( 0 ), + m_bTblAfterCell( false ), + m_nColBreakNeeded( false ), + m_bBufferSectionBreaks( false ), + m_bBufferSectionHeaders( false ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); +} + +RtfAttributeOutput::~RtfAttributeOutput() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); +} + +MSWordExportBase& RtfAttributeOutput::GetExport() +{ + return m_rExport; +} + +// These are used by wwFont::WriteRtf() + +/// Start the font. +void RtfAttributeOutput::StartFont( const String& rFamilyName ) const +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << OUStringToOString( OUString( rFamilyName ), m_rExport.eCurrentEncoding ).getStr(); +} + +/// End the font. +void RtfAttributeOutput::EndFont() const +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << ";}"; +} + +/// Alternate name for the font. +void RtfAttributeOutput::FontAlternateName( const String& rName ) const +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << OOO_STRING_SVTOOLS_RTF_FALT << ' '; + m_rExport.Strm() << OUStringToOString( OUString( rName ), m_rExport.eCurrentEncoding ) << '}'; +} + +/// Font charset. +void RtfAttributeOutput::FontCharset( sal_uInt8 nCharSet ) const +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_FCHARSET; + m_rExport.OutULong( nCharSet ); + m_rExport.Strm() << ' '; +} + +/// Font family. +void RtfAttributeOutput::FontFamilyType( FontFamily eFamily, const wwFont &rFont ) const +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << '{' << OOO_STRING_SVTOOLS_RTF_F; + + const char* pStr = OOO_STRING_SVTOOLS_RTF_FNIL; + switch (eFamily) + { + case FAMILY_ROMAN: + pStr = OOO_STRING_SVTOOLS_RTF_FROMAN; + break; + case FAMILY_SWISS: + pStr = OOO_STRING_SVTOOLS_RTF_FSWISS; + break; + case FAMILY_MODERN: + pStr = OOO_STRING_SVTOOLS_RTF_FMODERN; + break; + case FAMILY_SCRIPT: + pStr = OOO_STRING_SVTOOLS_RTF_FSCRIPT; + break; + case FAMILY_DECORATIVE: + pStr = OOO_STRING_SVTOOLS_RTF_FDECOR; + break; + default: + break; + } + m_rExport.OutULong(m_rExport.maFontHelper.GetId(rFont)) << pStr; +} + +/// Font pitch. +void RtfAttributeOutput::FontPitchType( FontPitch ePitch ) const +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_rExport.Strm() << OOO_STRING_SVTOOLS_RTF_FPRQ; + + USHORT nVal = 0; + switch (ePitch) + { + case PITCH_FIXED: + nVal = 1; + break; + case PITCH_VARIABLE: + nVal = 2; + break; + default: + break; + } + m_rExport.OutULong(nVal); +} + +static bool IsEMF(const sal_uInt8 *pGraphicAry, unsigned long nSize) +{ + if (pGraphicAry && (nSize > 0x2c )) + { + // check the magic number + if ( + (pGraphicAry[0x28] == 0x20 ) && (pGraphicAry[0x29] == 0x45) && + (pGraphicAry[0x2a] == 0x4d ) && (pGraphicAry[0x2b] == 0x46) + ) + { + //emf detected + return true; + } + } + return false; +} + +static bool StripMetafileHeader(const sal_uInt8 *&rpGraphicAry, unsigned long &rSize) +{ + if (rpGraphicAry && (rSize > 0x22)) + { + if ( + (rpGraphicAry[0] == 0xd7) && (rpGraphicAry[1] == 0xcd) && + (rpGraphicAry[2] == 0xc6) && (rpGraphicAry[3] == 0x9a) + ) + { // we have to get rid of the metafileheader + rpGraphicAry += 22; + rSize -= 22; + return true; + } + } + return false; +} + +static OString WriteHex(const sal_uInt8* pData, sal_uInt32 nSize, sal_uInt32 nLimit = 64) +{ + OStringBuffer aRet; + + sal_uInt32 nBreak = 0; + for (sal_uInt32 i = 0; i < nSize; i++) + { + OString sNo = OString::valueOf(sal_Int32(pData[i]), 16); + if (sNo.getLength() < 2) + aRet.append('0'); + aRet.append(sNo); + if (++nBreak == nLimit) + { + aRet.append(RtfExport::sNewLine); + nBreak = 0; + } + } + + return aRet.makeStringAndClear(); +} + +static OString WriteHex(sal_Int32 nNum) +{ + return WriteHex((sal_uInt8*)&nNum, sizeof(sal_Int32)); +} + +static OString WriteHex(OString sString) +{ + OStringBuffer aRet; + + aRet.append(WriteHex(sString.getLength()+1)); + aRet.append(WriteHex((sal_uInt8*)sString.getStr(), sString.getLength()+1)); + + return aRet.makeStringAndClear(); +} + +static OString ExportPICT(const Size &rOrig, const Size &rRendered, const Size &rMapped, + const SwCropGrf &rCr, const char *pBLIPType, const sal_uInt8 *pGraphicAry, + unsigned long nSize) +{ + OStringBuffer aRet; + bool bIsWMF = (const char *)pBLIPType == (const char *)OOO_STRING_SVTOOLS_RTF_WMETAFILE ? true : false; + if (pBLIPType && nSize && pGraphicAry) + { + aRet.append("{" OOO_STRING_SVTOOLS_RTF_PICT); + + long nXCroppedSize = rOrig.Width()-(rCr.GetLeft() + rCr.GetRight()); + long nYCroppedSize = rOrig.Height()-(rCr.GetTop() + rCr.GetBottom()); + /* #127543#: Graphic with a zero height or width, typically copied from webpages, caused + crashes. */ + if( !nXCroppedSize ) + nXCroppedSize = 100; + if( !nYCroppedSize ) + nYCroppedSize = 100; + + //Given the original size and taking cropping into account + //first, how much has the original been scaled to get the + //final rendered size + aRet.append(OOO_STRING_SVTOOLS_RTF_PICSCALEX); + aRet.append((sal_Int32)((100 * rRendered.Width()) / nXCroppedSize)); + aRet.append(OOO_STRING_SVTOOLS_RTF_PICSCALEY); + aRet.append((sal_Int32)((100 * rRendered.Height()) / nYCroppedSize)); + + aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPL); + aRet.append((sal_Int32)rCr.GetLeft()); + aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPR); + aRet.append((sal_Int32)rCr.GetRight()); + aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPT); + aRet.append((sal_Int32)rCr.GetTop()); + aRet.append(OOO_STRING_SVTOOLS_RTF_PICCROPB); + aRet.append((sal_Int32)rCr.GetBottom()); + + aRet.append(OOO_STRING_SVTOOLS_RTF_PICW); + aRet.append((sal_Int32)rMapped.Width()); + aRet.append(OOO_STRING_SVTOOLS_RTF_PICH); + aRet.append((sal_Int32)rMapped.Height()); + + aRet.append(OOO_STRING_SVTOOLS_RTF_PICWGOAL); + aRet.append((sal_Int32)rOrig.Width()); + aRet.append(OOO_STRING_SVTOOLS_RTF_PICHGOAL); + aRet.append((sal_Int32)rOrig.Height()); + + aRet.append(pBLIPType); + if (bIsWMF) + { + aRet.append((sal_Int32)8); + StripMetafileHeader(pGraphicAry, nSize); + } + aRet.append(RtfExport::sNewLine); + aRet.append(WriteHex(pGraphicAry, nSize)); + aRet.append('}'); + } + return aRet.makeStringAndClear(); +} + +void RtfAttributeOutput::FlyFrameOLEData( SwOLENode& rOLENode ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + uno::Reference < embed::XEmbeddedObject > xObj(const_cast(rOLENode).GetOLEObj().GetOleRef()); + sal_Int64 nAspect = rOLENode.GetAspect(); + svt::EmbeddedObjectRef aObjRef( xObj, nAspect ); + SvGlobalName aObjName(aObjRef->getClassID()); + + if (SotExchange::IsMath(aObjName)) + { + // ObjectHeader + m_aRunText.append(WriteHex(0x00000501)); // OLEVersion + m_aRunText.append(WriteHex(0x00000002)); // FormatID + m_aRunText.append(WriteHex(OString("Equation.3"))); // ClassName + m_aRunText.append(WriteHex(0x00000000)); // TopicName + m_aRunText.append(WriteHex(0x00000000)); // ItemName + + // NativeData + SvMemoryStream *pStream = new SvMemoryStream; + SvStorage* pStorage = new SvStorage(*pStream); + m_rExport.pOLEExp->ExportOLEObject( aObjRef, *pStorage ); + pStream->Seek(STREAM_SEEK_TO_END); + sal_uInt32 nNativeDataSize = pStream->Tell(); + const sal_uInt8* pNativeData = (sal_uInt8*)pStream->GetData(); + m_aRunText.append(WriteHex(nNativeDataSize)); + m_aRunText.append(RtfExport::sNewLine); + m_aRunText.append(WriteHex(pNativeData, nNativeDataSize, 126)); + m_aRunText.append(RtfExport::sNewLine); + delete pStream; + + // MetaFilePresentationObject + pStream = new SvMemoryStream; + Graphic* pGraphic = rOLENode.GetGraphic(); + if (GraphicConverter::Export(*pStream, *pGraphic, CVT_WMF) != ERRCODE_NONE) + OSL_ENSURE(false, "failed to export the presentation data"); + pStream->Seek(STREAM_SEEK_TO_END); + sal_uInt32 nPresentationDataSize = pStream->Tell(); + const sal_uInt8* pPresentationData = (sal_uInt8*)pStream->GetData(); + m_aRunText.append(WriteHex(pPresentationData, nPresentationDataSize, 126)); + } +} + +void RtfAttributeOutput::FlyFrameOLE( SwOLENode& rOLENode, const Size& rSize ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + SvMemoryStream aStream; + const sal_uInt8* pGraphicAry = 0; + sal_uInt32 nSize = 0; + Graphic* pGraphic = rOLENode.GetGraphic(); + + Size aSize(sw::util::GetSwappedInSize(rOLENode)); + Size aRendered(aSize); + aRendered.Width() = rSize.Width(); + aRendered.Height() = rSize.Height(); + Size aMapped(pGraphic->GetPrefSize()); + const SwCropGrf &rCr = (const SwCropGrf &)rOLENode.GetAttr(RES_GRFATR_CROPGRF); + const sal_Char* pBLIPType = OOO_STRING_SVTOOLS_RTF_WMETAFILE; + + if (GraphicConverter::Export(aStream, *pGraphic, CVT_WMF) != ERRCODE_NONE) + OSL_ENSURE(false, "failed to export the graphic"); + aStream.Seek(STREAM_SEEK_TO_END); + nSize = aStream.Tell(); + pGraphicAry = (sal_uInt8*)aStream.GetData(); + + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_OBJECT OOO_STRING_SVTOOLS_RTF_OBJEMB); + + // export the object data in the appropriate format; RTF requires the usage of the OLE 1.0 format + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_OBJDATA " "); + FlyFrameOLEData(rOLENode); + m_aRunText.append("}{" OOO_STRING_SVTOOLS_RTF_RESULT); + + SwTwips nHeight = aSize.Height(); + nHeight/=20; //nHeight was in twips, want it in half points, but then half of total height. + long nFontHeight = ((const SvxFontHeightItem&)m_rExport.GetItem(RES_CHRATR_FONTSIZE)).GetHeight(); + nHeight-=nFontHeight/20; + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_DN).append(nHeight); + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SHPPICT); + m_aRunText.append(ExportPICT(aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize)); + m_aRunText.append("}}}}"); +} + +void RtfAttributeOutput::FlyFrameGraphic( const SwGrfNode& rGrfNode, const Size& rSize ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + SvMemoryStream aStream; + const sal_uInt8* pGraphicAry = 0; + sal_uInt32 nSize = 0; + + Graphic aGraphic(rGrfNode.GetGrf()); + + // If there is no graphic there is not much point in parsing it + if(aGraphic.GetType()==GRAPHIC_NONE) + return; + + GfxLink aGraphicLink; + const sal_Char* pBLIPType = 0; + if (aGraphic.IsLink()) + { + aGraphicLink = aGraphic.GetLink(); + nSize = aGraphicLink.GetDataSize(); + pGraphicAry = aGraphicLink.GetData(); + switch (aGraphicLink.GetType()) + { + case GFX_LINK_TYPE_NATIVE_JPG: + pBLIPType = OOO_STRING_SVTOOLS_RTF_JPEGBLIP; + break; + case GFX_LINK_TYPE_NATIVE_PNG: + pBLIPType = OOO_STRING_SVTOOLS_RTF_PNGBLIP; + break; + case GFX_LINK_TYPE_NATIVE_WMF: + pBLIPType = + IsEMF(pGraphicAry, nSize) ? OOO_STRING_SVTOOLS_RTF_EMFBLIP : OOO_STRING_SVTOOLS_RTF_WMETAFILE; + break; + default: + break; + } + } + + GraphicType eGraphicType = aGraphic.GetType(); + if (!pGraphicAry) + { + if (ERRCODE_NONE == GraphicConverter::Export(aStream, aGraphic, + (eGraphicType == GRAPHIC_BITMAP) ? CVT_PNG : CVT_WMF)) + { + pBLIPType = (eGraphicType == GRAPHIC_BITMAP) ? + OOO_STRING_SVTOOLS_RTF_PNGBLIP : OOO_STRING_SVTOOLS_RTF_WMETAFILE; + aStream.Seek(STREAM_SEEK_TO_END); + nSize = aStream.Tell(); + pGraphicAry = (sal_uInt8*)aStream.GetData(); + } + } + + Size aMapped(eGraphicType == GRAPHIC_BITMAP ? aGraphic.GetSizePixel() : aGraphic.GetPrefSize()); + + const SwCropGrf &rCr = (const SwCropGrf &)rGrfNode.GetAttr(RES_GRFATR_CROPGRF); + + //Get original size in twips + Size aSize(sw::util::GetSwappedInSize(rGrfNode)); + Size aRendered(aSize); + aRendered.Width() = rSize.Width(); + aRendered.Height() = rSize.Height(); + + /* + If the graphic is not of type WMF then we will have to store two + graphics, one in the native format wrapped in shppict, and the other in + the wmf format wrapped in nonshppict, so as to keep wordpad happy. If its + a wmf already then we don't need any such wrapping + */ + bool bIsWMF = (const sal_Char*)pBLIPType == (const sal_Char*)OOO_STRING_SVTOOLS_RTF_WMETAFILE ? true : false; + if (!bIsWMF) + m_aRunText.append("{" OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_SHPPICT); + + if (pBLIPType) + m_aRunText.append(ExportPICT(aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize)); + else + { + aStream.Seek(0); + GraphicConverter::Export(aStream, aGraphic, CVT_WMF); + pBLIPType = OOO_STRING_SVTOOLS_RTF_WMETAFILE; + aStream.Seek(STREAM_SEEK_TO_END); + nSize = aStream.Tell(); + pGraphicAry = (sal_uInt8*)aStream.GetData(); + + m_aRunText.append(ExportPICT(aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize)); + } + + if (!bIsWMF) + { + m_aRunText.append("}" "{" OOO_STRING_SVTOOLS_RTF_NONSHPPICT); + + aStream.Seek(0); + GraphicConverter::Export(aStream, aGraphic, CVT_WMF); + pBLIPType = OOO_STRING_SVTOOLS_RTF_WMETAFILE; + aStream.Seek(STREAM_SEEK_TO_END); + nSize = aStream.Tell(); + pGraphicAry = (sal_uInt8*)aStream.GetData(); + + m_aRunText.append(ExportPICT(aSize, aRendered, aMapped, rCr, pBLIPType, pGraphicAry, nSize)); + + m_aRunText.append('}'); + } + + m_aRunText.append(m_rExport.sNewLine); +} + +/* vi:set shiftwidth=4 expandtab: */ diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx new file mode 100644 index 0000000000..8a4d0e7665 --- /dev/null +++ b/sw/source/filter/ww8/rtfattributeoutput.hxx @@ -0,0 +1,573 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Miklos Vajna. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _RTFATTRIBUTEOUTPUT_HXX_ +#define _RTFATTRIBUTEOUTPUT_HXX_ + +#include +#include "attributeoutputbase.hxx" +#include "fields.hxx" + +#include + +#include +#include + +#include + +class RtfExport; + +class SwGrfNode; +class SwOLENode; +class SdrObject; + +class RtfAttributeOutput : public AttributeOutputBase +{ +public: + /// Export the state of RTL/CJK. + virtual void RTLAndCJKState( bool bIsRTL, sal_uInt16 nScript ); + + /// Start of the paragraph. + virtual void StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo ); + + /// End of the paragraph. + virtual void EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner ); + + /// Empty paragraph. + virtual void EmptyParagraph(); + + /// Called before we start outputting the attributes. + virtual void StartParagraphProperties( const SwTxtNode& rNode ); + + /// Called after we end outputting the attributes. + virtual void EndParagraphProperties(); + + /// Start of the text run. + virtual void StartRun( const SwRedlineData* pRedlineData ); + + /// End of the text run. + virtual void EndRun(); + + /// Called before we start outputting the attributes. + virtual void StartRunProperties(); + + /// Called after we end outputting the attributes. + virtual void EndRunProperties( const SwRedlineData* pRedlineData ); + + /// Output text (inside a run). + virtual void RunText( const String& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8 ); + + // Access to (anyway) private buffers, used by the sdr exporter + rtl::OStringBuffer& RunText(); + rtl::OStringBuffer& Styles(); + + /// Output text (without markup). + virtual void RawText( const String& rText, bool bForceUnicode, rtl_TextEncoding eCharSet ); + + /// Output ruby start. + virtual void StartRuby( const SwTxtNode& rNode, const SwFmtRuby& rRuby ); + + /// Output ruby end. + virtual void EndRuby(); + + /// Output URL start. + virtual bool StartURL( const String& rUrl, const String& rTarget ); + + /// Output URL end. + virtual bool EndURL(); + + virtual void FieldVanish( const String& rTxt, ww::eField eType ); + + /// Output redlining. + /// + /// The common attribute that can be among the run properties. + virtual void Redline( const SwRedlineData* pRedline ); + + virtual void FormatDrop( const SwTxtNode& rNode, const SwFmtDrop& rSwFmtDrop, USHORT nStyle, ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo, ww8::WW8TableNodeInfoInner::Pointer_t pTextNodeInfoInner ); + + /// Output style. + virtual void ParagraphStyle( USHORT nStyle ); + + virtual void TableInfoCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableInfoRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableDefaultBorders( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableBackgrounds( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableHeight( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableCanSplit( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableBidi( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableVerticalCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableNodeInfo( ww8::WW8TableNodeInfo::Pointer_t pNodeInfo ); + + virtual void TableNodeInfoInner( ww8::WW8TableNodeInfoInner::Pointer_t pNodeInfoInner ); + + virtual void TableOrientation( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableSpacing( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + virtual void TableRowEnd( sal_uInt32 nDepth ); + + /// Start of the styles table. + virtual void StartStyles(); + + /// End of the styles table. + virtual void EndStyles( USHORT nNumberOfStyles ); + + /// Write default style. + virtual void DefaultStyle( USHORT nStyle ); + + /// Start of a style in the styles table. + virtual void StartStyle( const String& rName, bool bPapFmt, + USHORT nBase, USHORT nNext, USHORT nWwId, USHORT nId ); + + /// End of a style in the styles table. + virtual void EndStyle(); + + /// Start of (paragraph or run) properties of a style. + virtual void StartStyleProperties( bool bParProp, USHORT nStyle ); + + /// End of (paragraph or run) properties of a style. + virtual void EndStyleProperties( bool bParProp ); + + /// Numbering rule and Id. + virtual void OutlineNumbering( BYTE nLvl, const SwNumFmt &rNFmt, const SwFmt &rFmt ); + + /// Page break + /// As a paragraph property - the paragraph should be on the next page. + virtual void PageBreakBefore( bool bBreak ); + + /// Write a section break + /// msword::ColumnBreak or msword::PageBreak + virtual void SectionBreak( BYTE nC, const WW8_SepInfo* pSectionInfo = NULL ); + + /// Start of the section properties. + virtual void StartSection(); + + /// End of the section properties. + virtual void EndSection(); + + /// Protection of forms. + virtual void SectionFormProtection( bool bProtected ); + + /// Numbering of the lines in the document. + virtual void SectionLineNumbering( ULONG nRestartNo, const SwLineNumberInfo& rLnNumInfo ); + + /// Has different headers/footers for the title page. + virtual void SectionTitlePage(); + + /// Description of the page borders. + virtual void SectionPageBorders( const SwFrmFmt* pFmt, const SwFrmFmt* pFirstPageFmt ); + + /// Columns populated from right/numbers on the right side? + virtual void SectionBiDi( bool bBiDi ); + + /// The style of the page numbers. + /// + /// nPageRestartNumberr being 0 means no restart. + virtual void SectionPageNumbering( USHORT nNumType, USHORT nPageRestartNumber ); + + /// The type of breaking. + virtual void SectionType( BYTE nBreakCode ); + + /// Definition of a numbering instance. + virtual void NumberingDefinition( USHORT nId, const SwNumRule &rRule ); + + /// Start of the abstract numbering definition instance. + virtual void StartAbstractNumbering( USHORT nId ); + + /// End of the abstract numbering definition instance. + virtual void EndAbstractNumbering(); + + /// All the numbering level information. + virtual void NumberingLevel( BYTE nLevel, + USHORT nStart, + USHORT nNumberingType, + SvxAdjust eAdjust, + const BYTE *pNumLvlPos, + BYTE nFollow, + const wwFont *pFont, + const SfxItemSet *pOutSet, + sal_Int16 nIndentAt, + sal_Int16 nFirstLineIndex, + sal_Int16 nListTabPos, + const String &rNumberingString ); + + void WriteField_Impl( const SwField* pFld, ww::eField eType, const String& rFldCmd, BYTE nMode ); + void WriteBookmarks_Impl( std::vector< rtl::OUString >& rStarts, std::vector< rtl::OUString >& rEnds ); + void WriteHeaderFooter_Impl( const SwFrmFmt& rFmt, bool bHeader, const sal_Char* pStr ); + +protected: + /// Output frames - the implementation. + virtual void OutputFlyFrame_Impl( const sw::Frame& rFmt, const Point& rNdTopLeft ); + + /// Sfx item Sfx item RES_CHRATR_CASEMAP + virtual void CharCaseMap( const SvxCaseMapItem& rCaseMap ); + + /// Sfx item Sfx item RES_CHRATR_COLOR + virtual void CharColor( const SvxColorItem& rColor); + + /// Sfx item Sfx item RES_CHRATR_CONTOUR + virtual void CharContour( const SvxContourItem& rContour ); + + /// Sfx item RES_CHRATR_CROSSEDOUT + virtual void CharCrossedOut( const SvxCrossedOutItem& rCrossedOut ); + + /// Sfx item RES_CHRATR_ESCAPEMENT + virtual void CharEscapement( const SvxEscapementItem& rEscapement ); + + /// Sfx item RES_CHRATR_FONT + virtual void CharFont( const SvxFontItem& rFont ); + + /// Sfx item RES_CHRATR_FONTSIZE + virtual void CharFontSize( const SvxFontHeightItem& rFontSize ); + + /// Sfx item RES_CHRATR_KERNING + virtual void CharKerning( const SvxKerningItem& rKerning ); + + /// Sfx item RES_CHRATR_LANGUAGE + virtual void CharLanguage( const SvxLanguageItem& rLanguage ); + + /// Sfx item RES_CHRATR_POSTURE + virtual void CharPosture( const SvxPostureItem& rPosture ); + + /// Sfx item RES_CHRATR_SHADOWED + virtual void CharShadow( const SvxShadowedItem& rShadow ); + + /// Sfx item RES_CHRATR_UNDERLINE + virtual void CharUnderline( const SvxUnderlineItem& rUnderline ); + + /// Sfx item RES_CHRATR_WEIGHT + virtual void CharWeight( const SvxWeightItem& rWeight ); + + /// Sfx item RES_CHRATR_AUTOKERN + virtual void CharAutoKern( const SvxAutoKernItem& ); + + /// Sfx item RES_CHRATR_BLINK + virtual void CharAnimatedText( const SvxBlinkItem& rBlink ); + + /// Sfx item RES_CHRATR_BACKGROUND + virtual void CharBackground( const SvxBrushItem& rBrush ); + + /// Sfx item RES_CHRATR_CJK_FONT + virtual void CharFontCJK( const SvxFontItem& rFont ); + + /// Sfx item RES_CHRATR_CJK_FONTSIZE + virtual void CharFontSizeCJK( const SvxFontHeightItem& rFontSize ); + + /// Sfx item RES_CHRATR_CJK_LANGUAGE + virtual void CharLanguageCJK( const SvxLanguageItem& rLanguageItem ); + + /// Sfx item RES_CHRATR_CJK_POSTURE + virtual void CharPostureCJK( const SvxPostureItem& rPosture ); + + /// Sfx item RES_CHRATR_CJK_WEIGHT + virtual void CharWeightCJK( const SvxWeightItem& rWeight ); + + /// Sfx item RES_CHRATR_CTL_FONT + virtual void CharFontCTL( const SvxFontItem& rFont ); + + /// Sfx item RES_CHRATR_CTL_FONTSIZE + virtual void CharFontSizeCTL( const SvxFontHeightItem& rFontSize ); + + /// Sfx item RES_CHRATR_CTL_LANGUAGE + virtual void CharLanguageCTL( const SvxLanguageItem& rLanguageItem ); + + /// Sfx item RES_CHRATR_CTL_POSTURE + virtual void CharPostureCTL( const SvxPostureItem& rWeight ); + + /// Sfx item RES_CHRATR_CTL_WEIGHT + virtual void CharWeightCTL( const SvxWeightItem& rWeight ); + + /// Sfx item RES_CHRATR_ROTATE + virtual void CharRotate( const SvxCharRotateItem& rRotate ); + + /// Sfx item RES_CHRATR_EMPHASIS_MARK + virtual void CharEmphasisMark( const SvxEmphasisMarkItem& rEmphasisMark ); + + /// Sfx item RES_CHRATR_TWO_LINES + virtual void CharTwoLines( const SvxTwoLinesItem& rTwoLines ); + + /// Sfx item RES_CHRATR_SCALEW + virtual void CharScaleWidth( const SvxCharScaleWidthItem& rScaleWidth ); + + /// Sfx item RES_CHRATR_RELIEF + virtual void CharRelief( const SvxCharReliefItem& rRelief); + + /// Sfx item RES_CHRATR_HIDDEN + virtual void CharHidden( const SvxCharHiddenItem& rHidden ); + + /// Sfx item RES_TXTATR_INETFMT + virtual void TextINetFormat( const SwFmtINetFmt& ); + + /// Sfx item RES_TXTATR_CHARFMT + virtual void TextCharFormat( const SwFmtCharFmt& ); + + /// Sfx item RES_TXTATR_FTN + virtual void TextFootnote_Impl( const SwFmtFtn& ); + + /// Sfx item RES_PARATR_LINESPACING + virtual void ParaLineSpacing_Impl( short nSpace, short nMulti ); + + /// Sfx item RES_PARATR_ADJUST + virtual void ParaAdjust( const SvxAdjustItem& rAdjust ); + + /// Sfx item RES_PARATR_SPLIT + virtual void ParaSplit( const SvxFmtSplitItem& rSplit ); + + /// Sfx item RES_PARATR_WIDOWS + virtual void ParaWidows( const SvxWidowsItem& rWidows ); + + /// Sfx item RES_PARATR_TABSTOP + virtual void ParaTabStop( const SvxTabStopItem& rTabStop ); + + /// Sfx item RES_PARATR_HYPHENZONE + virtual void ParaHyphenZone( const SvxHyphenZoneItem& ); + + /// Sfx item RES_PARATR_NUMRULE + virtual void ParaNumRule_Impl( const SwTxtNode *pTxtNd, sal_Int32 nLvl, sal_Int32 nNumId ); + + /// Sfx item RES_PARATR_SCRIPTSPACE + virtual void ParaScriptSpace( const SfxBoolItem& ); + + /// Sfx item RES_PARATR_VERTALIGN + virtual void ParaVerticalAlign( const SvxParaVertAlignItem& rAlign ); + + /// Sfx item RES_PARATR_SNAPTOGRID + virtual void ParaSnapToGrid( const SvxParaGridItem& ); + + /// Sfx item RES_FRM_SIZE + virtual void FormatFrameSize( const SwFmtFrmSize& ); + + /// Sfx item RES_PAPER_BIN + virtual void FormatPaperBin( const SvxPaperBinItem& ); + + /// Sfx item RES_LR_SPACE + virtual void FormatLRSpace( const SvxLRSpaceItem& rLRSpace ); + + /// Sfx item RES_UL_SPACE + virtual void FormatULSpace( const SvxULSpaceItem& rULSpace ); + + /// Sfx item RES_SURROUND + virtual void FormatSurround( const SwFmtSurround& ); + + /// Sfx item RES_VERT_ORIENT + virtual void FormatVertOrientation( const SwFmtVertOrient& ); + + /// Sfx item RES_HORI_ORIENT + virtual void FormatHorizOrientation( const SwFmtHoriOrient& ); + + /// Sfx item RES_ANCHOR + virtual void FormatAnchor( const SwFmtAnchor& ); + + /// Sfx item RES_BACKGROUND + virtual void FormatBackground( const SvxBrushItem& ); + + /// Sfx item RES_BOX + virtual void FormatBox( const SvxBoxItem& ); + + /// Sfx item RES_COL + virtual void FormatColumns_Impl( USHORT nCols, const SwFmtCol & rCol, bool bEven, SwTwips nPageSize ); + + /// Sfx item RES_KEEP + virtual void FormatKeep( const SvxFmtKeepItem& ); + + /// Sfx item RES_TEXTGRID + virtual void FormatTextGrid( const SwTextGridItem& ); + + /// Sfx item RES_LINENUMBER + virtual void FormatLineNumbering( const SwFmtLineNumber& ); + + /// Sfx item RES_FRAMEDIR + virtual void FormatFrameDirection( const SvxFrameDirectionItem& ); + + /// Write the expanded field + virtual void WriteExpand( const SwField* pFld ); + + virtual void RefField( const SwField& rFld, const String& rRef ); + virtual void HiddenField( const SwField& rFld ); + virtual void SetField( const SwField& rFld, ww::eField eType, const String& rCmd ); + virtual void PostitField( const SwField* pFld ); + virtual bool DropdownField( const SwField* pFld ); + + /// Reference to the export, where to get the data from + RtfExport &m_rExport; + +private: + + /// Output graphic fly frames. + void FlyFrameGraphic( const SwGrfNode& rGrfNode, const Size& rSize ); + void FlyFrameOLE( SwOLENode& rOLENode, const Size& rSize ); + void FlyFrameOLEData( SwOLENode& rOLENode ); + + /* + * Table methods. + */ + + void InitTableHelper( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + void StartTable( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + void StartTableRow( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + void StartTableCell( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + void TableCellProperties( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner ); + + void EndTableCell( ); + + void EndTableRow( ); + + void EndTable(); + + /// End cell, row, and even the entire table if necessary. + void FinishTableRowCell( ww8::WW8TableNodeInfoInner::Pointer_t pInner, bool bForceEmptyParagraph = false ); + + void WriteTextFootnoteNumStr(const SwFmtFtn& rFootnote); + + /* + * Current style name and its ID. + */ + String m_rStyleName; + USHORT m_nStyleId; + /* + * Current list ID. + */ + USHORT m_nListId; + /* + * This is needed because the call order is: run text, run properties, paragraph properties. + * What we need is the opposite. + */ + rtl::OStringBuffer m_aRun; + rtl::OStringBuffer m_aRunText; + /* + * This is written after runs. + */ + rtl::OStringBuffer m_aAfterRuns; + /* + * Same for colors and stylesheets: first we just want to output colors, + * need to buffer the stylesheet table to output it after the color one. + */ + rtl::OStringBuffer m_aStylesheet; + /* + * This one just holds the style commands in the current style. + */ + rtl::OStringBuffer m_aStyles; + /* + * This is the same as m_aStyles but the conents of it is written last. + */ + rtl::OStringBuffer m_aStylesEnd; + + /* + * We just get a "end of strike" mark at the end of strike, store here what to finish: single or double strike. + */ + bool m_bStrikeDouble; + + /* + * The current table helper. + */ + SwWriteTable *m_pTableWrt; + + /* + * Remember if we are in an open cell, or not. + */ + bool m_bTableCellOpen; + + /* + * Remember the current table depth. + */ + sal_uInt32 m_nTableDepth; + + /* + * Remember if we wrote a \cell or not. + */ + bool m_bTblAfterCell; + + /* + * For late output of row definitions. + */ + rtl::OStringBuffer m_aRowDefs; + + /* + * Is a column break needed after the next \par? + */ + bool m_nColBreakNeeded; + + /* + * If section breaks should be buffered to m_aSectionBreaks + */ + bool m_bBufferSectionBreaks; + rtl::OStringBuffer m_aSectionBreaks; + + /* + * If section headers (and footers) should be buffered to + * m_aSectionHeaders. + */ + bool m_bBufferSectionHeaders; + rtl::OStringBuffer m_aSectionHeaders; + +public: + RtfAttributeOutput( RtfExport &rExport ); + + virtual ~RtfAttributeOutput(); + + /// Return the right export class. + virtual MSWordExportBase& GetExport(); + + rtl::OStringBuffer m_aTabStop; + + // These are used by wwFont::WriteRtf() + /// Start the font. + void StartFont( const String& rFamilyName ) const; + + /// End the font. + void EndFont() const; + + /// Alternate name for the font. + void FontAlternateName( const String& rName ) const; + + /// Font charset. + void FontCharset( sal_uInt8 nCharSet ) const; + + /// Font family. + void FontFamilyType( FontFamily eFamily, const wwFont &rFont ) const; + + /// Font pitch. + void FontPitchType( FontPitch ePitch ) const; +}; + +#endif // _RTFATTRIBUTEOUTPUT_HXX_ + +/* vi:set shiftwidth=4 expandtab: */ diff --git a/sw/source/filter/ww8/rtfexport.cxx b/sw/source/filter/ww8/rtfexport.cxx new file mode 100644 index 0000000000..6e922245e6 --- /dev/null +++ b/sw/source/filter/ww8/rtfexport.cxx @@ -0,0 +1,1240 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Miklos Vajna. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "rtfexport.hxx" +#include "rtfexportfilter.hxx" +#include "rtfsdrexport.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ww8par.hxx" +#include "ww8scan.hxx" + +#include +#include +#include +#include +#include + +using namespace ::comphelper; +using namespace ::com::sun::star; + +using rtl::OString; +using rtl::OUString; +using rtl::OStringBuffer; +using rtl::OUStringBuffer; + +using sw::mark::IMark; + +#if defined(UNX) +const sal_Char RtfExport::sNewLine = '\012'; +#else +const sal_Char __FAR_DATA 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( USHORT nScript, USHORT 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 ) +{ + OSL_TRACE("%s", 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*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + std::vector aStarts; + std::vector aEnds; + + aStarts.push_back(rName); + aEnds.push_back(rName); + + m_pAttrOutput->WriteBookmarks_Impl(aStarts, aEnds); +} + +void RtfExport::WriteChar( sal_Unicode ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* WriteChar() has nothing to do for rtf. */ +} + +static bool IsExportNumRule( const SwNumRule& rRule, BYTE* pEnd = 0 ) +{ + BYTE nEnd = MAXLEVEL; + while( nEnd-- && !rRule.GetNumFmt( nEnd )) + ; + ++nEnd; + + const SwNumFmt* pNFmt; + BYTE nLvl; + + for( nLvl = 0; nLvl < nEnd; ++nLvl ) + if( SVX_NUM_NUMBER_NONE != ( pNFmt = &rRule.Get( nLvl )) + ->GetNumberingType() || pNFmt->GetPrefix().Len() || + (pNFmt->GetSuffix().Len() && pNFmt->GetSuffix() != aDotStr )) + break; + + if( pEnd ) + *pEnd = nEnd; + return nLvl != nEnd; +} + +void RtfExport::BuildNumbering() +{ + const SwNumRuleTbl& rListTbl = pDoc->GetNumRuleTbl(); + + for( USHORT n = rListTbl.Count()+1; n; ) + { + SwNumRule* pRule; + --n; + if( n == rListTbl.Count() ) + pRule = (SwNumRule*)pDoc->GetOutlineNumRule(); + else + { + pRule = rListTbl[ n ]; + if( !pDoc->IsUsed( *pRule )) + continue; + } + + if( IsExportNumRule( *pRule )) + GetId( *pRule ); + } +} + +void RtfExport::WriteNumbering() +{ + OSL_TRACE("%s start", OSL_THIS_FUNC); + + if ( !pUsedNumTbl ) + return; // no numbering is used + + Strm() << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << OOO_STRING_SVTOOLS_RTF_LISTTABLE; + AbstractNumberingDefinitions(); + Strm() << '}'; + + Strm() << '{' << OOO_STRING_SVTOOLS_RTF_LISTOVERRIDETABLE; + NumberingDefinitions(); + Strm() << '}'; + + OSL_TRACE("%s end", OSL_THIS_FUNC); +} + +void RtfExport::WriteRevTab() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + int nRevAuthors = pDoc->GetRedlineTbl().Count(); + + if (nRevAuthors < 1) + return; + + // RTF always seems to use Unknown as the default first entry + String sUnknown(RTL_CONSTASCII_USTRINGPARAM("Unknown")); + GetRedline(sUnknown); + + for( USHORT i = 0; i < pDoc->GetRedlineTbl().Count(); ++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(std::map::iterator aIter = m_aRedlineTbl.begin(); aIter != m_aRedlineTbl.end(); ++aIter) + Strm() << '{' << OutString((*aIter).first, eDefaultEncoding) << ";}"; + Strm() << '}' << sNewLine; +} + +void RtfExport::WriteHeadersFooters( BYTE nHeadFootFlags, + const SwFrmFmt& rFmt, const SwFrmFmt& rLeftFmt, const SwFrmFmt& rFirstPageFmt, BYTE /*nBreakCode*/ ) +{ + OSL_TRACE("%s", 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 ); + + // 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 ); +} + +void RtfExport::OutputField( const SwField* pFld, ww::eField eFldType, const String& rFldCmd, BYTE nMode ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_pAttrOutput->WriteField_Impl( pFld, eFldType, rFldCmd, nMode ); +} + +void RtfExport::WriteFormData( const ::sw::mark::IFieldmark& /*rFieldmark*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfExport::WriteHyperlinkData( const ::sw::mark::IFieldmark& /*rFieldmark*/ ) +{ + OSL_TRACE("TODO: %s", OSL_THIS_FUNC); +} + +void RtfExport::DoComboBox(const rtl::OUString& /*rName*/, + const rtl::OUString& /*rHelp*/, + const rtl::OUString& /*rToolTip*/, + const rtl::OUString& /*rSelected*/, + uno::Sequence& /*rListItems*/) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + // this is handled in RtfAttributeOutput::OutputFlyFrame_Impl +} + +void RtfExport::DoFormText(const SwInputField* /*pFld*/) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + // this is hanled in RtfAttributeOutput::OutputFlyFrame_Impl +} + +ULONG RtfExport::ReplaceCr( BYTE ) +{ + OSL_TRACE("%s", 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() +{ + OSL_TRACE("%s start", OSL_THIS_FUNC); + pStyles->OutputStylesTable(); + OSL_TRACE("%s end", OSL_THIS_FUNC); +} + +void RtfExport::WriteMainText() +{ + OSL_TRACE("%s start", OSL_THIS_FUNC); + pCurPam->GetPoint()->nNode = pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex(); + WriteText(); + OSL_TRACE("%s end", OSL_THIS_FUNC); +} + +void RtfExport::WriteInfo() +{ + OSL_TRACE("%s", 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()); + 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 << " "; + OUString sProduct; + utl::ConfigManager::GetDirectConfigProperty(utl::ConfigManager::PRODUCTNAME) >>= sProduct; + Strm() << OUStringToOString( sProduct, eCurrentEncoding) << "}{" << OOO_STRING_SVTOOLS_RTF_VERN; + OutULong( SUPD*10 ) << '}'; + Strm() << '}'; +} + +void RtfExport::WritePageDescTable() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + // Write page descriptions (page styles) + USHORT nSize = pDoc->GetPageDescCnt(); + if( !nSize ) + return; + + Strm() << sNewLine; // a separator + bOutPageDescs = TRUE; + Strm() << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << OOO_STRING_SVTOOLS_RTF_PGDSCTBL; + for( USHORT n = 0; n < nSize; ++n ) + { + const SwPageDesc& rPageDesc = + const_cast(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 + USHORT i = nSize; + while( i ) + if( rPageDesc.GetFollow() == + &const_cast(pDoc)->GetPageDesc( --i ) ) + break; + Strm() << OOO_STRING_SVTOOLS_RTF_PGDSCNXT; + OutULong( i ) << ' '; + Strm() << OutString( rPageDesc.GetName(), eDefaultEncoding) << ";}"; + } + Strm() << '}' << sNewLine; + bOutPageDescs = FALSE; +} + +void RtfExport::ExportDocument_Impl() +{ +#ifdef DEBUG + // MSWordExportBase::WriteText and others write debug messages to std::clog + // which is not interesting while debugging RtfExport + std::ostringstream aOss; + std::streambuf *pOldBuf = std::clog.rdbuf(aOss.rdbuf()); +#endif + + // 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() << sNewLine; + // 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(); + USHORT nMaxItem = rPool.GetItemCount(RES_PROTECT); + for( USHORT n = 0; n < nMaxItem; ++n ) + { + const SvxProtectItem* pProtect = (const SvxProtectItem*)rPool.GetItem(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() ) + { + //JP 06.04.99: Bug 64361 - 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 ) + { + USHORT 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() + : const_cast(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 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; + // case FTNNUM_CHAPTER: + 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; + // case SVX_NUM_ARABIC: + 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; + // case SVX_NUM_ARABIC: + default: pOut = OOO_STRING_SVTOOLS_RTF_AFTNNAR; break; + } + Strm() << pOut; + } + + Strm() << sNewLine; + + // Init sections + m_pSections = new MSWordSections( *this ); + + WriteMainText(); + + Strm() << '}'; + +#ifdef DEBUG + std::clog.rdbuf(pOldBuf); +#endif +} + +void RtfExport::PrepareNewPageDesc( const SfxItemSet* pSet, + const SwNode& rNd, const SwFmtPageDesc* pNewPgDescFmt, + const SwPageDesc* pNewPgDesc ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + const SwSectionFmt* pFmt = GetSectionFormat( rNd ); + const 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 ); + + AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo() ); +} + +bool RtfExport::DisallowInheritingOutlineNumbering( const SwFmt& rFmt ) +{ + bool bRet( false ); + + OSL_TRACE("%s", 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 << 9; + + bRet = true; + } + } + } + + return bRet; +} + +void RtfExport::OutputGrfNode( const SwGrfNode& ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* noop, see RtfAttributeOutput::FlyFrameGraphic */ +} + +void RtfExport::OutputOLENode( const SwOLENode& ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* noop, see RtfAttributeOutput::FlyFrameOLE */ +} + +void RtfExport::AppendSection( const SwPageDesc* pPageDesc, const SwSectionFmt* pFmt, ULONG nLnNum ) +{ + OSL_TRACE("%s", 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 ) + : MSWordExportBase( pDocument, pCurrentPam, pOriginalPam ), + m_pFilter( pFilter ), + m_pWriter( pWriter ), + m_pAttrOutput( NULL ), + m_pSections( NULL ), + m_pSdrExport( NULL ), + eDefaultEncoding( + rtl_getTextEncodingFromWindowsCharset( + sw::ms::rtl_TextEncodingToWinCharset(DEF_ENCODING))), + eCurrentEncoding(eDefaultEncoding), + bRTFFlySyntax(false) +{ + // 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( 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) +{ + if (rContent.Len()) + { + Strm() << '{' << pToken << ' '; + Strm() << OutString( rContent, eCurrentEncoding ).getStr(); + Strm() << '}'; + } +} + +OString RtfExport::OutHex(ULONG nHex, BYTE nLen) +{ + sal_Char aNToABuf[] = "0000000000000000"; + + OSL_ENSURE( nLen < sizeof(aNToABuf), "nLen is too big" ); + if( nLen >= sizeof(aNToABuf) ) + nLen = (sizeof(aNToABuf)-1); + + // Set pointer to the buffer end + sal_Char* pStr = aNToABuf + (sizeof(aNToABuf)-1); + for( BYTE n = 0; n < nLen; ++n ) + { + *(--pStr) = (sal_Char)(nHex & 0xf ) + 48; + if( *pStr > '9' ) + *pStr += 39; + nHex >>= 4; + } + return OString(pStr); +} + +OString RtfExport::OutChar(sal_Unicode c, int *pUCMode, rtl_TextEncoding eDestEnc) +{ + OStringBuffer aBuf; + const sal_Char* pStr = 0; + // 0x0b instead of \n, etc because of the replacements in SwAttrIter::GetSnippet() + switch (c) + { + case 0x0b: + // hard line break + pStr = OOO_STRING_SVTOOLS_RTF_LINE; + break; + case '\t': + pStr = OOO_STRING_SVTOOLS_RTF_TAB; + break; + case '\\': + case '}': + case '{': + aBuf.append('\\'); + aBuf.append((sal_Char)c); + break; + case 0xa0: + // non-breaking space + pStr = "\\~"; + break; + case 0x1e: + // non-breaking hyphen + pStr = "\\_"; + break; + case 0x1f: + // optional hyphen + pStr = "\\-"; + break; + default: + if (c >= ' ' && c <= '~') + aBuf.append((sal_Char)c); + else { + //If we can't convert to the dest encoding, or if + //its an uncommon multibyte sequence which most + //readers won't be able to handle correctly, then + //If we can't convert to the dest encoding, then + //export as unicode + OUString sBuf(&c, 1); + OString sConverted; + sal_uInt32 nFlags = + RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR | + RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR; + bool bWriteAsUnicode = !(sBuf.convertToString(&sConverted, + eDestEnc, nFlags)) + || (RTL_TEXTENCODING_UTF8==eDestEnc); // #i43933# do not export UTF-8 chars in RTF; + if (bWriteAsUnicode) + sBuf.convertToString(&sConverted, + eDestEnc, OUSTRING_TO_OSTRING_CVTFLAGS); + const sal_Int32 nLen = sConverted.getLength(); + + if (bWriteAsUnicode && pUCMode) + { + // then write as unicode - character + if (*pUCMode != nLen) + { + aBuf.append("\\uc"); + aBuf.append((sal_Int32)nLen); + // #i47831# add an additional whitespace, so that "document whitespaces" are not ignored. + aBuf.append(' '); + *pUCMode = nLen; + } + aBuf.append("\\u"); + aBuf.append((sal_Int32)c); + } + + for (sal_Int32 nI = 0; nI < nLen; ++nI) + { + aBuf.append("\\'"); + aBuf.append(OutHex(sConverted.getStr()[nI], 2)); + } + } + } + if (pStr) { + aBuf.append(pStr); + aBuf.append(' '); + } + return aBuf.makeStringAndClear(); +} + +OString RtfExport::OutString(const String &rStr, rtl_TextEncoding eDestEnc) +{ + OSL_TRACE("%s, rStr = '%s'", OSL_THIS_FUNC, + OUStringToOString( OUString( rStr ), eCurrentEncoding ).getStr()); + OStringBuffer aBuf; + int nUCMode = 1; + for (xub_StrLen n = 0; n < rStr.Len(); ++n) + aBuf.append(OutChar(rStr.GetChar(n), &nUCMode, eDestEnc)); + if (nUCMode != 1) { + aBuf.append(OOO_STRING_SVTOOLS_RTF_UC); + aBuf.append((sal_Int32)1); + aBuf.append(" "); // #i47831# add an additional whitespace, so that "document whitespaces" are not ignored.; + } + return aBuf.makeStringAndClear(); +} + +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 ) << '}'; +} + +USHORT RtfExport::GetColor( const Color& rColor ) const +{ + for (RtfColorTbl::const_iterator it=m_aColTbl.begin() ; it != m_aColTbl.end(); it++ ) + if ((*it).second == rColor) { + OSL_TRACE("%s returning %d (%d,%d,%d)", OSL_THIS_FUNC, (*it).first, rColor.GetRed(), rColor.GetGreen(), rColor.GetBlue()); + return (*it).first; + } + OSL_ENSURE( FALSE, "No such Color in m_aColTbl!" ); + return 0; +} + +void RtfExport::InsColor( const Color& rCol ) +{ + USHORT n; + for (RtfColorTbl::iterator it=m_aColTbl.begin() ; it != m_aColTbl.end(); it++ ) + if ((*it).second == rCol) + return; // Already in the table + if (rCol.GetColor() == COL_AUTO) + n = 0; + else + { + n = m_aColTbl.size(); + // Fix for the case when first a !COL_AUTO gets inserted as #0, then + // gets overwritten by COL_AUTO + if (!n) + 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. + USHORT n, 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.GetItemCount(RES_CHRATR_COLOR); + for( n = 0; n < nMaxItem; ++n ) + { + if( 0 != (pCol = (const SvxColorItem*)rPool.GetItem( + RES_CHRATR_COLOR, n ) ) ) + InsColor( pCol->GetValue() ); + } + + const SvxUnderlineItem* pUnder = (const SvxUnderlineItem*)GetDfltAttr( RES_CHRATR_UNDERLINE ); + InsColor( pUnder->GetColor() ); + nMaxItem = rPool.GetItemCount(RES_CHRATR_UNDERLINE); + for( n = 0; n < nMaxItem;n++) + { + if( 0 != (pUnder = (const SvxUnderlineItem*)rPool.GetItem( RES_CHRATR_UNDERLINE, n ) ) ) + InsColor( pUnder->GetColor() ); + + } + + const SvxOverlineItem* pOver = (const SvxOverlineItem*)GetDfltAttr( RES_CHRATR_OVERLINE ); + InsColor( pOver->GetColor() ); + nMaxItem = rPool.GetItemCount(RES_CHRATR_OVERLINE); + for( n = 0; n < nMaxItem;n++) + { + if( 0 != (pOver = (const SvxOverlineItem*)rPool.GetItem( RES_CHRATR_OVERLINE, n ) ) ) + InsColor( pOver->GetColor() ); + + } + + } + + // background color + static const USHORT aBrushIds[] = { + RES_BACKGROUND, RES_CHRATR_BACKGROUND, 0 }; + + for( const USHORT* 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.GetItemCount( *pIds ); + for( n = 0; n < nMaxItem; ++n ) + if( 0 != (pBkgrd = (const SvxBrushItem*)rPool.GetItem( + *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.GetItemCount(RES_SHADOW); + for( n = 0; n < nMaxItem; ++n ) + if( 0 != (pShadow = (const SvxShadowItem*)rPool.GetItem( + 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.GetItemCount(RES_BOX); + for( n = 0; n < nMaxItem; ++n ) + if( 0 != (pBox = (const SvxBoxItem*)rPool.GetItem( RES_BOX, n ) )) + InsColorLine( *pBox ); + } + + for( 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( USHORT nId, const OString& rStyle ) +{ + m_aStyTbl.insert(std::pair(nId, rStyle) ); +} + +OString* RtfExport::GetStyle( USHORT nId ) +{ + std::map::iterator i = m_aStyTbl.find(nId); + if (i != m_aStyTbl.end()) + return &i->second; + return NULL; +} + +USHORT 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; + } +} + +void RtfExport::OutContent( const SwNode& rNode ) +{ + OutputContentNode(*rNode.GetCntntNode()); +} + +void RtfExport::OutPageDescription( const SwPageDesc& rPgDsc, BOOL bWriteReset, BOOL bCheckForFirstPage ) +{ + OSL_TRACE("%s start", OSL_THIS_FUNC); + 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, FALSE, + &pItem ) == SFX_ITEM_SET) + WriteHeaderFooter(*pItem, true); + if( pAktPageDesc->GetLeft().GetAttrSet().GetItemState( RES_FOOTER, FALSE, + &pItem ) == SFX_ITEM_SET) + WriteHeaderFooter(*pItem, false); + + // title page + if( pAktPageDesc != &rPgDsc ) + { + pAktPageDesc = &rPgDsc; + if( pAktPageDesc->GetMaster().GetAttrSet().GetItemState( RES_HEADER, + FALSE, &pItem ) == SFX_ITEM_SET ) + WriteHeaderFooter(*pItem, true); + if( pAktPageDesc->GetMaster().GetAttrSet().GetItemState( RES_FOOTER, + FALSE, &pItem ) == SFX_ITEM_SET ) + WriteHeaderFooter(*pItem, false); + } + + // numbering type + AttrOutput().SectionPageNumbering(pAktPageDesc->GetNumType().GetNumberingType(), 0); + + pAktPageDesc = pSave; + //bOutPageDesc = bOldOut; + OSL_TRACE("%s end", OSL_THIS_FUNC); +} + +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; + } + + OSL_TRACE("%s start", OSL_THIS_FUNC); + + Strm() << (bHeader ? OOO_STRING_SVTOOLS_RTF_HEADERY : OOO_STRING_SVTOOLS_RTF_FOOTERY); + OutLong( pAktPageDesc->GetMaster(). + GetULSpace().GetUpper() ); + 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() << '}'; + + OSL_TRACE("%s end", OSL_THIS_FUNC); +} + +void RtfExport::WriteHeaderFooter(const SwFrmFmt& rFmt, bool bHeader, const sal_Char* pStr) +{ + OSL_TRACE("%s start", OSL_THIS_FUNC); + + m_pAttrOutput->WriteHeaderFooter_Impl( rFmt, bHeader, pStr ); + + OSL_TRACE("%s end", OSL_THIS_FUNC); +} + +class SwRTFWriter : public Writer +{ + public: + SwRTFWriter( const String& rFilterName, const String& rBaseURL ); + virtual ~SwRTFWriter(); + virtual ULONG WriteStream(); +}; + +SwRTFWriter::SwRTFWriter( const String& /*rFltName*/, const String & rBaseURL ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + SetBaseURL( rBaseURL ); +} + +SwRTFWriter::~SwRTFWriter() +{} + +ULONG SwRTFWriter::WriteStream() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + RtfExport aExport( NULL, pDoc, new SwPaM( *pCurPam->End(), *pCurPam->Start() ), pCurPam, this ); + aExport.ExportDocument( true ); + return 0; +} + +extern "C" SAL_DLLPUBLIC_EXPORT void SAL_CALL ExportRTF( const String& rFltName, const String& rBaseURL, WriterRef& xRet ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + xRet = new SwRTFWriter( rFltName, rBaseURL ); +} + +/* vi:set shiftwidth=4 expandtab: */ diff --git a/sw/source/filter/ww8/rtfexport.hxx b/sw/source/filter/ww8/rtfexport.hxx new file mode 100644 index 0000000000..0a2f3f4d0b --- /dev/null +++ b/sw/source/filter/ww8/rtfexport.hxx @@ -0,0 +1,211 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Miklos Vajna. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _RTFEXPORT_HXX_ +#define _RTFEXPORT_HXX_ + +#include +#include "rtfattributeoutput.hxx" +#include "wrtww8.hxx" + +#include + +#include +#include + +class RtfExportFilter; +class RtfSdrExport; +typedef std::map RtfColorTbl; +typedef std::map RtfStyleTbl; +typedef std::map RtfRedlineTbl; +class SwNode; +class SwEndNode; +class SwTableNode; +class SwTxtNode; +class SwGrfNode; +class SwOLENode; +class SwSectionNode; +class SwNumRuleTbl; + +namespace com { namespace sun { namespace star { + namespace frame { class XModel; } +} } } + +/// The class that does all the actual RTF export-related work. +class RtfExport : public MSWordExportBase +{ + /// Pointer to the filter that owns us. + RtfExportFilter *m_pFilter; + Writer* m_pWriter; + + /// Attribute output for document. + RtfAttributeOutput *m_pAttrOutput; + + /// Sections/headers/footers + MSWordSections *m_pSections; + + RtfSdrExport *m_pSdrExport; + +public: + /// Access to the attribute output class. + virtual AttributeOutputBase& AttrOutput() const; + + /// Access to the sections/headers/footres. + virtual MSWordSections& Sections() const; + + /// Access to the Rtf Sdr exporter. + virtual RtfSdrExport& SdrExporter() const; + + /// Hack, unfortunately necessary at some places for now. + virtual bool HackIsWW8OrHigher() const { return true; } + + /// Guess the script (asian/western). + virtual bool CollapseScriptsforWordOk( USHORT nScript, USHORT nWhich ); + + virtual void AppendBookmarks( const SwTxtNode& rNode, xub_StrLen nAktPos, xub_StrLen nLen ); + + virtual void AppendBookmark( const rtl::OUString& rName, bool bSkip = false ); + + virtual void WriteCR( ww8::WW8TableNodeInfoInner::Pointer_t /*pTableTextNodeInfoInner = ww8::WW8TableNodeInfoInner::Pointer_t()*/ ) { /* no-op for rtf, most probably should not even be in MSWordExportBase */ } + virtual void WriteChar( sal_Unicode ); + + /// Write the numbering table. + virtual void WriteNumbering(); + + /// Write the revision table. + virtual void WriteRevTab(); + + /// Output the actual headers and footers. + virtual void WriteHeadersFooters( BYTE nHeadFootFlags, + const SwFrmFmt& rFmt, const SwFrmFmt& rLeftFmt, const SwFrmFmt& rFirstPageFmt, BYTE nBreakCode ); + + /// Write the field + virtual void OutputField( const SwField* pFld, ww::eField eFldType, + const String& rFldCmd, BYTE nMode = nsFieldFlags::WRITEFIELD_ALL ); + + /// Write the data of the form field + virtual void WriteFormData( const ::sw::mark::IFieldmark& rFieldmark ); + virtual void WriteHyperlinkData( const ::sw::mark::IFieldmark& rFieldmark ); + + virtual void DoComboBox(const rtl::OUString &rName, + const rtl::OUString &rHelp, + const rtl::OUString &ToolTip, + const rtl::OUString &rSelected, + com::sun::star::uno::Sequence &rListItems); + + virtual void DoFormText(const SwInputField * pFld); + + virtual ULONG ReplaceCr( BYTE nChar ); + +protected: + /// Format-dependant part of the actual export. + virtual void ExportDocument_Impl(); + + virtual void SectionBreaksAndFrames( const SwTxtNode& /*rNode*/ ) {} + + /// Get ready for a new section. + virtual void PrepareNewPageDesc( const SfxItemSet* pSet, + const SwNode& rNd, + const SwFmtPageDesc* pNewPgDescFmt = 0, + const SwPageDesc* pNewPgDesc = 0 ); + + /// Return value indicates if an inherited outline numbering is suppressed. + virtual bool DisallowInheritingOutlineNumbering(const SwFmt &rFmt); + + /// Output SwGrfNode + virtual void OutputGrfNode( const SwGrfNode& ); + + /// Output SwOLENode + virtual void OutputOLENode( const SwOLENode& ); + + virtual void AppendSection( const SwPageDesc *pPageDesc, const SwSectionFmt* pFmt, ULONG nLnNum ); + +public: + /// Pass the pDocument, pCurrentPam and pOriginalPam to the base class. + RtfExport( RtfExportFilter *pFilter, SwDoc *pDocument, + SwPaM *pCurrentPam, SwPaM *pOriginalPam, Writer* pWriter ); + + /// Destructor. + virtual ~RtfExport(); + +#if defined(UNX) + static const sal_Char sNewLine; // \012 or \015 +#else + static const sal_Char __FAR_DATA sNewLine[]; // \015\012 +#endif + + rtl_TextEncoding eDefaultEncoding; + rtl_TextEncoding eCurrentEncoding; + /// This is used by OutputFlyFrame_Impl() to control the written syntax + bool bRTFFlySyntax; + + BOOL m_bOutStyleTab : 1; + SvStream& Strm(); + SvStream& OutULong( ULONG nVal ); + SvStream& OutLong( long nVal ); + void OutUnicode(const sal_Char *pToken, const String &rContent); + void OutDateTime(const sal_Char* pStr, const util::DateTime& rDT ); + rtl::OString OutChar(sal_Unicode c, int *pUCMode, rtl_TextEncoding eDestEnc); + rtl::OString OutString(const String &rStr, rtl_TextEncoding eDestEnc); + rtl::OString OutHex(ULONG nHex, BYTE nLen); + void OutPageDescription( const SwPageDesc& rPgDsc, BOOL bWriteReset, BOOL bCheckForFirstPage ); + void OutContent( const SwNode& rNode ); + + USHORT GetColor( const Color& rColor ) const; + void InsColor( const Color& rCol ); + void InsColorLine( const SvxBoxItem& rBox ); + void OutColorTable(); + USHORT GetRedline( const String& rAuthor ); + + void InsStyle( USHORT nId, const rtl::OString& rStyle ); + rtl::OString* GetStyle( USHORT nId ); + +private: + /// No copying. + RtfExport( const RtfExport& ); + + /// No copying. + RtfExport& operator=( const RtfExport& ); + + void WriteFonts(); + void WriteStyles(); + void WriteMainText(); + void WriteInfo(); + /// Writes the writer-specific \pgdsctbl group. + void WritePageDescTable(); + /// This is necessary to have the numbering table ready before the main text is being processed. + void BuildNumbering(); + void WriteHeaderFooter(const SfxPoolItem& rItem, bool bHeader); + void WriteHeaderFooter(const SwFrmFmt& rFmt, bool bHeader, const sal_Char* pStr); + + RtfColorTbl m_aColTbl; + RtfStyleTbl m_aStyTbl; + RtfRedlineTbl m_aRedlineTbl; +}; + +#endif // _RTFEXPORT_HXX_ +/* vi:set shiftwidth=4 expandtab: */ diff --git a/sw/source/filter/ww8/rtfexportfilter.cxx b/sw/source/filter/ww8/rtfexportfilter.cxx new file mode 100644 index 0000000000..df680e4264 --- /dev/null +++ b/sw/source/filter/ww8/rtfexportfilter.cxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Miklos Vajna. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::comphelper; +using namespace ::com::sun::star; +using ::rtl::OUString; + +RtfExportFilter::RtfExportFilter( const uno::Reference< lang::XMultiServiceFactory >& xMSF) : + m_xMSF( xMSF ) +{ +} + +RtfExportFilter::~RtfExportFilter() +{ +} + +sal_Bool RtfExportFilter::filter( const uno::Sequence< beans::PropertyValue >& aDescriptor ) + throw (uno::RuntimeException) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + MediaDescriptor aMediaDesc = aDescriptor; + ::uno::Reference< io::XStream > xStream = + aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_STREAMFOROUTPUT(), uno::Reference< io::XStream >() ); + m_pStream = utl::UcbStreamHelper::CreateStream( xStream, sal_True ); + m_aWriter.SetStream(m_pStream); + + // get SwDoc* + uno::Reference< uno::XInterface > xIfc( m_xSrcDoc, uno::UNO_QUERY ); + SwXTextDocument *pTxtDoc = dynamic_cast< SwXTextDocument * >( xIfc.get() ); + if ( !pTxtDoc ) { + return sal_False; + } + + SwDoc *pDoc = pTxtDoc->GetDocShell()->GetDoc(); + if ( !pDoc ) { + return sal_False; + } + + // get SwPaM* + // we get SwPaM for the entire document; copy&paste is handled internally, not via UNO + SwPaM aPam( pDoc->GetNodes().GetEndOfContent() ); + aPam.SetMark(); + aPam.Move( fnMoveBackward, fnGoDoc ); + + SwPaM *pCurPam = new SwPaM( *aPam.End(), *aPam.Start() ); + + // export the document + // (in a separate block so that it's destructed before the commit) + { + RtfExport aExport( this, pDoc, pCurPam, &aPam, NULL ); + aExport.ExportDocument( true ); + } + + // delete the pCurPam + if ( pCurPam ) + { + while ( pCurPam->GetNext() != pCurPam ) + delete pCurPam->GetNext(); + delete pCurPam; + } + delete m_pStream; + + return sal_True; +} + + +void RtfExportFilter::cancel( ) throw (uno::RuntimeException) +{ +} + +void RtfExportFilter::setSourceDocument( const uno::Reference< lang::XComponent >& xDoc ) + throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + m_xSrcDoc = xDoc; +} + +////////////////////////////////////////////////////////////////////////// +// UNO helpers +////////////////////////////////////////////////////////////////////////// + +OUString RtfExport_getImplementationName() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( IMPL_NAME_RTFEXPORT ) ); +} + +uno::Sequence< OUString > SAL_CALL RtfExport_getSupportedServiceNames() throw() +{ + const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.ExportFilter" ) ); + const uno::Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +uno::Reference< uno::XInterface > SAL_CALL RtfExport_createInstance(const uno::Reference< lang::XMultiServiceFactory > & rSMgr ) throw( uno::Exception ) +{ + return (cppu::OWeakObject*) new RtfExportFilter( rSMgr ); +} + +/* vi:set shiftwidth=4 expandtab: */ diff --git a/sw/source/filter/ww8/rtfexportfilter.hxx b/sw/source/filter/ww8/rtfexportfilter.hxx new file mode 100644 index 0000000000..98f102217d --- /dev/null +++ b/sw/source/filter/ww8/rtfexportfilter.hxx @@ -0,0 +1,84 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Miklos Vajna. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _RTFEXPORTFILTER_HXX_ +#define _RTFEXPORTFILTER_HXX_ + +#include +#include +#include +#include +#include +#include + +// This is just here so that we don't have to copy&paste its string format methods +class RtfWriter : public Writer +{ +protected: + ULONG WriteStream() { return 0; } +}; + +/// The physical access to the RTF document (for writing). +class RtfExportFilter : public cppu::WeakImplHelper2 +< + com::sun::star::document::XFilter, + com::sun::star::document::XExporter +> +{ +protected: + ::com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > m_xMSF; + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > m_xSrcDoc; + SvStream* m_pStream; +public: + RtfExportFilter( const ::com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& xMSF ); + virtual ~RtfExportFilter(); + + // XFilter + virtual sal_Bool SAL_CALL filter( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aDescriptor ) + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL cancel( ) + throw (::com::sun::star::uno::RuntimeException); + + // XExporter + virtual void SAL_CALL setSourceDocument( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xDoc ) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + + RtfWriter m_aWriter; +}; + +::rtl::OUString RtfExport_getImplementationName(); +::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL RtfExport_getSupportedServiceNames() + throw(); +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL RtfExport_createInstance( + const ::com::sun::star::uno::Reference< + com::sun::star::lang::XMultiServiceFactory > &xMSF) + throw( ::com::sun::star::uno::Exception ); + +#define IMPL_NAME_RTFEXPORT "com.sun.star.comp.Writer.RtfExport" + +#endif // _RTFEXPORTFILTER_HXX_ +/* vi:set shiftwidth=4 expandtab: */ diff --git a/sw/source/filter/ww8/rtfimportfilter.cxx b/sw/source/filter/ww8/rtfimportfilter.cxx new file mode 100644 index 0000000000..7261e5734b --- /dev/null +++ b/sw/source/filter/ww8/rtfimportfilter.cxx @@ -0,0 +1,134 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Miklos Vajna. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "rtfimportfilter.hxx" +#include "../rtf/swparrtf.hxx" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +using namespace ::comphelper; +using namespace ::com::sun::star; +using ::rtl::OUString; +using rtl::OUStringToOString; + +RtfImportFilter::RtfImportFilter( const uno::Reference< lang::XMultiServiceFactory >& xMSF) : + m_xMSF( xMSF ) +{ +} + +RtfImportFilter::~RtfImportFilter() +{ +} + +sal_Bool RtfImportFilter::filter( const uno::Sequence< beans::PropertyValue >& aDescriptor ) + throw (uno::RuntimeException) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + MediaDescriptor aMediaDesc = aDescriptor; + ::uno::Reference< io::XInputStream > xInputStream = + aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_INPUTSTREAM(), uno::Reference< io::XInputStream >() ); + SvStream* pStream = utl::UcbStreamHelper::CreateStream( xInputStream, sal_True ); + if (!pStream) + return sal_False; + + // get SwDoc* + uno::Reference< uno::XInterface > xIfc( m_xDstDoc, uno::UNO_QUERY ); + SwXTextDocument *pTxtDoc = dynamic_cast< SwXTextDocument * >( xIfc.get() ); + if (!pTxtDoc) + return sal_False; + SwDoc *pDoc = pTxtDoc->GetDocShell()->GetDoc(); + if (!pDoc) + return sal_False; + + // get SwPaM* + // NEEDSWORK should we care about partial imports? For now we just import + // the whole document + SwPaM aPam( pDoc->GetNodes().GetEndOfContent() ); + aPam.SetMark(); + aPam.Move( fnMoveBackward, fnGoDoc ); + SwPaM *pCurPam = new SwPaM( *aPam.End(), *aPam.Start() ); + + String aURL; + OUString sTemp; + for ( sal_Int32 i = 0; i < aDescriptor.getLength(); i++ ) + { + if( aDescriptor[i].Name == OUString(RTL_CONSTASCII_USTRINGPARAM("URL")) ) + { + aDescriptor[i].Value >>= sTemp; + aURL = sTemp; + } + } + + RtfReader aReader; + return aReader.Read(pStream, *pDoc, aURL, *pCurPam) == 0; +} + + +void RtfImportFilter::cancel( ) throw (uno::RuntimeException) +{ +} + +void RtfImportFilter::setTargetDocument( const uno::Reference< lang::XComponent >& xDoc ) + throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + m_xDstDoc = xDoc; +} + +////////////////////////////////////////////////////////////////////////// +// UNO helpers +////////////////////////////////////////////////////////////////////////// + +OUString RtfImport_getImplementationName() +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( IMPL_NAME_RTFIMPORT ) ); +} + +uno::Sequence< OUString > SAL_CALL RtfImport_getSupportedServiceNames() throw() +{ + const OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.document.ImportFilter" ) ); + const uno::Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +uno::Reference< uno::XInterface > SAL_CALL RtfImport_createInstance(const uno::Reference< lang::XMultiServiceFactory > & rSMgr ) throw( uno::Exception ) +{ + return (cppu::OWeakObject*) new RtfImportFilter( rSMgr ); +} + +/* vi:set shiftwidth=4 expandtab: */ diff --git a/sw/source/filter/ww8/rtfimportfilter.hxx b/sw/source/filter/ww8/rtfimportfilter.hxx new file mode 100644 index 0000000000..6f6d84d1bf --- /dev/null +++ b/sw/source/filter/ww8/rtfimportfilter.hxx @@ -0,0 +1,74 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Miklos Vajna. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _RTFIMPORTFILTER_HXX_ +#define _RTFIMPORTFILTER_HXX_ + +#include +#include +#include +#include +#include +#include + +/// The physical access to the RTF document (for reading). +class RtfImportFilter : public cppu::WeakImplHelper2 +< + com::sun::star::document::XFilter, + com::sun::star::document::XImporter +> +{ +protected: + ::com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > m_xMSF; + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent > m_xDstDoc; +public: + RtfImportFilter( const ::com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& xMSF ); + virtual ~RtfImportFilter(); + + // XFilter + virtual sal_Bool SAL_CALL filter( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aDescriptor ) + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL cancel( ) + throw (::com::sun::star::uno::RuntimeException); + + // XImporter + virtual void SAL_CALL setTargetDocument( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xDoc ) + throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); +}; + +::rtl::OUString RtfImport_getImplementationName(); +::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL RtfImport_getSupportedServiceNames() + throw(); +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL RtfImport_createInstance( + const ::com::sun::star::uno::Reference< + com::sun::star::lang::XMultiServiceFactory > &xMSF) + throw( ::com::sun::star::uno::Exception ); + +#define IMPL_NAME_RTFIMPORT "com.sun.star.comp.Writer.RtfImport" + +#endif // _RTFIMPORTFILTER_HXX_ +/* vi:set shiftwidth=4 expandtab: */ diff --git a/sw/source/filter/ww8/rtfsdrexport.cxx b/sw/source/filter/ww8/rtfsdrexport.cxx new file mode 100644 index 0000000000..a2def60f48 --- /dev/null +++ b/sw/source/filter/ww8/rtfsdrexport.cxx @@ -0,0 +1,577 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Miklos Vajna. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "rtfsdrexport.hxx" +#include "rtfexport.hxx" +#include "writerhelper.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using rtl::OString; +using rtl::OStringBuffer; +using rtl::OUString; +using rtl::OUStringBuffer; +using namespace sw::util; + +/// Implementation of an empty stream that silently succeeds, but does nothing. +/// +/// In fact, this is a hack. The right solution is to abstract EscherEx to be +/// able to work without SvStream; but at the moment it is better to live with +/// this I guess. +class SvNullStream : public SvStream +{ +protected: + virtual sal_Size GetData( void* pData, sal_Size nSize ) { memset( pData, 0, nSize ); return nSize; } + virtual sal_Size PutData( const void*, sal_Size nSize ) { return nSize; } + virtual sal_Size SeekPos( sal_Size nPos ) { return nPos; } + virtual void SetSize( sal_Size ) {} + virtual void FlushData() {} + +public: + SvNullStream() : SvStream() {} + virtual ~SvNullStream() {} +}; + +RtfSdrExport::RtfSdrExport( RtfExport &rExport ) + : EscherEx( EscherExGlobalRef( new EscherExGlobal ), *( new SvNullStream )), + m_rExport( rExport ), + m_rAttrOutput( (RtfAttributeOutput&)m_rExport.AttrOutput() ), + m_nShapeType( ESCHER_ShpInst_Nil ), + m_pShapeStyle( new OStringBuffer( 200 ) ), + m_pShapeTypeWritten( new bool[ ESCHER_ShpInst_COUNT ] ) +{ + mnGroupLevel = 1; + memset( m_pShapeTypeWritten, 0, ESCHER_ShpInst_COUNT * sizeof( bool ) ); +} + +RtfSdrExport::~RtfSdrExport() +{ + delete mpOutStrm, mpOutStrm = NULL; + delete m_pShapeStyle, m_pShapeStyle = NULL; + delete[] m_pShapeTypeWritten, m_pShapeTypeWritten = NULL; +} + +void RtfSdrExport::OpenContainer( UINT16 nEscherContainer, int nRecInstance ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + EscherEx::OpenContainer( nEscherContainer, nRecInstance ); + + if ( nEscherContainer == ESCHER_SpContainer ) + { + m_nShapeType = ESCHER_ShpInst_Nil; + if ( m_pShapeStyle->getLength() ) + m_pShapeStyle->makeStringAndClear(); + m_pShapeStyle->ensureCapacity( 200 ); + m_aShapeProps.clear(); + } +} + +void RtfSdrExport::CloseContainer() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( mRecTypes.back() == ESCHER_SpContainer ) + { + // write the shape now when we have all the info + sal_Int32 nShapeElement = StartShape(); + EndShape( nShapeElement ); + + // cleanup + m_nShapeType = ESCHER_ShpInst_Nil; + } + + EscherEx::CloseContainer(); +} + +UINT32 RtfSdrExport::EnterGroup( const String& /*rShapeName*/, const Rectangle* /*pRect*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + return GenerateShapeId(); +} + +void RtfSdrExport::LeaveGroup() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* noop */ +} + +void RtfSdrExport::AddShape( UINT32 nShapeType, UINT32 nShapeFlags, UINT32 /*nShapeId*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + m_nShapeType = nShapeType; + m_nShapeFlags = nShapeFlags; +} + +inline sal_uInt16 impl_GetUInt16( const sal_uInt8* &pVal ) +{ + sal_uInt16 nRet = *pVal++; + nRet += ( *pVal++ ) << 8; + return nRet; +} + +inline sal_Int32 impl_GetPointComponent( const sal_uInt8* &pVal, sal_uInt16 nPointSize ) +{ + sal_Int32 nRet = 0; + if ( ( nPointSize == 0xfff0 ) || ( nPointSize == 4 ) ) + { + sal_uInt16 nUnsigned = *pVal++; + nUnsigned += ( *pVal++ ) << 8; + + nRet = sal_Int16( nUnsigned ); + } + else if ( nPointSize == 8 ) + { + sal_uInt32 nUnsigned = *pVal++; + nUnsigned += ( *pVal++ ) << 8; + nUnsigned += ( *pVal++ ) << 16; + nUnsigned += ( *pVal++ ) << 24; + + nRet = nUnsigned; + } + + return nRet; +} + +void RtfSdrExport::Commit( EscherPropertyContainer& rProps, const Rectangle& rRect ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( m_nShapeType == ESCHER_ShpInst_Nil ) + return; + + if ( m_nShapeType == ESCHER_ShpInst_Line ) + AddLineDimensions( rRect ); + else + AddRectangleDimensions( *m_pShapeStyle, rRect ); + + // properties + const EscherProperties &rOpts = rProps.GetOpts(); + for ( EscherProperties::const_iterator it = rOpts.begin(); it != rOpts.end(); ++it ) + { + sal_uInt16 nId = ( it->nPropId & 0x0FFF ); + + switch ( nId ) + { + case ESCHER_Prop_WrapText: + { + int nWrapType = 0; + switch ( it->nPropValue ) + { + case ESCHER_WrapSquare: nWrapType = 2; break; + case ESCHER_WrapByPoints: nWrapType = 4; break; + case ESCHER_WrapNone: nWrapType = 3; break; + case ESCHER_WrapTopBottom: nWrapType = 1; break; + case ESCHER_WrapThrough: nWrapType = 5; break; + } + if ( nWrapType ) + m_pShapeStyle->append(OOO_STRING_SVTOOLS_RTF_SHPWR).append((sal_Int32)nWrapType); + } + break; + case ESCHER_Prop_fillColor: + m_aShapeProps.insert(std::pair(OString("fillColor"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_fillBackColor: + m_aShapeProps.insert(std::pair(OString("fillBackColor"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_AnchorText: + m_aShapeProps.insert(std::pair(OString("anchorText"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_fNoFillHitTest: + if (it->nPropValue) + m_aShapeProps.insert(std::pair(OString("fNoFillHitTest"), OString::valueOf(sal_Int32(1)))); + break; + case ESCHER_Prop_fNoLineDrawDash: + if (it->nPropValue) + m_aShapeProps.insert(std::pair(OString("fNoLineDrawDash"), OString::valueOf(sal_Int32(1)))); + break; + case ESCHER_Prop_lineColor: + m_aShapeProps.insert(std::pair(OString("lineColor"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_lineBackColor: + m_aShapeProps.insert(std::pair(OString("lineBackColor"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_lineJoinStyle: + m_aShapeProps.insert(std::pair(OString("lineJoinStyle"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_fshadowObscured: + if (it->nPropValue) + m_aShapeProps.insert(std::pair(OString("fshadowObscured"), OString::valueOf(sal_Int32(1)))); + break; + case ESCHER_Prop_geoLeft: + case ESCHER_Prop_geoTop: + { + sal_uInt32 nLeft = 0, nTop = 0; + + if ( nId == ESCHER_Prop_geoLeft ) + { + nLeft = it->nPropValue; + rProps.GetOpt( ESCHER_Prop_geoTop, nTop ); + } + else + { + nTop = it->nPropValue; + rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft ); + } + + m_aShapeProps.insert(std::pair(OString("geoLeft"), + OString::valueOf(sal_Int32(sal_Int32( nLeft ))))); + m_aShapeProps.insert(std::pair(OString("geoTop"), + OString::valueOf(sal_Int32(sal_Int32( nTop ))))); + } + break; + + case ESCHER_Prop_geoRight: + case ESCHER_Prop_geoBottom: + { + sal_uInt32 nLeft = 0, nRight = 0, nTop = 0, nBottom = 0; + rProps.GetOpt( ESCHER_Prop_geoLeft, nLeft ); + rProps.GetOpt( ESCHER_Prop_geoTop, nTop ); + + if ( nId == ESCHER_Prop_geoRight ) + { + nRight = it->nPropValue; + rProps.GetOpt( ESCHER_Prop_geoBottom, nBottom ); + } + else + { + nBottom = it->nPropValue; + rProps.GetOpt( ESCHER_Prop_geoRight, nRight ); + } + + m_aShapeProps.insert(std::pair(OString("geoRight"), + OString::valueOf(sal_Int32(sal_Int32( nRight ) - sal_Int32( nLeft ))))); + m_aShapeProps.insert(std::pair(OString("geoBottom"), + OString::valueOf(sal_Int32(sal_Int32( nBottom ) - sal_Int32( nTop ))))); + } + break; + case ESCHER_Prop_pVertices: + case ESCHER_Prop_pSegmentInfo: + { + EscherPropSortStruct aVertices; + EscherPropSortStruct aSegments; + + if ( rProps.GetOpt( ESCHER_Prop_pVertices, aVertices ) && + rProps.GetOpt( ESCHER_Prop_pSegmentInfo, aSegments ) ) + { + const sal_uInt8 *pVerticesIt = aVertices.pBuf + 6; + const sal_uInt8 *pSegmentIt = aSegments.pBuf; + + OStringBuffer aSegmentInfo( 512 ); + OStringBuffer aVerticies( 512 ); + + sal_uInt16 nPointSize = aVertices.pBuf[4] + ( aVertices.pBuf[5] << 8 ); + + // number of segments + sal_uInt16 nSegments = impl_GetUInt16( pSegmentIt ); + sal_Int32 nVertices = 0; + aSegmentInfo.append("2;").append((sal_Int32)nSegments); + pSegmentIt += 4; + + for ( ; nSegments; --nSegments ) + { + sal_uInt16 nSeg = impl_GetUInt16( pSegmentIt ); + aSegmentInfo.append(';').append((sal_Int32)nSeg); + switch ( nSeg ) + { + case 0x0001: // lineto + case 0x4000: // moveto + { + sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize ); + sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize ); + aVerticies.append( ";(" ).append( nX ).append( "," ).append( nY ).append( ")" ); + nVertices ++; + } + break; + case 0x2001: // curveto + { + for (int i = 0; i < 3; i++) + { + sal_Int32 nX = impl_GetPointComponent( pVerticesIt, nPointSize ); + sal_Int32 nY = impl_GetPointComponent( pVerticesIt, nPointSize ); + aVerticies.append( ";(" ).append( nX ).append( "," ).append( nY ).append( ")" ); + nVertices ++; + } + } + break; + case 0xb300: + case 0xac00: + case 0xaa00: // nofill + case 0xab00: // nostroke + case 0x6001: // close + case 0x8000: // end + break; + default: + OSL_TRACE("%s: unhandled segment '%x' in the path", OSL_THIS_FUNC, nSeg); + break; + } + } + + if (aVerticies.getLength() ) + { + // We know the number of vertices at the end only, so we have to prepend them here. + OStringBuffer aBuf; + aBuf.append("8;").append((sal_Int32)nVertices); + aBuf.append(aVerticies.makeStringAndClear()); + m_aShapeProps.insert(std::pair(OString("pVerticies"), aBuf.makeStringAndClear())); + } + if ( aSegmentInfo.getLength() ) + m_aShapeProps.insert(std::pair(OString("pSegmentInfo"), aSegmentInfo.makeStringAndClear())); + } + else + OSL_TRACE("%s: unhandled shape path, missing either pVertices or pSegmentInfo", OSL_THIS_FUNC); + } + break; + case ESCHER_Prop_shapePath: + // noop, we use pSegmentInfo instead + break; + case ESCHER_Prop_fFillOK: + if (!it->nPropValue) + m_aShapeProps.insert(std::pair(OString("fFillOK"), OString::valueOf(sal_Int32(0)))); + break; + case ESCHER_Prop_dxTextLeft: + m_aShapeProps.insert(std::pair(OString("dxTextLeft"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_dyTextTop: + m_aShapeProps.insert(std::pair(OString("dyTextTop"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_dxTextRight: + m_aShapeProps.insert(std::pair(OString("dxTextRight"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_dyTextBottom: + m_aShapeProps.insert(std::pair(OString("dyTextBottom"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_FitTextToShape: + // Size text to fit shape size: not supported by RTF + break; + case ESCHER_Prop_adjustValue: + m_aShapeProps.insert(std::pair(OString("adjustValue"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + case ESCHER_Prop_txflTextFlow: + m_aShapeProps.insert(std::pair(OString("txflTextFlow"), OString::valueOf(sal_Int32(it->nPropValue)))); + break; + default: + OSL_TRACE("%s: unhandled property: %d (value: %d)", OSL_THIS_FUNC, nId, it->nPropValue); + break; + } + } +} + +void RtfSdrExport::AddLineDimensions( const Rectangle& rRectangle ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + // We get the position relative to (the current?) character + m_aShapeProps.insert(std::pair(OString("posrelh"), OString::valueOf(sal_Int32(3)))); + + switch ( m_nShapeFlags & 0xC0 ) + { + case 0x40: + m_aShapeProps.insert(std::pair(OString("fFlipV"), OString::valueOf(sal_Int32(1)))); + break; + case 0x80: + m_aShapeProps.insert(std::pair(OString("fFlipH"), OString::valueOf(sal_Int32(1)))); + break; + case 0xC0: + m_aShapeProps.insert(std::pair(OString("fFlipV"), OString::valueOf(sal_Int32(1)))); + m_aShapeProps.insert(std::pair(OString("fFlipH"), OString::valueOf(sal_Int32(1)))); + break; + } + + // the actual dimensions + m_pShapeStyle->append(OOO_STRING_SVTOOLS_RTF_SHPLEFT).append(rRectangle.Left()); + m_pShapeStyle->append(OOO_STRING_SVTOOLS_RTF_SHPTOP).append(rRectangle.Top()); + m_pShapeStyle->append(OOO_STRING_SVTOOLS_RTF_SHPRIGHT).append(rRectangle.Right()); + m_pShapeStyle->append(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM).append(rRectangle.Bottom()); +} + +void RtfSdrExport::AddRectangleDimensions( rtl::OStringBuffer& rBuffer, const Rectangle& rRectangle ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + // We get the position relative to (the current?) character + m_aShapeProps.insert(std::pair(OString("posrelh"), OString::valueOf(sal_Int32(3)))); + + rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPLEFT).append(rRectangle.Left()); + rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPTOP).append(rRectangle.Top()); + rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPRIGHT).append(rRectangle.Right()); + rBuffer.append(OOO_STRING_SVTOOLS_RTF_SHPBOTTOM).append(rRectangle.Bottom()); +} + +void RtfSdrExport::AddShapeAttribute( sal_Int32 /*nAttribute*/, const rtl::OString& /*rValue*/ ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + /* noop */ +} + +extern const char* pShapeTypes[]; + +sal_Int32 RtfSdrExport::StartShape() +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( m_nShapeType == ESCHER_ShpInst_Nil ) + return -1; + + m_aShapeProps.insert(std::pair(OString("shapeType"), OString::valueOf(sal_Int32(m_nShapeType)))); + + m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_SHP); + m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_IGNORE).append(OOO_STRING_SVTOOLS_RTF_SHPINST); + + m_rAttrOutput.RunText().append(m_pShapeStyle->makeStringAndClear()); + // Ignore \shpbxpage, \shpbxmargin, and \shpbxcolumn, in favor of the posrelh property. + m_rAttrOutput.RunText().append(OOO_STRING_SVTOOLS_RTF_SHPBXIGNORE); + // Ignore \shpbypage, \shpbymargin, and \shpbycolumn, in favor of the posrelh property. + m_rAttrOutput.RunText().append(OOO_STRING_SVTOOLS_RTF_SHPBYIGNORE); + + for(std::map::reverse_iterator i = m_aShapeProps.rbegin(); i != m_aShapeProps.rend(); i++) + m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_SP) + .append('{').append(OOO_STRING_SVTOOLS_RTF_SN " ").append((*i).first).append('}') + .append('{').append(OOO_STRING_SVTOOLS_RTF_SV " ").append((*i).second).append('}') + .append('}'); + + // now check if we have some text + const SdrTextObj* pTxtObj = PTR_CAST(SdrTextObj, m_pSdrObject); + if (pTxtObj) + { + const OutlinerParaObject* pParaObj = 0; + bool bOwnParaObj = false; + + /* + #i13885# + When the object is actively being edited, that text is not set into + the objects normal text object, but lives in a seperate object. + */ + if (pTxtObj->IsTextEditActive()) + { + pParaObj = pTxtObj->GetEditOutlinerParaObject(); + bOwnParaObj = true; + } + else + { + pParaObj = pTxtObj->GetOutlinerParaObject(); + } + + if( pParaObj ) + { + // this is reached only in case some text is attached to the shape + WriteOutliner(*pParaObj); + if( bOwnParaObj ) + delete pParaObj; + } + } + + return m_nShapeType; +} + +void RtfSdrExport::WriteOutliner(const OutlinerParaObject& rParaObj) +{ + OSL_TRACE("%s start", OSL_THIS_FUNC); + + const EditTextObject& rEditObj = rParaObj.GetTextObject(); + MSWord_SdrAttrIter aAttrIter( m_rExport, rEditObj, TXT_HFTXTBOX ); + + USHORT nPara = rEditObj.GetParagraphCount(); + + m_rAttrOutput.RunText().append('{').append(OOO_STRING_SVTOOLS_RTF_SHPTXT).append(' '); + for (USHORT n = 0; n < nPara; ++n) + { + if( n ) + aAttrIter.NextPara( n ); + + rtl_TextEncoding eChrSet = aAttrIter.GetNodeCharSet(); + + String aStr( rEditObj.GetText( n )); + xub_StrLen nAktPos = 0; + xub_StrLen nEnd = aStr.Len(); + + aAttrIter.OutParaAttr(false); + m_rAttrOutput.RunText().append(m_rAttrOutput.Styles().makeStringAndClear()); + + do { + xub_StrLen nNextAttr = aAttrIter.WhereNext(); + rtl_TextEncoding eNextChrSet = aAttrIter.GetNextCharSet(); + + if( nNextAttr > nEnd ) + nNextAttr = nEnd; + + aAttrIter.OutAttr( nAktPos ); + m_rAttrOutput.RunText().append('{').append(m_rAttrOutput.Styles().makeStringAndClear()).append(m_rExport.sNewLine); + bool bTxtAtr = aAttrIter.IsTxtAttr( nAktPos ); + if( !bTxtAtr ) + { + String aOut( aStr.Copy( nAktPos, nNextAttr - nAktPos ) ); + m_rAttrOutput.RunText().append( m_rExport.OutString( aOut, eChrSet ) ); + } + + m_rAttrOutput.RunText().append('}'); + + nAktPos = nNextAttr; + eChrSet = eNextChrSet; + aAttrIter.NextPos(); + } + while( nAktPos < nEnd ); + } + m_rAttrOutput.RunText().append(OOO_STRING_SVTOOLS_RTF_PAR).append('}'); + + OSL_TRACE("%s end", OSL_THIS_FUNC); +} + +void RtfSdrExport::EndShape( sal_Int32 nShapeElement ) +{ + OSL_TRACE("%s", OSL_THIS_FUNC); + + if ( nShapeElement >= 0 ) + { + // end of the shape + m_rAttrOutput.RunText().append('}').append('}'); + } +} + +UINT32 RtfSdrExport::AddSdrObject( const SdrObject& rObj ) +{ + m_pSdrObject = &rObj; + return EscherEx::AddSdrObject(rObj); +} + +/* vi:set shiftwidth=4 expandtab: */ diff --git a/sw/source/filter/ww8/rtfsdrexport.hxx b/sw/source/filter/ww8/rtfsdrexport.hxx new file mode 100644 index 0000000000..46d5e58baf --- /dev/null +++ b/sw/source/filter/ww8/rtfsdrexport.hxx @@ -0,0 +1,111 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2010 Miklos Vajna. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _RTFSdrEXPORT_HXX_ +#define _RTFSdrEXPORT_HXX_ + +#include +#include +#include + +#include + +class RtfExport; +class RtfAttributeOutput; + +class RtfSdrExport : public EscherEx +{ + RtfExport &m_rExport; + + RtfAttributeOutput &m_rAttrOutput; + + const SdrObject* m_pSdrObject; + + /// Remember the shape type. + sal_uInt32 m_nShapeType; + + /// Remember the shape flags. + sal_uInt32 m_nShapeFlags; + + /// Remember style, the most important shape attribute ;-) + rtl::OStringBuffer *m_pShapeStyle; + + std::map m_aShapeProps; + + /// Remember which shape types we had already written. + bool *m_pShapeTypeWritten; + +public: + RtfSdrExport( RtfExport &rExport ); + virtual ~RtfSdrExport(); + + /// Export the sdr object as Sdr. + /// + /// Call this when you need to export the object as Sdr in RTF. + UINT32 AddSdrObject( const SdrObject& rObj ); + +protected: + /// Add an attribute to the generated shape element. + /// + /// This should be called from within StartShape() to ensure that the + /// added attribute is preserved. + void AddShapeAttribute( sal_Int32 nAttribute, const rtl::OString& sValue ); + + /// Start the shape for which we just collected the information. + /// + /// Returns the element's tag number, -1 means we wrote nothing. + virtual sal_Int32 StartShape(); + + /// End the shape. + /// + /// The parameter is just what we got from StartShape(). + virtual void EndShape( sal_Int32 nShapeElement ); + + virtual void Commit( EscherPropertyContainer& rProps, const Rectangle& rRect ); + +private: + + virtual void OpenContainer( UINT16 nEscherContainer, int nRecInstance = 0 ); + virtual void CloseContainer(); + + virtual UINT32 EnterGroup( const String& rShapeName, const Rectangle* pBoundRect = 0 ); + virtual void LeaveGroup(); + + virtual void AddShape( UINT32 nShapeType, UINT32 nShapeFlags, UINT32 nShapeId = 0 ); + +private: + /// Add starting and ending point of a line to the m_pShapeAttrList. + void AddLineDimensions( const Rectangle& rRectangle ); + + /// Add position and size to the OStringBuffer. + void AddRectangleDimensions( rtl::OStringBuffer& rBuffer, const Rectangle& rRectangle ); + + void WriteOutliner(const OutlinerParaObject& rParaObj); +}; + +#endif // _RTFSdrEXPORT_HXX_ +/* vi:set shiftwidth=4 expandtab: */ diff --git a/sw/source/filter/ww8/wrtw8esh.cxx b/sw/source/filter/ww8/wrtw8esh.cxx index 72dbabefd9..71889e25bf 100644 --- a/sw/source/filter/ww8/wrtw8esh.cxx +++ b/sw/source/filter/ww8/wrtw8esh.cxx @@ -811,49 +811,7 @@ void WW8Export::AppendFlyInFlys(const sw::Frame& rFrmFmt, OutputField(0, ww::eSHAPE, aEmptyStr, WRITEFIELD_CLOSE); } -class WW8_SdrAttrIter : public MSWordAttrIter -{ -private: - const EditTextObject* pEditObj; - const SfxItemPool* pEditPool; - EECharAttribArray aTxtAtrArr; - SvPtrarr aChrTxtAtrArr; - SvUShorts aChrSetArr; - USHORT nPara; - xub_StrLen nAktSwPos; - xub_StrLen nTmpSwPos; // fuer HasItem() - rtl_TextEncoding eNdChrSet; - USHORT nScript; - BYTE mnTyp; - - xub_StrLen SearchNext( xub_StrLen nStartPos ); - void SetCharSet(const EECharAttrib& rTxtAttr, bool bStart); - - //No copying - WW8_SdrAttrIter(const WW8_SdrAttrIter&); - WW8_SdrAttrIter& operator=(const WW8_SdrAttrIter&); -public: - WW8_SdrAttrIter( WW8Export& rWr, const EditTextObject& rEditObj, - BYTE nType ); - void NextPara( USHORT nPar ); - void OutParaAttr(bool bCharAttr); - void OutEEField(const SfxPoolItem& rHt); - - bool IsTxtAttr(xub_StrLen nSwPos); - - void NextPos() { nAktSwPos = SearchNext( nAktSwPos + 1 ); } - - void OutAttr( xub_StrLen nSwPos ); - virtual const SfxPoolItem* HasTextItem( USHORT nWhich ) const; - virtual const SfxPoolItem& GetItem( USHORT nWhich ) const; - bool OutAttrWithRange(xub_StrLen nPos); - xub_StrLen WhereNext() const { return nAktSwPos; } - rtl_TextEncoding GetNextCharSet() const; - rtl_TextEncoding GetNodeCharSet() const { return eNdChrSet; } -}; - - -WW8_SdrAttrIter::WW8_SdrAttrIter( WW8Export& rWr, +MSWord_SdrAttrIter::MSWord_SdrAttrIter( MSWordExportBase& rWr, const EditTextObject& rEditObj, BYTE nTyp ) : MSWordAttrIter( rWr ), pEditObj(&rEditObj), pEditPool(0), aTxtAtrArr( 0, 4 ), aChrTxtAtrArr( 0, 4 ), aChrSetArr( 0, 4 ), @@ -862,7 +820,7 @@ WW8_SdrAttrIter::WW8_SdrAttrIter( WW8Export& rWr, NextPara( 0 ); } -void WW8_SdrAttrIter::NextPara( USHORT nPar ) +void MSWord_SdrAttrIter::NextPara( USHORT nPar ) { nPara = nPar; // Attributwechsel an Pos 0 wird ignoriert, da davon ausgegangen @@ -885,7 +843,7 @@ void WW8_SdrAttrIter::NextPara( USHORT nPar ) nAktSwPos = SearchNext( 1 ); } -rtl_TextEncoding WW8_SdrAttrIter::GetNextCharSet() const +rtl_TextEncoding MSWord_SdrAttrIter::GetNextCharSet() const { if( aChrSetArr.Count() ) return (rtl_TextEncoding)aChrSetArr[ aChrSetArr.Count() - 1 ]; @@ -893,7 +851,7 @@ rtl_TextEncoding WW8_SdrAttrIter::GetNextCharSet() const } // der erste Parameter in SearchNext() liefert zurueck, ob es ein TxtAtr ist. -xub_StrLen WW8_SdrAttrIter::SearchNext( xub_StrLen nStartPos ) +xub_StrLen MSWord_SdrAttrIter::SearchNext( xub_StrLen nStartPos ) { xub_StrLen nPos; xub_StrLen nMinPos = STRING_MAXLEN; @@ -932,7 +890,7 @@ xub_StrLen WW8_SdrAttrIter::SearchNext( xub_StrLen nStartPos ) return nMinPos; } -void WW8_SdrAttrIter::SetCharSet(const EECharAttrib& rAttr, bool bStart) +void MSWord_SdrAttrIter::SetCharSet(const EECharAttrib& rAttr, bool bStart) { void* p = 0; rtl_TextEncoding eChrSet; @@ -962,7 +920,7 @@ void WW8_SdrAttrIter::SetCharSet(const EECharAttrib& rAttr, bool bStart) } } -void WW8_SdrAttrIter::OutEEField(const SfxPoolItem& rHt) +void MSWord_SdrAttrIter::OutEEField(const SfxPoolItem& rHt) { const SvxFieldItem &rField = (const SvxFieldItem &)rHt; const SvxFieldData *pFld = rField.GetField(); @@ -981,7 +939,7 @@ void WW8_SdrAttrIter::OutEEField(const SfxPoolItem& rHt) } } -void WW8_SdrAttrIter::OutAttr( xub_StrLen nSwPos ) +void MSWord_SdrAttrIter::OutAttr( xub_StrLen nSwPos ) { OutParaAttr(true); @@ -1038,7 +996,7 @@ void WW8_SdrAttrIter::OutAttr( xub_StrLen nSwPos ) } } -bool WW8_SdrAttrIter::IsTxtAttr(xub_StrLen nSwPos) +bool MSWord_SdrAttrIter::IsTxtAttr(xub_StrLen nSwPos) { for (USHORT i = 0; i < aTxtAtrArr.Count(); ++i) { @@ -1063,7 +1021,7 @@ bool WW8_SdrAttrIter::IsTxtAttr(xub_StrLen nSwPos) // Attribut-Anfangposition fragen kann. // Es koennen nur Attribute mit Ende abgefragt werden. // Es wird mit bDeep gesucht -const SfxPoolItem* WW8_SdrAttrIter::HasTextItem(USHORT nWhich) const +const SfxPoolItem* MSWord_SdrAttrIter::HasTextItem(USHORT nWhich) const { const SfxPoolItem* pRet = 0; nWhich = sw::hack::TransformWhichBetweenPools(*pEditPool, @@ -1088,7 +1046,7 @@ const SfxPoolItem* WW8_SdrAttrIter::HasTextItem(USHORT nWhich) const return pRet; } -const SfxPoolItem& WW8_SdrAttrIter::GetItem( USHORT nWhich ) const +const SfxPoolItem& MSWord_SdrAttrIter::GetItem( USHORT nWhich ) const { using sw::hack::GetSetWhichFromSwDocWhich; const SfxPoolItem* pRet = HasTextItem(nWhich); @@ -1102,7 +1060,7 @@ const SfxPoolItem& WW8_SdrAttrIter::GetItem( USHORT nWhich ) const return *pRet; } -void WW8_SdrAttrIter::OutParaAttr(bool bCharAttr) +void MSWord_SdrAttrIter::OutParaAttr(bool bCharAttr) { SfxItemSet aSet( pEditObj->GetParaAttribs( nPara )); if( aSet.Count() ) @@ -1175,7 +1133,7 @@ void WW8Export::WriteOutliner(const OutlinerParaObject& rParaObj, BYTE nTyp) { bool bAnyWrite = false; const EditTextObject& rEditObj = rParaObj.GetTextObject(); - WW8_SdrAttrIter aAttrIter( *this, rEditObj, nTyp ); + MSWord_SdrAttrIter aAttrIter( *this, rEditObj, nTyp ); USHORT nPara = rEditObj.GetParagraphCount(); BYTE bNul = 0; diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index 81a2bacbd8..5d8f5e27c8 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -1,7 +1,7 @@ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * + * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite @@ -337,7 +337,7 @@ xub_StrLen SwAttrIter::SearchNext( xub_StrLen nStartPos ) xub_StrLen pos = lcl_getMinPos( fieldEndPos, fieldStartPos ); pos = lcl_getMinPos( pos, formElementPos ); - if (pos!=STRING_NOTFOUND) + if (pos!=STRING_NOTFOUND) nMinPos=pos; // first the redline, then the attributes @@ -894,7 +894,7 @@ bool WW8AttributeOutput::AnalyzeURL( const String& rUrl, const String& rTarget, if ( sMark.Len() ) ( ( sURL.APPEND_CONST_ASC( " \\l \"" ) ) += sMark ) += '\"'; - + if ( rTarget.Len() ) ( sURL.APPEND_CONST_ASC( " \\n " ) ) += rTarget; @@ -1344,10 +1344,10 @@ short MSWordExportBase::GetDefaultFrameDirection( ) const else if ( pOutFmtNode->ISA( SwTxtFmtColl ) ) nDir = FRMDIR_HORI_LEFT_TOP; //what else can we do :-( } - + if ( nDir == FRMDIR_ENVIRONMENT ) nDir = FRMDIR_HORI_LEFT_TOP; //Set something - + return nDir; } @@ -1597,12 +1597,12 @@ void WW8AttributeOutput::FormatDrop( const SwTxtNode& rNode, const SwFmtDrop &rS m_rWW8Export.WriteCR( pTextNodeInfoInner ); if ( pTextNodeInfo.get() != NULL ) - { -#ifdef DEBUG + { +#ifdef DEBUG ::std::clog << pTextNodeInfo->toString() << ::std::endl; #endif - TableInfoCell( pTextNodeInfoInner ); + TableInfoCell( pTextNodeInfoInner ); } m_rWW8Export.pPapPlc->AppendFkpEntry( m_rWW8Export.Strm().Tell(), m_rWW8Export.pO->Count(), m_rWW8Export.pO->GetData() ); @@ -1646,14 +1646,127 @@ void WW8AttributeOutput::FormatDrop( const SwTxtNode& rNode, const SwFmtDrop &rS m_rWW8Export.pO->Remove( 0, m_rWW8Export.pO->Count() ); } -xub_StrLen MSWordExportBase::GetNextPos( SwAttrIter* aAttrIter, const SwTxtNode& /*rNode*/, xub_StrLen /*nAktPos*/ ) +xub_StrLen MSWordExportBase::GetNextPos( SwAttrIter* aAttrIter, const SwTxtNode& rNode, xub_StrLen nAktPos ) +{ + // Get the bookmarks for the normal run + xub_StrLen nNextPos = aAttrIter->WhereNext(); + + GetSortedBookmarks( rNode, nAktPos, nNextPos - nAktPos ); + + xub_StrLen nNextBookmark = nNextPos; + NearestBookmark( nNextPos ); + + return std::min( nNextPos, nNextBookmark ); +} + +void MSWordExportBase::UpdatePosition( SwAttrIter* aAttrIter, xub_StrLen nAktPos, xub_StrLen /*nEnd*/ ) +{ + xub_StrLen nNextPos; + + // either no bookmark, or it is not at the current position + if ( !NearestBookmark( nNextPos ) || nNextPos > nAktPos ) + aAttrIter->NextPos(); +} + +bool MSWordExportBase::GetBookmarks( const SwTxtNode& rNd, xub_StrLen nStt, + xub_StrLen nEnd, IMarkVector& rArr ) +{ + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + ULONG nNd = rNd.GetIndex( ); + + const sal_Int32 nMarks = pMarkAccess->getMarksCount(); + for ( sal_Int32 i = 0; i < nMarks; i++ ) + { + IMark* pMark = ( pMarkAccess->getMarksBegin() + i )->get(); + + // Only keep the bookmarks starting or ending in this node + if ( pMark->GetMarkStart().nNode == nNd || + pMark->GetMarkEnd().nNode == nNd ) + { + xub_StrLen nBStart = pMark->GetMarkStart().nContent.GetIndex(); + xub_StrLen nBEnd = pMark->GetMarkEnd().nContent.GetIndex(); + + // Keep only the bookmars starting or ending in the snippet + bool bIsStartOk = ( nBStart >= nStt ) && ( nBStart <= nEnd ); + bool bIsEndOk = ( nBEnd >= nStt ) && ( nBEnd <= nEnd ); + + if ( bIsStartOk || bIsEndOk ) + rArr.push_back( pMark ); + } + } + return ( rArr.size() > 0 ); +} + +class CompareMarksEnd : public std::binary_function < const IMark *, const IMark *, bool > +{ +public: + inline bool operator() ( const IMark * pOneB, const IMark * pTwoB ) const + { + xub_StrLen nOEnd = pOneB->GetMarkEnd().nContent.GetIndex(); + xub_StrLen nTEnd = pTwoB->GetMarkEnd().nContent.GetIndex(); + + return nOEnd < nTEnd; + } +}; + +bool MSWordExportBase::NearestBookmark( xub_StrLen& rNearest ) { - return aAttrIter->WhereNext(); + bool bHasBookmark = false; + + if ( m_rSortedMarksStart.size( ) > 0 ) + { + IMark* pMarkStart = m_rSortedMarksStart.front(); + rNearest = pMarkStart->GetMarkStart().nContent.GetIndex(); + bHasBookmark = true; + } + + if ( m_rSortedMarksEnd.size( ) > 0 ) + { + IMark* pMarkEnd = m_rSortedMarksEnd[0]; + if ( !bHasBookmark ) + rNearest = pMarkEnd->GetMarkEnd().nContent.GetIndex(); + else + rNearest = std::min( rNearest, pMarkEnd->GetMarkEnd().nContent.GetIndex() ); + bHasBookmark = true; + } + + return bHasBookmark; } -void MSWordExportBase::UpdatePosition( SwAttrIter* aAttrIter, xub_StrLen /*nAktPos*/, xub_StrLen /*nEnd*/ ) +void MSWordExportBase::GetSortedBookmarks( const SwTxtNode& rNode, xub_StrLen nAktPos, xub_StrLen nLen ) { - aAttrIter->NextPos(); + IMarkVector aMarksStart; + if ( GetBookmarks( rNode, nAktPos, nAktPos + nLen, aMarksStart ) ) + { + IMarkVector aSortedEnd; + IMarkVector aSortedStart; + for ( IMarkVector::const_iterator it = aMarksStart.begin(), end = aMarksStart.end(); + it < end; ++it ) + { + IMark* pMark = (*it); + + // Remove the positions egals to the current pos + xub_StrLen nStart = pMark->GetMarkStart().nContent.GetIndex(); + xub_StrLen nEnd = pMark->GetMarkEnd().nContent.GetIndex(); + + if ( nStart > nAktPos ) + aSortedStart.push_back( pMark ); + + if ( nEnd > nAktPos ) + aSortedEnd.push_back( pMark ); + } + + // Sort the bookmarks by end position + std::sort( aSortedEnd.begin(), aSortedEnd.end(), CompareMarksEnd() ); + + m_rSortedMarksStart.swap( aSortedStart ); + m_rSortedMarksEnd.swap( aSortedEnd ); + } + else + { + m_rSortedMarksStart.clear( ); + m_rSortedMarksEnd.clear( ); + } } void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) @@ -1834,7 +1947,7 @@ void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) } } } - + // Output the character attributes AttrOutput().StartRunProperties(); aAttrIter.OutAttr( nAktPos ); // nAktPos - 1 ?? @@ -1887,7 +2000,7 @@ void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) while ( nAktPos < nEnd ); AttrOutput().StartParagraphProperties( rNode ); - + AttrOutput().ParagraphStyle( nStyle ); if ( mpParentFrame && !bIsInTable ) // Fly-Attrs @@ -1903,7 +2016,7 @@ void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) if (pTextNodeInfoInner->isFirstInTable()) { const SwTable * pTable = pTextNodeInfoInner->getTable(); - const SwTableFmt * pTabFmt = + const SwTableFmt * pTabFmt = dynamic_cast(pTable->GetRegisteredIn()); if (pTabFmt != NULL) { @@ -1911,8 +2024,8 @@ void MSWordExportBase::OutputTextNode( const SwTxtNode& rNode ) AttrOutput().PageBreakBefore(true); } } - } - + } + if ( !bFlyInTable ) { SfxItemSet* pTmpSet = 0; diff --git a/sw/source/filter/ww8/wrtw8num.cxx b/sw/source/filter/ww8/wrtw8num.cxx index 2ed01f48a8..da139872e5 100644 --- a/sw/source/filter/ww8/wrtw8num.cxx +++ b/sw/source/filter/ww8/wrtw8num.cxx @@ -721,6 +721,9 @@ void MSWordExportBase::SubstituteBullet( String& rNumStr, StarSymbolToMSMultiFont *pConvert = 0; FontFamily eFamily = FAMILY_DECORATIVE; + if (!bSubstituteBullets) + return; + if (!pConvert) { pConvert = CreateStarSymbolToMSMultiFont(); diff --git a/sw/source/filter/ww8/wrtw8sty.cxx b/sw/source/filter/ww8/wrtw8sty.cxx index 42b829a999..2a6a204118 100644 --- a/sw/source/filter/ww8/wrtw8sty.cxx +++ b/sw/source/filter/ww8/wrtw8sty.cxx @@ -79,6 +79,7 @@ #include "ww8par.hxx" #include "ww8attributeoutput.hxx" #include "docxattributeoutput.hxx" +#include "rtfattributeoutput.hxx" using namespace sw::util; using namespace nsHdFtFlags; @@ -711,6 +712,17 @@ void wwFont::WriteDocx( const DocxAttributeOutput* rAttrOutput ) const rAttrOutput->EndFont(); } +void wwFont::WriteRtf( const RtfAttributeOutput* rAttrOutput ) const +{ + rAttrOutput->FontFamilyType( meFamily, *this ); + rAttrOutput->FontPitchType( mePitch ); + rAttrOutput->FontCharset( sw::ms::rtl_TextEncodingToWinCharset( meChrSet ) ); + rAttrOutput->StartFont( msFamilyNm ); + if ( mbAlt ) + rAttrOutput->FontAlternateName( msAltNm ); + rAttrOutput->EndFont(); +} + bool operator<(const wwFont &r1, const wwFont &r2) { int nRet = memcmp(r1.maWW8_FFN, r2.maWW8_FFN, sizeof(r1.maWW8_FFN)); @@ -763,6 +775,22 @@ void wwFontHelper::InitFontTable(bool bWrtWW8,const SwDoc& rDoc) GetId(wwFont(pFont->GetFamilyName(), pFont->GetPitch(), pFont->GetFamily(), pFont->GetCharSet(),bWrtWW8)); } + + if (!bLoadAllFonts) + return; + + const USHORT aTypes[] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT, RES_CHRATR_CTL_FONT, 0 }; + for (const USHORT* pId = aTypes; *pId; ++pId) + { + USHORT nMaxItem = rPool.GetItemCount( *pId ); + for( USHORT nGet = 0; nGet < nMaxItem; ++nGet ) + if( 0 != (pFont = (const SvxFontItem*)rPool.GetItem( + *pId, nGet )) ) + { + GetId(wwFont(pFont->GetFamilyName(), pFont->GetPitch(), + pFont->GetFamily(), pFont->GetCharSet(),bWrtWW8)); + } + } } USHORT wwFontHelper::GetId(const Font& rFont) @@ -835,6 +863,14 @@ void wwFontHelper::WriteFontTable( const DocxAttributeOutput& rAttrOutput ) ::std::bind2nd( ::std::mem_fun( &wwFont::WriteDocx ), &rAttrOutput ) ); } +void wwFontHelper::WriteFontTable( const RtfAttributeOutput& rAttrOutput ) +{ + ::std::vector aFontList( AsVector() ); + + ::std::for_each( aFontList.begin(), aFontList.end(), + ::std::bind2nd( ::std::mem_fun( &wwFont::WriteRtf ), &rAttrOutput ) ); +} + /* */ WW8_WrPlc0::WW8_WrPlc0( ULONG nOffset ) diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx index 2cf3a421e2..43016e4641 100755 --- a/sw/source/filter/ww8/wrtww8.cxx +++ b/sw/source/filter/ww8/wrtww8.cxx @@ -3371,7 +3371,7 @@ MSWordExportBase::MSWordExportBase( SwDoc *pDocument, SwPaM *pCurrentPam, SwPaM mpTableInfo(new ww8::WW8TableInfo()), nUniqueList(0), mnHdFtIndex(0), pAktPageDesc(0), pPapPlc(0), pChpPlc(0), pChpIter(0), pStyles( NULL ), - bHasHdr(false), bHasFtr(false), + bHasHdr(false), bHasFtr(false), bSubstituteBullets(true), pDoc( pDocument ), pCurPam( pCurrentPam ), pOrigPam( pOriginalPam ) diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx index d73ebae2f2..3a005a91b5 100644 --- a/sw/source/filter/ww8/wrtww8.hxx +++ b/sw/source/filter/ww8/wrtww8.hxx @@ -1,7 +1,7 @@ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * + * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite @@ -35,6 +35,7 @@ #define _SVSTDARR_ULONGS #include #endif +#include #include #include @@ -55,6 +56,7 @@ class SwAttrIter; class AttributeOutputBase; class DocxAttributeOutput; +class RtfAttributeOutput; class BitmapPalette; class SwEscherEx; class DateTime; @@ -254,7 +256,7 @@ private: void WriteFtnEndTxt( WW8Export& rWrt, ULONG nCpStt ); public: void OutHeaderFooter(WW8Export& rWrt, bool bHeader, - const SwFmt& rFmt, ULONG& rCpPos, BYTE nHFFlags, BYTE nFlag, BYTE nBreakCode); + const SwFmt& rFmt, ULONG& rCpPos, BYTE nHFFlags, BYTE nFlag, BYTE nBreakCode); }; //-------------------------------------------------------------------------- @@ -294,6 +296,7 @@ public: rtl_TextEncoding eChrSet, bool bWrtWW8 ); bool Write( SvStream *pTableStram ) const; void WriteDocx( const DocxAttributeOutput* rAttrOutput ) const; + void WriteRtf( const RtfAttributeOutput* rAttrOutput ) const; rtl::OUString GetFamilyName() const { return rtl::OUString( msFamilyNm ); } friend bool operator < (const wwFont &r1, const wwFont &r2); }; @@ -309,7 +312,7 @@ private: ::std::vector< const wwFont* > AsVector() const; public: - wwFontHelper() : mbWrtWW8(false) {} + wwFontHelper() : mbWrtWW8(false), bLoadAllFonts(false) {} /// rDoc used only to get the initial standard font(s) in use. void InitFontTable(bool bWrtWW8, const SwDoc& rDoc); USHORT GetId(const Font& rFont); @@ -317,6 +320,10 @@ public: USHORT GetId(const wwFont& rFont); void WriteFontTable( SvStream *pTableStream, WW8Fib& pFib ); void WriteFontTable( const DocxAttributeOutput& rAttrOutput ); + void WriteFontTable( const RtfAttributeOutput& rAttrOutput ); + + /// If true, all fonts are loaded before processing the document. + BYTE bLoadAllFonts: 1; }; class DrawObj @@ -535,6 +542,7 @@ public: BYTE bEndAtTxtEnd : 1; // true: all END at Textend BYTE bHasHdr : 1; BYTE bHasFtr : 1; + BYTE bSubstituteBullets : 1; // true: SubstituteBullet() gets called SwDoc *pDoc; SwPaM *pCurPam, *pOrigPam; @@ -542,6 +550,11 @@ public: /// Stack to remember the nesting (see MSWordSaveData for more) ::std::stack< MSWordSaveData > maSaveData; + /// Used to split the runs according to the bookmarks start and ends + typedef std::vector< ::sw::mark::IMark* > IMarkVector; + IMarkVector m_rSortedMarksStart; + IMarkVector m_rSortedMarksEnd; + public: /// The main function to export the document. void ExportDocument( bool bWriteAll ); @@ -565,9 +578,9 @@ public: /// Return the numeric id of the style. USHORT GetId( const SwCharFmt& rFmt ) const; - + USHORT GetId( const SwTOXType& rTOXType ); - + const SfxPoolItem& GetItem( USHORT nWhich ) const; /// Find the reference. @@ -648,7 +661,7 @@ public: /// The return value indicates, if a follow page desc is written. bool OutputFollowPageDesc( const SfxItemSet* pSet, const SwTxtNode* pNd ); - + /// Write header/footer text. void WriteHeaderFooterText( const SwFmt& rFmt, bool bHeader); @@ -671,7 +684,7 @@ public: /// Write static data of SwNumRule - LSTF void NumberingDefinitions(); - + /// Write all Levels for all SwNumRules - LVLF void AbstractNumberingDefinitions(); @@ -703,7 +716,7 @@ public: /// Write the data of the form field virtual void WriteFormData( const ::sw::mark::IFieldmark& rFieldmark ) = 0; virtual void WriteHyperlinkData( const ::sw::mark::IFieldmark& rFieldmark ) = 0; - + virtual void DoComboBox(const rtl::OUString &rName, const rtl::OUString &rHelp, const rtl::OUString &ToolTip, @@ -749,7 +762,7 @@ protected: bool FmtHdFtContainsChapterField(const SwFrmFmt &rFmt) const; virtual void SectionBreaksAndFrames( const SwTxtNode& rNode ) = 0; - + virtual void PrepareNewPageDesc( const SfxItemSet* pSet, const SwNode& rNd, const SwFmtPageDesc* pNewPgDescFmt = 0, @@ -780,7 +793,18 @@ protected: /// /// One of OutputTextNode(), OutputGrfNode(), or OutputOLENode() void OutputContentNode( const SwCntntNode& ); - + + /// Find the nearest bookmark from the current position. + /// + /// Returns false when there is no bookmark. + bool NearestBookmark( xub_StrLen& rNearest ); + + void GetSortedBookmarks( const SwTxtNode& rNd, xub_StrLen nAktPos, + xub_StrLen nLen ); + + bool GetBookmarks( const SwTxtNode& rNd, xub_StrLen nStt, xub_StrLen nEnd, + IMarkVector& rArr ); + public: MSWordExportBase( SwDoc *pDocument, SwPaM *pCurrentPam, SwPaM *pOriginalPam ); virtual ~MSWordExportBase(); @@ -984,7 +1008,7 @@ public: void WriteAsStringTable(const ::std::vector&, INT32& rfcSttbf, INT32& rlcbSttbf, USHORT nExtraLen = 0); - + virtual ULONG ReplaceCr( BYTE nChar ); virtual void WriteCR( ww8::WW8TableNodeInfoInner::Pointer_t pTableTextNodeInfoInner = ww8::WW8TableNodeInfoInner::Pointer_t() ); @@ -1098,7 +1122,7 @@ protected: /// Output SwOLENode virtual void OutputOLENode( const SwOLENode& ); - + virtual void AppendSection( const SwPageDesc *pPageDesc, const SwSectionFmt* pFmt, ULONG nLnNum ); private: @@ -1346,6 +1370,47 @@ public: virtual const SfxPoolItem& GetItem( USHORT nWhich ) const = 0; }; +class MSWord_SdrAttrIter : public MSWordAttrIter +{ +private: + const EditTextObject* pEditObj; + const SfxItemPool* pEditPool; + EECharAttribArray aTxtAtrArr; + SvPtrarr aChrTxtAtrArr; + SvUShorts aChrSetArr; + USHORT nPara; + xub_StrLen nAktSwPos; + xub_StrLen nTmpSwPos; // for HasItem() + rtl_TextEncoding eNdChrSet; + USHORT nScript; + BYTE mnTyp; + + xub_StrLen SearchNext( xub_StrLen nStartPos ); + void SetCharSet(const EECharAttrib& rTxtAttr, bool bStart); + + //No copying + MSWord_SdrAttrIter(const MSWord_SdrAttrIter&); + MSWord_SdrAttrIter& operator=(const MSWord_SdrAttrIter&); +public: + MSWord_SdrAttrIter( MSWordExportBase& rWr, const EditTextObject& rEditObj, + BYTE nType ); + void NextPara( USHORT nPar ); + void OutParaAttr(bool bCharAttr); + void OutEEField(const SfxPoolItem& rHt); + + bool IsTxtAttr(xub_StrLen nSwPos); + + void NextPos() { nAktSwPos = SearchNext( nAktSwPos + 1 ); } + + void OutAttr( xub_StrLen nSwPos ); + virtual const SfxPoolItem* HasTextItem( USHORT nWhich ) const; + virtual const SfxPoolItem& GetItem( USHORT nWhich ) const; + bool OutAttrWithRange(xub_StrLen nPos); + xub_StrLen WhereNext() const { return nAktSwPos; } + rtl_TextEncoding GetNextCharSet() const; + rtl_TextEncoding GetNodeCharSet() const { return eNdChrSet; } +}; + /// Class to collect and output the styles table. class MSWordStyles { @@ -1399,11 +1464,11 @@ class WW8SHDLong sal_uInt32 m_cvFore; sal_uInt32 m_cvBack; sal_uInt16 m_ipat; - + public: WW8SHDLong() : m_cvFore(0), m_cvBack(0), m_ipat(0) {} virtual ~WW8SHDLong() {} - + void Write(WW8Export & rExport); void setCvFore(sal_uInt32 cvFore) { m_cvFore = cvFore; } void setCvBack(sal_uInt32 cvBack) { m_cvBack = cvBack; } diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx index 1e5d01101f..cde7c02ce4 100644 --- a/sw/source/filter/ww8/ww8atr.cxx +++ b/sw/source/filter/ww8/ww8atr.cxx @@ -3340,7 +3340,7 @@ void WW8AttributeOutput::CharTwoLines( const SvxTwoLinesItem& rTwoLines ) m_rWW8Export.pO->Insert( (BYTE)0x02, m_rWW8Export.pO->Count() ); sal_Unicode cStart = rTwoLines.GetStartBracket(); - sal_Unicode cEnd = rTwoLines.GetStartBracket(); + sal_Unicode cEnd = rTwoLines.GetEndBracket(); /* As per usual we have problems. We can have seperate left and right brackets diff --git a/sw/util/msword.map b/sw/util/msword.map index 16b9d25b0b..d2a9d9b4f7 100755 --- a/sw/util/msword.map +++ b/sw/util/msword.map @@ -6,6 +6,9 @@ UDK_3_0_0 { ExportDOC; SaveOrDelMSVBAStorage_ww8; GetSaveWarningOfMSVBAStorage_ww8; + component_getImplementationEnvironment; + component_writeInfo; + component_getFactory; local: *; }; -- cgit v1.2.3