Hiyas-
attached find the start of a KWord exporter; it does most character
and paragraph properties, save color, and page properties, but is
missing lots of fancier stuff (sections, columns, headers/footers,
lists).
It is, however, quite useable, and ready for inclusion in AbiWord
(at least in DEBUG builds).
The source files go in abi/src/wp/impexp/xp.
--
-pookie
/* AbiWord
* Copyright (C) 1998 AbiSource, Inc.
*
* 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 <locale.h>
#include "ut_string.h"
#include "ut_types.h"
#include "ut_units.h"
#include "ut_bytebuf.h"
#include "ut_base64.h"
#include "ut_debugmsg.h"
#include "pt_Types.h"
#include "ie_exp_KWord_1.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 "pp_Property.h"
#include "xap_App.h"
#include "ap_Prefs.h"
#include "pd_Style.h"
#include "fd_Field.h"
#include "xap_EncodingManager.h"
#include "fl_AutoNum.h"
#include "fp_PageSize.h"
#include "ut_string_class.h"
/*****************************************************************/
/*****************************************************************/
class s_KWord_1_Listener : public PL_Listener
{
public:
s_KWord_1_Listener(PD_Document * pDocument,
IE_Exp_KWord_1 * pie);
virtual ~s_KWord_1_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:
void _handlePageSize(PT_AttrPropIndex api);
void _handleAttributes(PT_AttrPropIndex api);
void _handleStyles(void);
void _handleDataItems(void);
void _outputData(const UT_UCSChar * data, UT_uint32 length);
void _convertFontSize(char* szDest, const char*
szFontSize);
void _convertColor(char* szDest, const char* pszColor);
void _closeSection(void);
void _closeBlock(void);
void _closeSpan(void);
void _openBlock(PT_AttrPropIndex api);
void _openSection(PT_AttrPropIndex api);
void _openSpan(PT_AttrPropIndex api, PT_BlockOffset
pos, UT_uint32 len);
private:
PD_Document * m_pDocument;
IE_Exp_KWord_1 * m_pie;
bool m_bInSection;
bool m_bInBlock;
bool m_bInSpan;
bool m_bFirstWrite;
UT_String m_sFormats;
UT_String m_sLayout;
int m_iImgCnt;
};
/*****************************************************************/
/*****************************************************************/
#ifdef ENABLE_PLUGINS
// completely generic code to allow this to be a plugin
#include "xap_Module.h"
#define SUPPORTS_ABI_VERSION(a,b,c) (((a==0)&&(b==7)&&(c==15)) ? 1 : 0)
// we use a reference-counted sniffer
static IE_Exp_KWord_1_Sniffer * m_sniffer = 0;
ABI_FAR extern "C"
int abi_plugin_register (XAP_ModuleInfo * mi)
{
if (!m_sniffer)
{
m_sniffer = new IE_Exp_KWord_1_Sniffer ();
}
else
{
m_sniffer->ref();
}
mi->name = "KWord Exporter";
mi->desc = "Export KWord Documents";
mi->version = "0.7.15";
mi->author = "Abi the Ant and Nils Barth";
mi->usage = "No Usage";
IE_Exp::registerExporter (m_sniffer);
return 1;
}
ABI_FAR extern "C"
int abi_plugin_unregister (XAP_ModuleInfo * mi)
{
mi->name = 0;
mi->desc = 0;
mi->version = 0;
mi->author = 0;
mi->usage = 0;
UT_ASSERT (m_sniffer);
IE_Exp::unregisterExporter (m_sniffer);
if (!m_sniffer->unref())
{
m_sniffer = 0;
}
return 1;
}
ABI_FAR extern "C"
int abi_plugin_supports_version (UT_uint32 major, UT_uint32 minor,
UT_uint32 release)
{
return SUPPORTS_ABI_VERSION(major, minor, release);
}
#endif
/*****************************************************************/
/*****************************************************************/
IE_Exp_KWord_1::IE_Exp_KWord_1(PD_Document * pDocument)
: IE_Exp(pDocument), m_pListener(0)
{
m_error = UT_OK;
}
IE_Exp_KWord_1::~IE_Exp_KWord_1()
{
}
/*****************************************************************/
/*****************************************************************/
bool IE_Exp_KWord_1_Sniffer::recognizeSuffix(const char * szSuffix)
{
return (!UT_stricmp(szSuffix,".kwd"));
}
UT_Error IE_Exp_KWord_1_Sniffer::constructExporter(PD_Document * pDocument,
IE_Exp ** ppie)
{
IE_Exp_KWord_1 * p = new IE_Exp_KWord_1(pDocument);
*ppie = p;
return UT_OK;
}
bool IE_Exp_KWord_1_Sniffer::getDlgLabels(const char ** pszDesc,
const char
** pszSuffixList,
IEFileType *
ft)
{
*pszDesc = "KWord (.kwd)";
*pszSuffixList = "*.kwd";
*ft = getFileType();
return true;
}
/*****************************************************************/
/*****************************************************************/
UT_Error IE_Exp_KWord_1::_writeDocument(void)
{
m_pListener = new s_KWord_1_Listener(m_pDocument,this);
if (!m_pListener)
return UT_IE_NOMEMORY;
if (!m_pDocument->tellListener(static_cast<PL_Listener *>(m_pListener)))
return UT_ERROR;
delete m_pListener;
m_pListener = NULL;
return ((m_error) ? UT_IE_COULDNOTWRITE : UT_OK);
}
/*****************************************************************/
/*****************************************************************/
s_KWord_1_Listener::s_KWord_1_Listener(PD_Document * pDocument,
IE_Exp_KWord_1 * pie)
: m_pDocument (pDocument), m_pie (pie),
m_bInSection(false), m_bInBlock(false),
m_bInSpan(false), m_bFirstWrite(true),
m_sFormats(""), m_sLayout(""), m_iImgCnt(0)
{
// Be nice to XML apps. See the notes in _outputData() for more
// details on the charset used in our documents. By not declaring
// any encoding, XML assumes we're using UTF-8. Note that US-ASCII
// is a strict subset of UTF-8.
if (!XAP_EncodingManager::get_instance()->cjk_locale() &&
(XAP_EncodingManager::get_instance()->try_nativeToU(0xa1) != 0xa1)) {
// use utf8 for CJK locales and latin1 locales and unicode locales
m_pie->write("<?xml version=\"1.0\" encoding=\"");
m_pie->write(XAP_EncodingManager::get_instance()->getNativeEncodingName());
m_pie->write("\"?>\n");
} else {
m_pie->write("<?xml version=\"1.0\"?>\n");
}
m_pie->write("<!-- This document was created by AbiWord -->\n");
m_pie->write("<!-- AbiWord is a free, Open Source word processor. -->\n");
m_pie->write("<!-- You may obtain more information about AbiWord at
www.abisource.com -->\n\n");
m_pie->write("<DOC editor=\"AbiWord\" mime=\"application/x-kword\"
syntaxVersion=\"1\">\n");
}
s_KWord_1_Listener::~s_KWord_1_Listener()
{
_closeSpan();
_closeBlock();
_closeSection();
m_pie->write("</FRAMESETS>\n");
_handleStyles();
// FIXME: handle <PIXMAPS>
// _handleDataItems();
m_pie->write ("</DOC>\n");
}
bool s_KWord_1_Listener::populate(PL_StruxFmtHandle /*sfh*/,
const PX_ChangeRecord
* pcr)
{
switch (pcr->getType())
{
case PX_ChangeRecord::PXT_InsertSpan:
{
const PX_ChangeRecord_Span * pcrs =
static_cast<const PX_ChangeRecord_Span *> (pcr);
PT_AttrPropIndex api = pcr->getIndexAP();
if (api)
{
_openSpan(api,pcrs->getBlockOffset(),pcrs->getLength());
}
PT_BufIndex bi = pcrs->getBufIndex();
_outputData(m_pDocument->getPointer(bi),pcrs->getLength());
if (api)
{
_closeSpan();
}
return true;
}
case PX_ChangeRecord::PXT_InsertObject:
{
const PX_ChangeRecord_Object * pcro = static_cast<const
PX_ChangeRecord_Object *> (pcr);
//PT_AttrPropIndex api = pcr->getIndexAP();
switch (pcro->getObjectType())
{
case PTO_Image:
{
//char buf[16];
//sprintf(buf, "%d.png", m_iImgCnt++);
//m_pie->write("<fo:external-graphic src=\"");
//m_pie->write(m_pie->getFileName());
//m_pie->write(buf);
//m_pie->write("\"/>\n");
return true;
}
case PTO_Field:
{
return true;
}
default:
{
UT_ASSERT(0);
return false;
}
}
}
case PX_ChangeRecord::PXT_InsertFmtMark:
return true;
default:
UT_ASSERT(0);
return false;
}
}
bool s_KWord_1_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<const PX_ChangeRecord_Strux
*> (pcr);
*psfh = 0; // we don't
need it.
switch (pcrx->getStruxType())
{
case PTX_Section:
{
_closeSpan();
_closeBlock();
_closeSection();
PT_AttrPropIndex indexAP = pcr->getIndexAP();
const PP_AttrProp* pAP = NULL;
if (m_pDocument->getAttrProp(indexAP, &pAP) && pAP)
{
const XML_Char* pszSectionType = NULL;
pAP->getAttribute("type", pszSectionType);
if (
!pszSectionType
|| (0 == UT_strcmp(pszSectionType, "doc"))
)
{
_openSection(pcr->getIndexAP());
m_bInSection = true;
}
else
{
m_bInSection = false;
}
}
else
{
m_bInSection = false;
}
return true;
}
case PTX_SectionHdrFtr:
{
// TODO???
return true;
}
case PTX_Block:
{
_closeSpan();
_closeBlock();
_openBlock(pcr->getIndexAP());
return true;
}
default:
{
UT_ASSERT(0);
return false;
}
}
}
bool s_KWord_1_Listener::signal(UT_uint32 /* iSignal */)
{
UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
return false;
}
bool s_KWord_1_Listener::change(PL_StruxFmtHandle /*sfh*/,
const PX_ChangeRecord *
/*pcr*/)
{
UT_ASSERT(0); // this function is
not used.
return false;
}
bool s_KWord_1_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(0); // this function is
not used.
return false;
}
/*****************************************************************/
/*****************************************************************/
static const char *
preferedUnitString(fp_PageSize::Unit docUnit)
{
if(docUnit == fp_PageSize::cm)
return "mm";
else if(docUnit == fp_PageSize::mm)
return "mm";
else if(docUnit == fp_PageSize::inch)
return "inch";
else
{
UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
return "";
}
}
static const char *
justificationToNumber(const char * justification_name)
{
if (! strcmp(justification_name,"left"))
return "0";
else if (! strcmp(justification_name,"right"))
return "1";
else if (! strcmp(justification_name,"center"))
return "2";
else if (! strcmp(justification_name,"justify"))
return "3";
else
{
UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
return "";
}
}
// Converts the AbiWord page sizes into the KOffice sizes;
// compare abi/src/text/fmt/xp/fp_PageSize.h
// and koffice/lib/kofficeui/koGlobal.h
// FIXME: put a prototype above
const char*
abiPageSizeToKoPageFormat (fp_PageSize abi_page_size)
{
// The goofy order of the pagesizes is due to koGlobal.h
switch (fp_PageSize::NameToPredefined(abi_page_size.getPredefinedName())) {
case fp_PageSize::A3:
return "0";
break;
case fp_PageSize::A4:
return "1";
break;
case fp_PageSize::A5:
return "2";
break;
case fp_PageSize::Letter:
return "3";
break;
case fp_PageSize::Legal:
return "4";
break;
// FIXME: I don't understand what is meant in KWord by `screen'
// sized paper
case fp_PageSize::Custom:
return "6";
break;
case fp_PageSize::B5:
return "7";
break;
#if 0 // This requires the `lot more page sizes' patch
case fp_PageSize::Executive:
return "8";
break;
#endif
#if 0 // KWord DTD 2 sizes
case fp_PageSize::A0:
return 9;
case fp_PageSize::A1:
return 10;
case fp_PageSize::A2:
return 11;
case fp_PageSize::A6:
return 12;
case fp_PageSize::A7:
return 13;
case fp_PageSize::A8:
return 14;
case fp_PageSize::A9:
return 15;
case fp_PageSize::B0:
return 16;
case fp_PageSize::B1:
return 17;
case fp_PageSize::B10:
return 18;
case fp_PageSize::B2:
return 19;
case fp_PageSize::B3:
return 20;
case fp_PageSize::B4:
return 21;
case fp_PageSize::B6:
return 22;
#endif
default:
return "6"; // Custom
break;
}
}
void s_KWord_1_Listener::_handlePageSize(PT_AttrPropIndex api)
{
//
// Code to write out the PageSize Definitions to disk
//
char *old_locale;
//const PP_AttrProp * pAP = NULL;
//bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
old_locale = setlocale (LC_NUMERIC, "C");
m_pie->write("<PAPER");
// KWord version 1 width/height are in mm
const fp_PageSize::Unit kword_1_unit = fp_PageSize::mm;
m_pie->write(" format=\"");
m_pie->write(abiPageSizeToKoPageFormat(m_pDocument->m_docPageSize));
m_pie->write("\"");
m_pie->write(" orientation=\"");
if (m_pDocument->m_docPageSize.isPortrait())
m_pie->write("0");
else
m_pie->write("1");
m_pie->write("\"");
// FIXME: I think we need to create new frames for each change in
// number of columns
m_pie->write(" columns=\"1\"");
// FIXME: put something useful here
m_pie->write(" columnspacing=\"0\"");
char buf[20]; // FIXME: EVIL! Bad! No hard-coded buffers!
m_pie->write(" width=\"");
sprintf((char *) buf,"%f",m_pDocument->m_docPageSize.Width(kword_1_unit));
m_pie->write((char *)buf);
m_pie->write("\"");
m_pie->write(" height=\"");
sprintf((char *) buf,"%f",m_pDocument->m_docPageSize.Height(kword_1_unit));
m_pie->write((char *)buf);
m_pie->write("\"");
m_pie->write(">\n");
// PAPERBORDERS
m_pie->write("<PAPERBORDERS");
m_pie->write(" left=\"");
sprintf((char *) buf,"%f",m_pDocument->m_docPageSize.MarginLeft(kword_1_unit));
m_pie->write((char *)buf);
m_pie->write("\"");
m_pie->write(" right=\"");
sprintf((char *)
buf,"%f",m_pDocument->m_docPageSize.MarginRight(kword_1_unit));
m_pie->write((char *)buf);
m_pie->write("\"");
m_pie->write(" top=\"");
sprintf((char *) buf,"%f",m_pDocument->m_docPageSize.MarginTop(kword_1_unit));
m_pie->write((char *)buf);
m_pie->write("\"");
m_pie->write(" bottom=\"");
sprintf((char *)
buf,"%f",m_pDocument->m_docPageSize.MarginBottom(kword_1_unit));
m_pie->write((char *)buf);
m_pie->write("\"");
m_pie->write("/>\n");
m_pie->write("</PAPER>\n");
setlocale (LC_NUMERIC, old_locale);
m_bFirstWrite = false;
return;
}
void s_KWord_1_Listener::_handleAttributes(PT_AttrPropIndex api)
{
m_pie->write("<ATTRIBUTES");
m_pie->write(" processing=\"0\"");
m_pie->write(" unit=\"");
m_pie->write(preferedUnitString(m_pDocument->m_docPageSize.getUnit()));
m_pie->write("\"");
m_pie->write("/>\n");
return;
}
void s_KWord_1_Listener::_handleDataItems(void)
{
const char * szName;
const char * szMimeType;
const UT_ByteBuf * pByteBuf;
for (UT_uint32 k=0;
(m_pDocument->enumDataItems(k,NULL,&szName,&pByteBuf,(void**)&szMimeType)); k++)
{
FILE *fp;
char fname [1024]; // FIXME EVIL EVIL bad hardcoded buffer size
if (!UT_strcmp(szMimeType, "image/svg-xml"))
sprintf(fname, "%s-%d.svg", m_pie->getFileName(), k);
if (!UT_strcmp(szMimeType, "text/mathml"))
sprintf(fname, "%s-%d.mathml", m_pie->getFileName(), k);
else // PNG Image
sprintf(fname, "%s-%d.png", m_pie->getFileName(), k);
fp = fopen (fname, "wb+");
if(!fp)
continue;
int cnt = 0, len = pByteBuf->getLength();
while (cnt < len)
{
xxx_UT_DEBUGMSG(("DOM: len: %d cnt: %d\n", len, cnt));
cnt += fwrite (pByteBuf->getPointer(cnt), sizeof(UT_Byte), len-cnt, fp);
}
fclose(fp);
}
return;
}
void s_KWord_1_Listener::_handleStyles(void)
{
m_pie->write("<STYLES>\n");
// FIXME: write out styles
m_pie->write("</STYLES>\n");
}
void s_KWord_1_Listener::_openSection(PT_AttrPropIndex api)
{
if (m_bFirstWrite)
{
_handlePageSize(api);
_handleAttributes(api);
m_pie->write("<FRAMESETS>\n");
}
m_bInSection = true;
m_pie->write("<FRAMESET");
m_pie->write(" frameType=\"1\"");
m_pie->write(" frameInfo=\"0\"");
m_pie->write(" removable=\"0\"");
m_pie->write(" visible=\"1\"");
m_pie->write(" name=\"Frameset 1\"");
m_pie->write(">\n");
m_pie->write("<FRAME");
//FIXME: I think KWord ignores these, because it's a `normal page' frame
m_pie->write(" left=\"0\"");
m_pie->write(" top=\"0\"");
m_pie->write(" right=\"0\"");
m_pie->write(" bottom=\"0\"");
m_pie->write(" runaround=\"1\"");
// These make the frame act like a normal main document frame
m_pie->write(" autoCreateNewFrame=\"1\"");
m_pie->write(" newFrameBehaviour=\"0\"");
m_pie->write("/>");
}
// FIXME: prototype this
static const
UT_String measureToLengthsList(const char *pMeasure)
{
double dLength;
UT_String sLengths = "";
sLengths += " pt=\"";
dLength = UT_convertToDimension(pMeasure, DIM_PT);
sLengths += UT_convertToDimensionlessString(dLength,"2.4");
sLengths += "\"";
sLengths += " mm=\"";
dLength = UT_convertToDimension(pMeasure, DIM_MM);
sLengths += UT_convertToDimensionlessString(dLength,"2.4");
sLengths += "\"";
sLengths += " inch=\"";
dLength = UT_convertToDimension(pMeasure, DIM_IN);
sLengths += UT_convertToDimensionlessString(dLength,"2.4");
sLengths += "\"";
return sLengths;
}
//#define USED() do {if(!used) used = true;} while (0)
void s_KWord_1_Listener::_openBlock(PT_AttrPropIndex api)
{
if (!m_bInSection)
{
return;
}
const UT_Dimension kword_1_dimension = DIM_MM;
const PP_AttrProp * pAP = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
m_bInBlock = true;
m_pie->write("<PARAGRAPH>\n<TEXT>");
// keep track of whether we have we written anything
//bool used = false;
m_sFormats = "";
m_sFormats += "<FORMATS>\n";
m_sLayout = "";
m_sLayout += "<LAYOUT>\n";
// FIXME: we should write a <LAYOUT> section only if there are any
// non-empty, supported attributes, so we prolly need an if {...}
// surrounding this -- actually, it may be easier to use `USED',
// and at the end put: if (!used) m_sLayout = "";
// FIXME: Once styles are supported, make sure we write out even
// "false" settings, as these may be needed to override styles
// FIXME: tabstops, default-tab-interval, background-color
// NAME
// <NAME value=\"Standard\"/>
// this should be the style attribute
// FOLLOWING
// FIXME: does AbiWord support this?
if (bHaveProp && pAP)
{
const XML_Char * szValue;
// FLOW
// <FLOW align="left,right,center,justify"/>
if (pAP->getProperty("text-align", szValue))
{
//m_sLayout += "<FLOW align=\""; // KWord DTD 2
//m_sLayout += (const char *) szValue; // KWord DTD 2
m_sLayout += "<FLOW value=\""; // KWord DTD 1
m_sLayout += justificationToNumber((const char *) szValue); //
KWord DTD 1
m_sLayout += ("\"/>\n");
}
// FIXME: this is a bit tricky...
// LINESPACING
// extra space between lines, in points;
// <LINESPACING pt="12"/> (or mm="5" or whatever)
// KWord DTD 2:
// extra space between lines, in points; can also be "oneandhalf" or "double"
// <LINESPACING value="12"/>
// NOTE: AbiWord uses 1.0 1.5 2.0 (for single, half again, double) spacing,
// and 24pt 24pt+ for EXACT spacing, and AT LEAST spacing.
// (and if you edit it manually, you can put in 3.0, 4.5, or any other multiple
// you want instead of 1.0, 2.0, etc.)
// These do not map well onto KWord's `extra spacing' format, as we need to
// figure out how much space a given line of AbiWord text takes, though with
// KWord DTD 2, we can preserve 1.5 and 2.0 times spacing.
// Single space for 12pt text seems to be 13pt (need to check),
// if (pAP->getProperty("line-height", szValue))
// INDENTS
// (in mm in KWord 1, in pt in KWord 2)
// first=text-indent+margin-left
// left=margin-left
// right=margin-right // KWord DTD 2
// e.g., <INDENTS first="16" left="0"/>
double left_indent = 0;
if (pAP->getProperty("margin-left", szValue))
left_indent = UT_convertToDimension(szValue,
kword_1_dimension);
double first_indent = left_indent;
if (pAP->getProperty("text-indent", szValue))
first_indent += UT_convertToDimension(szValue,
kword_1_dimension);
double right_indent = 0;
if (pAP->getProperty("margin-right", szValue))
right_indent = UT_convertToDimension(szValue,
kword_1_dimension);
// Only write <INDENTS> if there are some non-trivial ones.
//if ((left_indent != 0.) || (first_indent != 0.) || (right_indent !=
0.))
// WORK-AROUND: KWord 1.0 hangs on negative indents
// FIXME: might need to write in zero for negative value to deal
// with styles
if ((left_indent > 0.) || (first_indent > 0.) || (right_indent > 0.))
{
m_sLayout += "<INDENTS";
//if (left_indent != 0.)
if (left_indent > 0.)
{
m_sLayout += " left=\"";
m_sLayout +=
UT_convertToDimensionlessString(left_indent,"2.4");
m_sLayout += "\"";
}
//if (first_indent != 0.)
if (first_indent > 0.)
{
m_sLayout += " first=\"";
m_sLayout +=
UT_convertToDimensionlessString(first_indent,"2.4");
m_sLayout += "\"";
}
//if (right_indent != 0.)
if (right_indent > 0.)
{
m_sLayout += " right=\"";
m_sLayout +=
UT_convertToDimensionlessString(right_indent,"2.4");
m_sLayout += "\"";
}
m_sLayout += "/>\n";
}
// OFFSETS
// (in mm in KWord 1, in pt in KWord 2)
// before=margin-top
// after=margin-bottom
// e.g., <OFFSETS before="12" after="12"/>
#if 0 // KWord DTD 2
double before_offset = 0;
if (pAP->getProperty("margin-top", szValue))
before_offset = UT_convertToDimension(szValue,
kword_1_dimension);
double after_offset = 0;
if (pAP->getProperty("margin-bottom", szValue))
after_offset = UT_convertToDimension(szValue,
kword_1_dimension);
// Only write <OFFSETS> if there are some non-trivial ones.
if ((before_offset != 0.) || (after_offset != 0.))
{
m_sLayout += "<OFFSETS";
if (before_offset != 0.)
{
m_sLayout += " before=\"";
m_sLayout +=
UT_convertToDimensionlessString(before_offset,"2.4");
m_sLayout += "\"";
}
if (after_offset != 0.)
{
m_sLayout += " after=\"";
m_sLayout +=
UT_convertToDimensionlessString(after_offset,"2.4");
m_sLayout += "\"";
}
m_sLayout += "/>\n";
}
#endif // KWord DTD 2
// WORK-AROUND: despite a DTD to the contrary, KWord 1 uses
// <OHEAD pt="" mm="" inch=""/>
// <OFOOT pt="" mm="" inch=""/>
double before_offset = 0;
if (pAP->getProperty("margin-top", szValue))
before_offset = UT_convertToDimension(szValue, DIM_MM);
if (before_offset != 0.)
{
m_sLayout += "<OHEAD";
m_sLayout += measureToLengthsList((const char*) szValue);
m_sLayout += "/>\n";
}
double after_offset = 0;
if (pAP->getProperty("margin-bottom", szValue))
after_offset = UT_convertToDimension(szValue,
kword_1_dimension);
if (after_offset != 0.)
{
m_sLayout += "<OFOOT";
m_sLayout += measureToLengthsList((const char*) szValue);
m_sLayout += "/>\n";
}
// PAGEBREAKING
// e.g., <PAGEBREAKING linesTogether="true" keepWithNext="true"/>
bool bLinesTogether=false;
if (pAP->getProperty("keep-together", szValue))
bLinesTogether = (strcasecmp(szValue,"true") == 0);
bool bKeepWithNext=false;
if (pAP->getProperty("keep-with-next", szValue))
bKeepWithNext = (strcasecmp(szValue,"true") == 0);
// FIXME: I should probably run this if and only if the above properties
// exist (dealing with styles)
if (bLinesTogether || bKeepWithNext)
{
m_sLayout += "<PAGEBREAKING";
m_sLayout += " linesTogether=\"";
if (bLinesTogether)
m_sLayout += "true";
else
m_sLayout += "false";
m_sLayout += "\"";
m_sLayout += " keepWithNext=\"";
if (bKeepWithNext)
m_sLayout += "true";
else
m_sLayout += "false";
m_sLayout += "\"";
m_sLayout += "/>";
}
// FIXME: are widows unsupported in KWord?
// if (pAP->getProperty("widows", szValue))
#if 0
// put these inside a <FORMAT>
if (pAP->getProperty("bgcolor", szValue))
{
USED();
m_pie->write("background-color=\"#");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
if (pAP->getProperty("color", szValue))
{
USED();
m_pie->write("color=\"#");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
if (pAP->getProperty("lang", szValue))
{
USED();
m_pie->write("language=\"");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
if (pAP->getProperty("font-size", szValue))
{
USED();
m_pie->write("font-size=\"");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
if (pAP->getProperty("font-family", szValue))
{
USED();
m_pie->write("font-family=\"");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
if (pAP->getProperty("font-weight", szValue))
{
USED();
m_pie->write("font-weight=\"");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
if (pAP->getProperty("font-style", szValue))
{
USED();
m_pie->write("font-style=\"");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
if (pAP->getProperty("font-stretch", szValue))
{
USED();
m_pie->write("font-stretch=\"");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
#endif
}
m_sLayout += "</LAYOUT>\n";
}
void s_KWord_1_Listener::_openSpan(PT_AttrPropIndex api, PT_BlockOffset pos, UT_uint32
len)
{
if (!m_bInBlock)
{
return;
}
m_bInSpan = true;
const PP_AttrProp * pAP = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
// keep track of whether we've written out anything
//bool used = false;
// FIXME: this is where all the formatting happens -- I need to
// enqueue formatting information, to be written to file when
// closeBlock is called
m_sFormats += "<FORMAT id=\"1\""; // id="1" means normal text
m_sFormats += " pos=\""; // current cursor position
char buf[100]; // FIXME: bad! hard-coded buffer size
sprintf(buf,"%ld", (long) pos);
m_sFormats += buf;
m_sFormats += "\"";
m_sFormats += " len=\""; // length of span
sprintf(buf,"%ld", (long) len);
m_sFormats += buf;
m_sFormats += "\"";
m_sFormats += ">\n";
// FIXME: I don't think KWord supports styles for spans, so we'll have to
// do it manually?
if (bHaveProp && pAP)
{
// query and output properties
const XML_Char * szValue;
#if 0
// <COLOR red="" green="" blue=""/> er, what is the range for these?
if (pAP->getProperty("color", szValue))
{
USED();
m_pie->write("color=\"#");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
// FIXME: does KWord support background color for spans of text?
if (pAP->getProperty("bgcolor", szValue))
{
USED();
m_pie->write("background-color=\"#");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
#endif
// <FONT name="times"/>
if (pAP->getProperty("font-family", szValue))
{
m_sFormats += "<FONT name=\"";
m_sFormats += ((const char *)szValue);
m_sFormats += "\"/>\n";
}
// WORK-AROUND: actually, the <FONT> tag seems to be required;
// maybe it isn't if you have a (default) style?
// FIXME
else
m_sFormats += "<FONT name=\"times\"/>\n";
// <SIZE value="12"/> size in pt
if (pAP->getProperty("font-size", szValue))
{
char buf[100]; // FIXME: bad! hard-coded buffer size
m_sFormats += "<SIZE value=\"";
sprintf(buf,"%d", (int) UT_convertToDimension(szValue,
DIM_PT));
m_sFormats += buf;
m_sFormats += "\"/>\n";
}
// <WEIGHT value="50"/> 50=normal, 75=bold
if (pAP->getProperty("font-weight", szValue))
{
m_sFormats += "<WEIGHT value=\"";
if (!strcasecmp((char *) szValue, "bold"))
m_sFormats += "75";
else
m_sFormats += "50";
m_sFormats += "\"/>\n";
}
// <ITALIC value="1"/> 0=normal, 1=italic
if (pAP->getProperty("font-style", szValue))
{
m_sFormats += "<ITALIC value=\"";
if (!strcasecmp((char *) szValue, "italic"))
m_sFormats += "1";
else
m_sFormats += "0";
m_sFormats += "\"/>\n";
}
// <UNDERLINE value="1"/> 0=normal, 1=underline
// <STRIKEOUT value="1"/> 0=normal, 1=strikeout
if (pAP->getProperty("text-decoration", szValue))
{
if (strstr (szValue, "underline"))
m_sFormats += "<UNDERLINE value=\"1\"/>\n";
else
m_sFormats += "<UNDERLINE value=\"0\"/>\n";
if (strstr (szValue, "line-through"))
m_sFormats += "<STRIKEOUT value=\"1\"/>\n";
else
m_sFormats += "<STRIKEOUT value=\"0\"/>\n";
}
// <VERTALIGN value="0"/> 0=normal, 1=subscript, 2=superscript
if (pAP->getProperty("text-position", szValue))
{
if (!strcasecmp (szValue, "subscript"))
m_sFormats += "<VERTALIGN value=\"1\"/>\n";
else if (!strcasecmp (szValue, "superscript"))
m_sFormats += "<VERTALIGN value=\"2\"/>\n";
else
m_sFormats += "<VERTALIGN value=\"0\"/>\n";
}
#if 0
// ACK! KWord doesn't support languages, only Character sets!
// <CHARSET value=""/>
if (pAP->getProperty("lang", szValue))
{
USED();
m_pie->write("language=\"");
m_pie->write((const char *)szValue);
m_pie->write("\"");
}
// FIXME: what IS font-stretch?
// FIXME: dir/dir-override -- does KWord support these?
#endif
}
m_sFormats += "</FORMAT>\n";
}
#undef USED
void s_KWord_1_Listener::_closeBlock(void)
{
if (!m_bInBlock)
{
return;
}
m_bInBlock = false;
m_pie->write("</TEXT>\n");
m_sFormats += "</FORMATS>\n";
m_pie->write(m_sFormats.c_str()); // <FORMATS>...</FORMATS>
m_pie->write(m_sLayout.c_str()); // <LAYOUT>...</LAYOUT>
m_pie->write("</PARAGRAPH>\n");
}
void s_KWord_1_Listener::_closeSection(void)
{
if (!m_bInSection)
{
return;
}
m_bInSection = false;
m_pie->write("</FRAMESET>\n");
}
void s_KWord_1_Listener::_closeSpan(void)
{
if (!m_bInSpan)
{
return;
}
m_bInSpan = false;
// FIXME: I don't think I need to do anything here -- it should
// all be done in openSpan
}
/*****************************************************************/
/*****************************************************************/
void s_KWord_1_Listener::_convertColor(char* szDest, const char* pszColor)
{
/* FIXME: Convert this to deal with KWord's format for colors. */
strcpy(szDest, pszColor);
}
void s_KWord_1_Listener::_convertFontSize(char* szDest, const char* pszFontSize)
{
strcpy (szDest, pszFontSize);
}
/*****************************************************************/
/*****************************************************************/
void s_KWord_1_Listener::_outputData(const UT_UCSChar * data, UT_uint32 length)
{
UT_String sBuf;
const UT_UCSChar * pData;
UT_ASSERT(sizeof(UT_Byte) == sizeof(char));
for (pData=data; (pData<data+length); /**/)
{
switch (*pData)
{
case '<':
sBuf += "<";
pData++;
break;
case '>':
sBuf += ">";
pData++;
break;
case '&':
sBuf += "&";
pData++;
break;
case UCS_LF: // LF -- representing
a Forced-Line-Break
// TODO
UT_ASSERT(UT_TODO);
pData++;
break;
case UCS_VTAB: // VTAB --
representing a Forced-Column-Break
// TODO
UT_ASSERT(UT_TODO);
pData++;
break;
case UCS_FF: // FF -- representing
a Forced-Page-Break
// TODO:
UT_ASSERT(UT_TODO);
pData++;
break;
default:
if (*pData > 0x007f)
{
if(XAP_EncodingManager::get_instance()->isUnicodeLocale() ||
(XAP_EncodingManager::get_instance()->try_nativeToU(0xa1) == 0xa1))
{
XML_Char * pszUTF8 =
UT_encodeUTF8char(*pData++);
while (*pszUTF8)
{
sBuf += (char)*pszUTF8;
pszUTF8++;
}
}
else
{
/*
Try to convert to native encoding and if
character fits into byte, output raw byte.
This
is somewhat essential for single-byte non-latin
languages like russian or polish - since
tools like grep and sed can be used then for
these files without any problem.
Networks and mail transfers are 8bit clean
these days. - VH
*/
UT_UCSChar c =
XAP_EncodingManager::get_instance()->try_UToNative(*pData);
if (c==0 || c>255)
{
char localBuf[20];
char * plocal = localBuf;
sprintf(localBuf,"&#x%x;",*pData++);
sBuf += plocal;
}
else
{
sBuf += (char)c;
pData++;
}
}
}
else
{
sBuf += (char)*pData++;
}
break;
}
}
m_pie->write(sBuf.c_str(), sBuf.size());
}
/* AbiWord
* Copyright (C) 2001 AbiSource, Inc.
*
* 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.
*/
#ifndef IE_EXP_KWORD_1_H
#define IE_EXP_KWORD_1_H
#include "ie_exp.h"
#include "pl_Listener.h"
class PD_Document;
class s_KWord_1_Listener;
// The exporter/writer for the KWord 1 spec
class IE_Exp_KWord_1_Sniffer : public IE_ExpSniffer
{
friend class IE_Exp;
public:
IE_Exp_KWord_1_Sniffer () {}
virtual ~IE_Exp_KWord_1_Sniffer () {}
virtual bool recognizeSuffix (const char * szSuffix);
virtual bool getDlgLabels (const char ** szDesc,
const char ** szSuffixList,
IEFileType * ft);
virtual UT_Error constructExporter (PD_Document * pDocument,
IE_Exp
** ppie);
};
class IE_Exp_KWord_1 : public IE_Exp
{
public:
IE_Exp_KWord_1(PD_Document * pDocument);
virtual ~IE_Exp_KWord_1();
protected:
virtual UT_Error _writeDocument(void);
s_KWord_1_Listener * m_pListener;
};
#endif /* IE_EXP_KWORD_1_H */
Index: abi/src/wp/impexp/xp/Makefile
===================================================================
RCS file: /cvsroot/abi/src/wp/impexp/xp/Makefile,v
retrieving revision 1.57
diff -u -r1.57 Makefile
--- abi/src/wp/impexp/xp/Makefile 2001/06/18 15:11:47 1.57
+++ abi/src/wp/impexp/xp/Makefile 2001/08/16 14:40:29
@@ -43,6 +43,7 @@
ie_exp_MIF.cpp \
ie_exp_XSL-FO.cpp \
ie_exp_ISCII.cpp \
+ ie_exp_KWord_1.cpp \
ie_imp.cpp \
ie_imp_XML.cpp \
ie_imp_AbiWord_1.cpp \
Index: abi/src/wp/impexp/xp/ie_impexp_Register.cpp
===================================================================
RCS file: /cvsroot/abi/src/wp/impexp/xp/ie_impexp_Register.cpp,v
retrieving revision 1.6
diff -u -r1.6 ie_impexp_Register.cpp
--- abi/src/wp/impexp/xp/ie_impexp_Register.cpp 2001/07/03 14:47:39 1.6
+++ abi/src/wp/impexp/xp/ie_impexp_Register.cpp 2001/08/16 14:40:36
@@ -40,6 +40,7 @@
#include "ie_exp_Applix.h"
#include "ie_exp_XSL-FO.h"
#include "ie_exp_ISCII.h"
+#include "ie_exp_KWord_1.h"
#include "ie_imp_AbiWord_1.h"
#include "ie_imp_GZipAbiWord.h"
@@ -89,6 +90,9 @@
IE_Exp::registerExporter(new IE_Exp_XSL_FO_Sniffer ());
IE_Exp::registerExporter(new IE_Exp_HTML_Sniffer ());
IE_Exp::registerExporter(new IE_Exp_ISCII_Sniffer ());
+#ifdef DEBUG
+ IE_Exp::registerExporter(new IE_Exp_KWord_1_Sniffer ());
+#endif
IE_Exp::registerExporter(new IE_Exp_LaTeX_Sniffer ());
IE_Exp::registerExporter(new IE_Exp_PalmDoc_Sniffer ());
IE_Exp::registerExporter(new IE_Exp_Psion_TextEd_Sniffer ());