/* AbiWord xml2ps export plugin * Copyright (C) 2004 David Bolack * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include "ut_string.h" #include "ut_locale.h" #include "pt_Types.h" #include "fd_Field.h" #include "pd_Document.h" #include "pp_AttrProp.h" #include "px_ChangeRecord.h" #include "px_CR_Object.h" #include "px_CR_Span.h" #include "px_CR_Strux.h" #include "ut_string_class.h" #include "ie_exp_Passepartout.h" /*****************************************************************/ /*****************************************************************/ class IE_Exp_Passepartout : public IE_Exp { public: IE_Exp_Passepartout(PD_Document * pDocument); virtual ~IE_Exp_Passepartout() {} protected: virtual PL_Listener * _constructListener(void); virtual UT_Error _writeDocument(void); private: PL_Listener * m_pListener; }; ////////////////////////////////////////////////////////////////// // a private listener class to help us translate the document // into a passepartout stream. ////////////////////////////////////////////////////////////////// class Passepartout_Listener : public PL_Listener { public: Passepartout_Listener(PD_Document * pDocument, IE_Exp_Passepartout * pie); virtual ~Passepartout_Listener(); virtual bool populate(PL_StruxFmtHandle sfh, const PX_ChangeRecord * pcr); virtual bool populateStrux(PL_StruxDocHandle sdh, const PX_ChangeRecord * pcr, PL_StruxFmtHandle * psfh); virtual bool change(PL_StruxFmtHandle sfh, const PX_ChangeRecord * pcr); virtual bool insertStrux(PL_StruxFmtHandle sfh, const PX_ChangeRecord * pcr, PL_StruxDocHandle sdh, PL_ListenerId lid, void (* pfnBindHandles)(PL_StruxDocHandle sdhNew, PL_ListenerId lid, PL_StruxFmtHandle sfhNew)); virtual bool signal(UT_uint32 iSignal); protected: virtual void _outputData(const UT_UCSChar * p, UT_uint32 length); void _closeBlock(void); void _openBlock(PT_AttrPropIndex api); void _closeFont(void); void _openFont(PT_AttrPropIndex api); private: PD_Document * m_pDocument; IE_Exp_Passepartout * m_pie; bool m_bInBlock; bool m_inFont; bool m_inParagraph; bool m_bBreakExtra; bool m_bWasSpace; }; /*****************************************************************/ /*****************************************************************/ IE_Exp_Passepartout_Sniffer::IE_Exp_Passepartout_Sniffer (const char * /*name*/) : IE_ExpSniffer(IE_IMPEXPNAME_TEXT, true) { } UT_Confidence_t IE_Exp_Passepartout_Sniffer::supportsMIME (const char * szMIME) { if (strncmp (szMIME, "text/xml2ps", 11) == 0) return UT_CONFIDENCE_PERFECT; return UT_CONFIDENCE_ZILCH; } /*! Check filename extension for filetypes we support \param szSuffix Filename extension */ bool IE_Exp_Passepartout_Sniffer::recognizeSuffix(const char * szSuffix) { return (!g_ascii_strcasecmp(szSuffix,".xml2ps")); } UT_Error IE_Exp_Passepartout_Sniffer::constructExporter(PD_Document * pDocument, IE_Exp ** ppie) { *ppie = new IE_Exp_Passepartout(pDocument); return UT_OK; } bool IE_Exp_Passepartout_Sniffer::getDlgLabels(const char ** pszDesc, const char ** pszSuffixList, IEFileType * ft) { *pszDesc = "PassepartoutToo (.xml2ps)"; *pszSuffixList = "*.xml2ps"; *ft = getFileType(); return true; } /*****************************************************************/ /*****************************************************************/ IE_Exp_Passepartout::IE_Exp_Passepartout(PD_Document * pDocument) : IE_Exp(pDocument), m_pListener(NULL) { m_error = UT_OK; } PL_Listener * IE_Exp_Passepartout::_constructListener(void) { return new Passepartout_Listener(getDoc(),this); } UT_Error IE_Exp_Passepartout::_writeDocument(void) { m_pListener = _constructListener(); if (!m_pListener) return UT_IE_NOMEMORY; if (getDocRange()) getDoc()->tellListenerSubset(static_cast(m_pListener),getDocRange()); else getDoc()->tellListener(static_cast(m_pListener)); DELETEP(m_pListener); return ((m_error) ? UT_IE_COULDNOTWRITE : UT_OK); } /*****************************************************************/ /*****************************************************************/ /*! Output text buffer to stream \param data Buffer to output \param length Size of buffer */ void Passepartout_Listener::_outputData(const UT_UCSChar * data, UT_uint32 length) { if (!m_bInBlock) return; UT_UTF8String sBuf; const UT_UCSChar * pData; sBuf.reserve(length); for (pData=data; (pData': sBuf += ">"; pData++; break; case '&': sBuf += "&"; pData++; break; case UCS_LF: // LF -- representing a Forced-Line-Break sBuf += "
"; pData++; break; case ' ': case '\t': if(m_bWasSpace) { sBuf += " "; pData++; } else { // just tack on a single space to the textrun m_bWasSpace = true; sBuf += " "; pData++; } break; default: sBuf.appendUCS4(pData, 1); pData++; } } m_pie->write(sBuf.utf8_str(),sBuf.byteLength()); } void Passepartout_Listener::_closeBlock(void) { if (m_inFont) _closeFont(); if (!m_bInBlock) return; m_pie->write("\n"); m_bInBlock = false; } void Passepartout_Listener::_openBlock(PT_AttrPropIndex api) { const PP_AttrProp * pAP = NULL; const char* pszLeftMargin = NULL; const char* pszRightMargin = NULL; const char* pszTopMargin = NULL; const char* pszBottomMargin = NULL; const char* pszFontFamily = NULL; const char* pszFontSize = NULL; const char* pszParaAlign = NULL; const char* pszParaLineHeight = NULL; if(m_bInBlock) _closeBlock(); m_bInBlock = true; UT_UTF8String TempStr; double pszLeftMarginDouble, pszRightMarginDouble, pszTopMarginDouble,pszBottomMarginDouble; bool bHaveProp = m_pDocument->getAttrProp (api, &pAP); // Get a bunch of block level and other default properties. // Note, these don't seem to exist in the piecetable until someone alters them. need a // better way to get the defaults. pAP->getProperty("page-margin-left", (const gchar *&)pszLeftMargin); pAP->getProperty("page-margin-right", (const gchar *&)pszRightMargin); pAP->getProperty("page-margin-top", (const gchar *&)pszTopMargin); pAP->getProperty("page-margin-bottom", (const gchar *&)pszBottomMargin); pAP->getProperty("font-family", (const gchar *&) pszFontFamily); pAP->getProperty("font-size", (const gchar *&) pszFontSize ); pAP->getProperty("text-align", (const gchar *&) pszParaAlign ); pAP->getProperty("line-height", (const gchar *&) pszParaLineHeight ); // Insert defaults if we don't have any values. Note that these come from hardcoded values from pp_Property.cpp and // Probably should be found via a function/method at a later date. pszLeftMarginDouble = UT_convertToPoints(pszLeftMargin); pszRightMarginDouble = UT_convertToPoints(pszRightMargin); pszTopMarginDouble = UT_convertToPoints(pszTopMargin); pszBottomMarginDouble = UT_convertToPoints(pszBottomMargin); if ( !pszLeftMargin ) pszLeftMarginDouble = 1; if ( !pszRightMargin ) pszRightMarginDouble = 1; if ( !pszTopMargin ) pszTopMarginDouble = 1; if ( !pszBottomMargin ) pszBottomMarginDouble = 1; UT_LocaleTransactor locale(LC_NUMERIC, "C"); if (bHaveProp && pAP) { m_pie->write("write(TempStr.utf8_str()); } else { TempStr = UT_UTF8String_sprintf(" font-family=\"%s\"", "Times New Roman" ); m_pie->write(TempStr.utf8_str()); } if ( pszFontSize != NULL ) { TempStr = UT_UTF8String_sprintf(" font-size=\"%s\"", pszFontSize ); m_pie->write(TempStr.utf8_str()); } else { TempStr = UT_UTF8String_sprintf(" font-size=\"%s\"", "12pt" ); m_pie->write(TempStr.utf8_str()); } if ( pszParaAlign != NULL ) { TempStr = UT_UTF8String_sprintf(" align=\"%s\"", pszParaAlign ); m_pie->write(TempStr.utf8_str()); } else { TempStr = UT_UTF8String_sprintf(" align=\"%s\"", "right" ); m_pie->write(TempStr.utf8_str()); } if ( pszParaLineHeight != NULL ) { TempStr = UT_UTF8String_sprintf(" line-height=\"%s\"", pszParaLineHeight ); m_pie->write(TempStr.utf8_str()); } else { TempStr = UT_UTF8String_sprintf(" line-height=\"%s\"", "1.0" ); m_pie->write(TempStr.utf8_str()); } if( pszTopMargin != NULL ) { TempStr = UT_UTF8String_sprintf(" margin-top=\"%gpt\"", pszTopMarginDouble ); m_pie->write(TempStr.utf8_str()); } if( pszBottomMargin != NULL ) { TempStr = UT_UTF8String_sprintf(" margin-bottom=\"%gpt\"", pszBottomMarginDouble ); m_pie->write(TempStr.utf8_str()); } if( pszLeftMargin != NULL ) { TempStr = UT_UTF8String_sprintf(" margin-right=\"%gpt\"", pszRightMarginDouble ); m_pie->write(TempStr.utf8_str()); } if( pszRightMargin != NULL ) { TempStr = UT_UTF8String_sprintf(" margin-left=\"%gpt\"", pszLeftMarginDouble ); m_pie->write(TempStr.utf8_str()); } m_pie->write(">"); } else { m_pie->write("\n"); } } void Passepartout_Listener::_closeFont(void) { if (!m_inFont) return; m_pie->write(""); m_inFont = false; } void Passepartout_Listener::_openFont(PT_AttrPropIndex api) { const PP_AttrProp * pAP = NULL; const char* pszFontFamily = NULL; const char* pszFontSize = NULL; if(m_inFont) _closeFont(); m_inFont = true; UT_UTF8String TempStr; bool bHaveProp = m_pDocument->getAttrProp (api, &pAP); // Get a bunch of block level and other default properties. pAP->getProperty("font-family", (const gchar *&) pszFontFamily); pAP->getProperty("font-size", (const gchar *&) pszFontSize ); if (bHaveProp && pAP) { m_pie->write("write(TempStr.utf8_str()); } else { TempStr = UT_UTF8String_sprintf(" font-family=\"%s\"", "Times New Roman" ); m_pie->write(TempStr.utf8_str()); } if ( pszFontSize != NULL ) { TempStr = UT_UTF8String_sprintf(" font-size=\"%s\"", pszFontSize ); m_pie->write(TempStr.utf8_str()); } else { TempStr = UT_UTF8String_sprintf(" font-size=\"%s\"", "12pt" ); m_pie->write(TempStr.utf8_str()); } m_pie->write(">"); } else { m_pie->write("\n"); } } /***************************************************************/ /***************************************************************/ Passepartout_Listener::Passepartout_Listener(PD_Document * pDocument, IE_Exp_Passepartout * pie) : m_pDocument(pDocument), m_pie(pie), m_bInBlock(false), m_bBreakExtra(false), m_bWasSpace(false) { PT_AttrPropIndex api = m_pDocument->getAttrPropIndex(); const PP_AttrProp * pAP = NULL; const char* pszLeftMargin = NULL; const char* pszRightMargin = NULL; const char* pszTopMargin = NULL; const char* pszBottomMargin = NULL; const char* pszFontFamily = NULL; const char* pszFontSize = NULL; UT_UTF8String TempStr; double pszLeftMarginDouble, pszRightMarginDouble, pszTopMarginDouble,pszBottomMarginDouble; bool bHaveProp = m_pDocument->getAttrProp (api, &pAP); m_inFont = false; m_inParagraph = false; // Get a bunch of block level and other default properties. pAP->getProperty("margin-left", (const gchar *&)pszLeftMargin); pAP->getProperty("margin-right", (const gchar *&)pszRightMargin); pAP->getProperty("margin-top", (const gchar *&)pszTopMargin); pAP->getProperty("margin-bottom", (const gchar *&)pszBottomMargin); pAP->getProperty("font-family", (const gchar *&) pszFontFamily); pAP->getProperty("font-size", (const gchar *&) pszFontSize ); // Manipulate them a little. Not sure this is needed. pszLeftMarginDouble = UT_convertToPoints(pszLeftMargin); pszRightMarginDouble = UT_convertToPoints(pszRightMargin); pszTopMarginDouble = UT_convertToPoints(pszTopMargin); pszBottomMarginDouble = UT_convertToPoints(pszBottomMargin); m_pie->write("\n"); UT_LocaleTransactor locale(LC_NUMERIC, "C"); if (bHaveProp && pAP) { m_pie->write("write(TempStr.utf8_str()); } if ( pszFontSize != NULL ) { TempStr = UT_UTF8String_sprintf(" font-size=\"%s\"", pszFontSize ); m_pie->write(TempStr.utf8_str()); } if( pszTopMargin != NULL ) { TempStr = UT_UTF8String_sprintf(" margin-top=\"%gpt\"", pszTopMarginDouble ); m_pie->write(TempStr.utf8_str()); } if( pszBottomMargin != NULL ) { TempStr = UT_UTF8String_sprintf(" margin-bottom=\"%gpt\"", pszBottomMarginDouble ); m_pie->write(TempStr.utf8_str()); } if( pszRightMargin != NULL ) { TempStr = UT_UTF8String_sprintf(" margin-right=\"%gpt\"", pszRightMarginDouble ); m_pie->write(TempStr.utf8_str()); } if( pszLeftMargin != NULL ) { TempStr = UT_UTF8String_sprintf(" margin-left=\"%gpt\"", pszLeftMarginDouble ); m_pie->write(TempStr.utf8_str()); } m_pie->write(">"); } else { m_pie->write("\n"); } } Passepartout_Listener::~Passepartout_Listener() { _closeBlock(); m_pie->write("\n"); } /***************************************************************/ /***************************************************************/ bool Passepartout_Listener::populate(PL_StruxFmtHandle /*sfh*/, const PX_ChangeRecord * pcr) { switch (pcr->getType()) { case PX_ChangeRecord::PXT_InsertSpan: { const PX_ChangeRecord_Span * pcrs = static_cast(pcr); PT_AttrPropIndex api = pcr->getIndexAP(); _closeFont(); _openFont(api); PT_BufIndex bi = pcrs->getBufIndex(); const UT_UCS4Char * pData = m_pDocument->getPointer(bi); _outputData(pData,pcrs->getLength()); return true; } case PX_ChangeRecord::PXT_InsertFmtMark: return true; default: UT_ASSERT_HARMLESS(UT_TODO); return true; } } bool Passepartout_Listener::populateStrux(PL_StruxDocHandle /*sdh*/, const PX_ChangeRecord * pcr, PL_StruxFmtHandle * psfh) { UT_ASSERT(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux); const PX_ChangeRecord_Strux * pcrx = static_cast(pcr); *psfh = 0; // we don't need it. switch (pcrx->getStruxType()) { case PTX_SectionEndnote: case PTX_SectionHdrFtr: case PTX_Section: { _closeBlock(); PT_AttrPropIndex api = pcr->getIndexAP(); const PP_AttrProp * pAP = NULL; bool bHaveProp = m_pDocument->getAttrProp (api, &pAP); if (bHaveProp && pAP) { } return true; } case PTX_Block: { PT_AttrPropIndex api = pcr->getIndexAP(); _closeBlock(); _openBlock(api); m_bInBlock = true; return true; } // Be nice about these until we figure out what to do with 'em case PTX_SectionTable: case PTX_SectionCell: case PTX_EndTable: case PTX_EndCell: case PTX_EndFrame: case PTX_EndMarginnote: case PTX_EndFootnote: case PTX_SectionFrame: case PTX_SectionMarginnote: case PTX_SectionFootnote: case PTX_EndEndnote: return true ; default: UT_ASSERT_HARMLESS(UT_TODO); return true; } } bool Passepartout_Listener::change(PL_StruxFmtHandle /*sfh*/, const PX_ChangeRecord * /*pcr*/) { UT_ASSERT_NOT_REACHED(); // this function is not used. return false; } bool Passepartout_Listener::insertStrux(PL_StruxFmtHandle /*sfh*/, const PX_ChangeRecord * /*pcr*/, PL_StruxDocHandle /*sdh*/, PL_ListenerId /* lid */, void (* /*pfnBindHandles*/)(PL_StruxDocHandle /* sdhNew */, PL_ListenerId /* lid */, PL_StruxFmtHandle /* sfhNew */)) { UT_ASSERT_NOT_REACHED(); // this function is not used. return false; } bool Passepartout_Listener::signal(UT_uint32 /* iSignal */) { UT_ASSERT_NOT_REACHED(); return false; }