/* This file is part of the KDE project
Copyright (C) 2001, 2002, 2003, 2004 Nicolas GOUTTE
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/*
This file is based on the old file:
/home/kde/koffice/filters/kword/ascii/asciiexport.cc
The old file was copyrighted by
Copyright (C) 1998, 1999 Reginald Stadlbauer
Copyright (c) 2000 ID-PRO Deutschland GmbH. All rights reserved.
Contact: Wolf-Michael Bolle
The old file was licensed under the terms of the GNU Library General Public
License version 2.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class ABIWORDExportFactory : KGenericFactory
{
public:
ABIWORDExportFactory(void) : KGenericFactory ("kwordabiwordexport")
{}
protected:
virtual void setupTranslations( void )
{
KGlobal::locale()->insertCatalogue( "kofficefilters" );
}
};
K_EXPORT_COMPONENT_FACTORY( libabiwordexport, ABIWORDExportFactory() )
class StyleMap : public TQMap
{
public:
StyleMap(void) {}
~StyleMap(void) {}
};
class AbiWordWorker : public KWEFBaseWorker
{
public:
AbiWordWorker(void);
virtual ~AbiWordWorker(void) { delete m_streamOut; delete m_ioDevice; }
public:
virtual bool doOpenFile(const TQString& filenameOut, const TQString& to);
virtual bool doCloseFile(void); // Close file in normal conditions
virtual bool doOpenDocument(void);
virtual bool doCloseDocument(void);
virtual bool doFullParagraph(const TQString& paraText, const LayoutData& tqlayout,
const ValueListFormatData& paraFormatDataList);
virtual bool doOpenTextFrameSet(void); // AbiWord's
virtual bool doCloseTextFrameSet(void); // AbiWord's
virtual bool doFullPaperFormat(const int format,
const double width, const double height, const int orientation); // Calc AbiWord's
virtual bool doFullPaperBorders (const double top, const double left,
const double bottom, const double right); // Like KWord's
virtual bool doCloseHead(void); // Write
virtual bool doOpenStyles(void); // AbiWord's
virtual bool doCloseStyles(void); // AbiWord's
virtual bool doFullDefineStyle(LayoutData& tqlayout); // AbiWord's
virtual bool doOpenSpellCheckIgnoreList (void); // AbiWord's
virtual bool doCloseSpellCheckIgnoreList (void); // AbiWord's
virtual bool doFullSpellCheckIgnoreWord (const TQString& ignoreword); // AbiWord's
virtual bool doFullDocumentInfo(const KWEFDocumentInfo& docInfo); // AbiWord's
private:
void processParagraphData (const TQString& paraText,
const TextFormatting& formatLayout,
const ValueListFormatData& paraFormatDataList);
void processNormalText ( const TQString& paraText,
const TextFormatting& formatLayout,
const FormatData& formatData);
void processVariable ( const TQString& paraText,
const TextFormatting& formatLayout,
const FormatData& formatData);
void processAnchor ( const TQString& paraText,
const TextFormatting& formatLayout,
const FormatData& formatData);
TQString textFormatToAbiProps(const TextFormatting& formatOrigin,
const TextFormatting& formatData, const bool force) const;
TQString layoutToCss(const LayoutData& layoutOrigin,
const LayoutData& tqlayout, const bool force) const;
TQString escapeAbiWordText(const TQString& strText) const;
bool makeTable(const FrameAnchor& anchor);
bool makePicture(const FrameAnchor& anchor);
void writeAbiProps(const TextFormatting& formatLayout, const TextFormatting& format);
void writePictureData(const TQString& koStoreName, const TQString& keyName);
TQString transformToTextDate(const TQDateTime& dt);
private:
TQIODevice* m_ioDevice;
TQTextStream* m_streamOut;
TQString m_pagesize; // Buffer for the tag
TQMap m_mapPictureData;
StyleMap m_styleMap;
double m_paperBorderTop,m_paperBorderLeft,m_paperBorderBottom,m_paperBorderRight;
bool m_inIgnoreWords; // true if has been written
KWEFDocumentInfo m_docInfo; // document information
};
AbiWordWorker::AbiWordWorker(void) : m_ioDevice(NULL), m_streamOut(NULL),
m_paperBorderTop(0.0),m_paperBorderLeft(0.0),
m_paperBorderBottom(0.0),m_paperBorderRight(0.0)
{
}
TQString AbiWordWorker::escapeAbiWordText(const TQString& strText) const
{
// Escape quotes (needed in attributes)
// Escape apostrophs (allowed by XML)
return KWEFUtil::EscapeSgmlText(NULL,strText,true,true);
}
bool AbiWordWorker::doOpenFile(const TQString& filenameOut, const TQString& )
{
kdDebug(30506) << "Opening file: " << filenameOut
<< " (in AbiWordWorker::doOpenFile)" << endl;
//Find the last extension
TQString strExt;
const int result=filenameOut.findRev('.');
if (result>=0)
{
strExt=filenameOut.mid(result);
}
TQString strMimeType; // Mime type of the compressor
if ((strExt==".gz")||(strExt==".GZ") //in case of .abw.gz (logical extension)
||(strExt==".zabw")||(strExt==".ZABW")) //in case of .zabw (extension used prioritary with AbiWord)
{
// Compressed with gzip
strMimeType="application/x-gzip";
}
else if ((strExt==".bz2")||(strExt==".BZ2") //in case of .abw.bz2 (logical extension)
||(strExt==".bzabw")||(strExt==".BZABW")) //in case of .bzabw (extension used prioritary with AbiWord)
{
// Compressed with bzip2
strMimeType="application/x-bzip2";
}
else
{
// No compression
strMimeType="text/plain";
}
kdDebug(30506) << "Compression: " << strMimeType << endl;
m_ioDevice = KFilterDev::deviceForFile(filenameOut,strMimeType);
if (!m_ioDevice)
{
kdError(30506) << "No output file! Aborting!" << endl;
return false;
}
if ( !m_ioDevice->open (IO_WriteOnly) )
{
kdError(30506) << "Unable to open output file! Aborting!" << endl;
return false;
}
m_streamOut=new TQTextStream(m_ioDevice);
// We only export in UTF-8 (are there AbiWord ports that cannot read UTF-8? Be careful SVG uses UTF-8 too!)
m_streamOut->setEncoding( TQTextStream::UnicodeUTF8 );
return true;
}
bool AbiWordWorker::doCloseFile(void)
{
delete m_streamOut;
m_streamOut=NULL;
if (m_ioDevice)
m_ioDevice->close();
return (m_ioDevice);
}
bool AbiWordWorker::doOpenDocument(void)
{
kdDebug(30506)<< "AbiWordWorker::doOpenDocument" << endl;
// Make the file header
// First the XML header in UTF-8 version
// (AbiWord and QT handle UTF-8 well, so we stay with this encoding!)
*m_streamOut << "\n";
// NOTE: AbiWord CVS 2002-02-?? has a new DOCTYPE
*m_streamOut << "\n";
// First magic: "\n";
// Second magic: "\n";
// We have chosen NOT to have the full comment header that AbiWord files normally have.
// ### TODO: perhaps we should add the comment: do not edit the file
*m_streamOut << "\n";
return true;
}
void AbiWordWorker::writePictureData(const TQString& koStoreName, const TQString& keyName)
{
kdDebug(30506) << "AbiWordWorker::writeImageData" << endl;
TQByteArray image;
TQString strExtension(koStoreName.lower());
const int result=koStoreName.findRev(".");
if (result>=0)
{
strExtension=koStoreName.mid(result+1);
}
bool isImageLoaded=false;
if (strExtension=="png")
{
isImageLoaded=loadSubFile(koStoreName,image);
}
else
{
// All other picture types must be converted to PNG
// (yes, even JPEG, SVG or WMF!)
isImageLoaded=loadAndConvertToImage(koStoreName,strExtension,"PNG",image);
}
if (isImageLoaded)
{
*m_streamOut << "\n";
TQCString base64=KCodecs::base64Encode(image,true);
*m_streamOut << base64 << "\n"; // TQCString is taken as Latin1 by TQTextStream
*m_streamOut << "\n";
}
else
{
kdWarning(30506) << "Unable to load picture: " << koStoreName << endl;
}
}
bool AbiWordWorker::doCloseDocument(void)
{
// Before writing the element,
// we must be sure that we have data and that we can retrieve it.
if (m_kwordLeader && !m_mapPictureData.isEmpty())
{
*m_streamOut << "\n";
TQMap::ConstIterator it;
TQMap::ConstIterator end(m_mapPictureData.end());
// all images first
for (it=m_mapPictureData.begin(); it!=end; ++it)
{
// Warning: do not mix up KWord's key and the iterator's key!
writePictureData(it.key(),it.data().filename());
}
*m_streamOut << "\n";
}
*m_streamOut << "\n"; //Close the file for XML
return true;
}
bool AbiWordWorker::doOpenTextFrameSet(void)
{
*m_streamOut << "\n";
return true;
}
bool AbiWordWorker::doCloseTextFrameSet(void)
{
*m_streamOut << "\n";
return true;
}
bool AbiWordWorker::doOpenStyles(void)
{
*m_streamOut << "\n";
return true;
}
bool AbiWordWorker::doCloseStyles(void)
{
*m_streamOut << "\n";
return true;
}
TQString AbiWordWorker::textFormatToAbiProps(const TextFormatting& formatOrigin,
const TextFormatting& formatData, const bool force) const
{
// TODO: rename variable formatData
TQString strElement; // TODO: rename this variable
// Font name
TQString fontName = formatData.fontName;
if ( !fontName.isEmpty()
&& (force || (formatOrigin.fontName!=formatData.fontName)))
{
strElement+="font-family: ";
strElement+= escapeAbiWordText(fontName); // TODO: add alternative font names
strElement+="; ";
}
if (force || (formatOrigin.italic!=formatData.italic))
{
// Font style
strElement+="font-style: ";
if ( formatData.italic )
{
strElement+="italic";
}
else
{
strElement+="normal";
}
strElement+="; ";
}
if (force || ((formatOrigin.weight>=75)!=(formatData.weight>=75)))
{
strElement+="font-weight: ";
if ( formatData.weight >= 75 )
{
strElement+="bold";
}
else
{
strElement+="normal";
}
strElement+="; ";
}
if (force || (formatOrigin.fontSize!=formatData.fontSize))
{
const int size=formatData.fontSize;
if (size>0)
{
// We use absolute font sizes.
strElement+="font-size: ";
strElement+=TQString::number(size,10);
strElement+="pt; ";
}
}
if (force || (formatOrigin.fgColor!=formatData.fgColor))
{
if ( formatData.fgColor.isValid() )
{
// Give colour
strElement+="color: ";
// No leading # (unlike CSS2)
// We must have two hex digits for each colour channel!
const int red=formatData.fgColor.red();
strElement += TQString::number((red&0xf0)>>4,16);
strElement += TQString::number(red&0x0f,16);
const int green=formatData.fgColor.green();
strElement += TQString::number((green&0xf0)>>4,16);
strElement += TQString::number(green&0x0f,16);
const int blue=formatData.fgColor.blue();
strElement += TQString::number((blue&0xf0)>>4,16);
strElement += TQString::number(blue&0x0f,16);
strElement+="; ";
}
}
if (force || (formatOrigin.bgColor!=formatData.bgColor))
{
if ( formatData.bgColor.isValid() )
{
// Give background colour
strElement+="bgcolor: ";
// No leading # (unlike CSS2)
// We must have two hex digits for each colour channel!
const int red=formatData.bgColor.red();
strElement += TQString::number((red&0xf0)>>4,16);
strElement += TQString::number(red&0x0f,16);
const int green=formatData.bgColor.green();
strElement += TQString::number((green&0xf0)>>4,16);
strElement += TQString::number(green&0x0f,16);
const int blue=formatData.bgColor.blue();
strElement += TQString::number((blue&0xf0)>>4,16);
strElement += TQString::number(blue&0x0f,16);
strElement+="; ";
}
}
if (force || (formatOrigin.underline!=formatData.underline)
|| (formatOrigin.strikeout!=formatData.strikeout))
{
strElement+="text-decoration: ";
if ( formatData.underline )
{
strElement+="underline";
}
else if ( formatData.strikeout )
{
strElement+="line-through";
}
else
{
strElement+="none";
}
strElement+="; ";
}
return strElement;
}
bool AbiWordWorker::makeTable(const FrameAnchor& anchor)
{
#if 0
*m_streamOut << "
\n"; // Close previous paragraph ### TODO: do it correctly like for HTML
*m_streamOut << "\n";
#endif
TQValueList::ConstIterator itCell;
for (itCell=anchor.table.cellList.begin();
itCell!=anchor.table.cellList.end(); itCell++)
{
#if 0
// ### TODO: rowspan, colspan
// AbiWord seems to work by attaching to the cell borders
*m_streamOut << "\n";
#endif
if (!doFullAllParagraphs(*(*itCell).paraList))
{
return false;
}
#if 0
*m_streamOut << " | \n";
#endif
}
#if 0
*m_streamOut << "
\n";
*m_streamOut << "\n"; // Re-open the "previous" paragraph ### TODO: do it correctly like for HTML
#endif
return true;
}
bool AbiWordWorker::makePicture(const FrameAnchor& anchor)
{
kdDebug(30506) << "New image/clipart: " << anchor.picture.koStoreName
<< " , " << anchor.picture.key.toString() << endl;
const double height=anchor.frame.bottom - anchor.frame.top;
const double width =anchor.frame.right - anchor.frame.left;
// TODO: we are only using the filename, not the rest of the key
// TODO: (bad if there are two images of the same name, but of a different key)
*m_streamOut << ""; // NO end of line!
// TODO: other props for image
m_mapPictureData[anchor.picture.koStoreName]=anchor.picture.key;
return true;
}
void AbiWordWorker::writeAbiProps (const TextFormatting& formatLayout, const TextFormatting& format)
{
TQString abiprops=textFormatToAbiProps(formatLayout,format,false);
// Erase the last semi-comma (as in CSS2, semi-commas only separate instructions and do not terminate them)
const int result=abiprops.findRev(";");
if (result>=0)
{
// Remove the last semi-comma and the space thereafter
abiprops.remove(result,2);
}
if (!abiprops.isEmpty())
{
*m_streamOut << " props=\"" << abiprops << "\"";
}
}
void AbiWordWorker::processNormalText ( const TQString ¶Text,
const TextFormatting& formatLayout,
const FormatData& formatData)
{
// Retrieve text and escape it
TQString partialText=escapeAbiWordText(paraText.mid(formatData.pos,formatData.len));
// Replace line feeds by line breaks
int pos;
while ((pos=partialText.find(TQChar(10)))>-1)
{
partialText.replace(pos,1,"
");
}
if (formatData.text.missing)
{
// It's just normal text, so we do not need a element!
*m_streamOut << partialText;
}
else
{ // Text with properties, so use a element!
*m_streamOut << "" << partialText << "";
}
}
void AbiWordWorker::processVariable ( const TQString&,
const TextFormatting& formatLayout,
const FormatData& formatData)
{
if (0==formatData.variable.m_type)
{
// As AbiWord's field is inflexible, we cannot make the date custom
*m_streamOut << "";
}
else if (2==formatData.variable.m_type)
{
// As AbiWord's field is inflexible, we cannot make the time custom
*m_streamOut << "";
}
else if (4==formatData.variable.m_type)
{
// As AbiWord's field is inflexible, we cannot make the time custom
TQString strFieldType;
if (formatData.variable.isPageNumber())
{
strFieldType="page_number";
}
else if (formatData.variable.isPageCount())
{
strFieldType="page_count";
}
if (strFieldType.isEmpty())
{
// Unknown subtype, therefore write out the result
*m_streamOut << formatData.variable.m_text;
}
else
{
*m_streamOut << "";
}
}
else if (9==formatData.variable.m_type)
{
// A link
*m_streamOut << " has always a child
writeAbiProps(formatLayout,formatData.text);
*m_streamOut << ">"
<< escapeAbiWordText(formatData.variable.getLinkName())
<< "";
}
#if 0
else if (11==(*paraFormatDataIt).variable.m_type)
{
// Footnote
TQString value = (*paraFormatDataIt).variable.getFootnoteValue();
bool automatic = (*paraFormatDataIt).variable.getFootnoteAuto();
TQValueList *paraList = (*paraFormatDataIt).variable.getFootnotePara();
if( paraList )
{
TQString fstr;
TQValueList::ConstIterator it;
for (it=paraList->begin();it!=paraList->end();it++)
fstr += ProcessParagraphData( (*it).text, (*it).tqlayout,(*it).formattingList);
str += "{\\super ";
str += automatic ? "\\chftn " : value;
str += "{\\footnote ";
str += "{\\super ";
str += automatic ? "\\chftn " : value;
str += fstr;
str += " }";
str += " }";
str += " }";
}
}
#endif
else
{
// Generic variable
*m_streamOut << formatData.variable.m_text;
}
}
void AbiWordWorker::processAnchor ( const TQString&,
const TextFormatting& /*formatLayout*/, //TODO
const FormatData& formatData)
{
// We have an image or a table
if ( (2==formatData.frameAnchor.type) // or
|| (5==formatData.frameAnchor.type) ) //
{
makePicture(formatData.frameAnchor);
}
else if (6==formatData.frameAnchor.type)
{
makeTable(formatData.frameAnchor);
}
else
{
kdWarning(30506) << "Unsupported anchor type: "
<< formatData.frameAnchor.type << endl;
}
}
void AbiWordWorker::processParagraphData ( const TQString ¶Text,
const TextFormatting& formatLayout,
const ValueListFormatData ¶FormatDataList)
{
if ( paraText.length () > 0 )
{
ValueListFormatData::ConstIterator paraFormatDataIt;
for ( paraFormatDataIt = paraFormatDataList.begin ();
paraFormatDataIt != paraFormatDataList.end ();
paraFormatDataIt++ )
{
if (1==(*paraFormatDataIt).id)
{
processNormalText(paraText, formatLayout, (*paraFormatDataIt));
}
else if (4==(*paraFormatDataIt).id)
{
processVariable(paraText, formatLayout, (*paraFormatDataIt));
}
else if (6==(*paraFormatDataIt).id)
{
processAnchor(paraText, formatLayout, (*paraFormatDataIt));
}
}
}
}
TQString AbiWordWorker::layoutToCss(const LayoutData& layoutOrigin,
const LayoutData& tqlayout, const bool force) const
{
TQString props;
if (force || (layoutOrigin.alignment!=tqlayout.alignment))
{
// Check if the current alignment is a valid one for AbiWord.
if ((tqlayout.alignment == "left") || (tqlayout.alignment == "right")
|| (tqlayout.alignment == "center") || (tqlayout.alignment == "justify"))
{
props += "text-align:";
props += tqlayout.alignment;
props += "; ";
}
else if (tqlayout.alignment == "auto")
{
// We assume a left alignment as AbiWord is not really bi-di (and this filter even less.)
props += "text-align:left; ";
}
else
{
kdWarning(30506) << "Unknown alignment: " << tqlayout.alignment << endl;
}
}
// TODO/FIXME: what if all tabulators must be erased?
#if 0
// DEPRECATED!
if (!tqlayout.tabulator.isEmpty()
&& (force || (layoutOrigin.tabulator!=tqlayout.tabulator)))
{
props += "tabstops:";
props += tqlayout.tabulator;
props += "; ";
}
#endif
if (!tqlayout.tabulatorList.isEmpty()
&& (force || (layoutOrigin.tabulatorList!=tqlayout.tabulatorList) ))
{
props += "tabstops:";
bool first=true;
TabulatorList::ConstIterator it;
TabulatorList::ConstIterator end(tqlayout.tabulatorList.end());
for (it=tqlayout.tabulatorList.begin();it!=end;++it)
{
if (first)
{
first=false;
}
else
{
props += ",";
}
props += TQString::number((*it).m_ptpos);
props += "pt";
switch ((*it).m_type)
{
case 0: props += "/L"; break;
case 1: props += "/C"; break;
case 2: props += "/R"; break;
case 3: props += "/D"; break;
default: props += "/L";
}
props += "0"; // No filling
}
props += "; ";
}
if ((tqlayout.indentLeft>=0.0)
&& (force || (layoutOrigin.indentLeft!=tqlayout.indentLeft)))
{
props += TQString("margin-left:%1pt; ").arg(tqlayout.indentLeft);
}
if ((tqlayout.indentRight>=0.0)
&& (force || (layoutOrigin.indentRight!=tqlayout.indentRight)))
{
props += TQString("margin-right:%1pt; ").arg(tqlayout.indentRight);
}
if (force || (layoutOrigin.indentLeft!=tqlayout.indentLeft))
{
props += "text-indent: ";
props += TQString::number(tqlayout.indentFirst);
props += "pt; ";
}
if ((tqlayout.marginBottom>=0.0)
&& ( force || ( layoutOrigin.marginBottom != tqlayout.marginBottom ) ) )
{
props += TQString("margin-bottom:%1pt; ").arg(tqlayout.marginBottom);
}
if ((tqlayout.marginTop>=0.0)
&& ( force || ( layoutOrigin.marginTop != tqlayout.marginTop ) ) )
{
props += TQString("margin-top:%1pt; ").arg(tqlayout.marginTop);
}
if (force
|| ( layoutOrigin.lineSpacingType != tqlayout.lineSpacingType )
|| ( layoutOrigin.lineSpacing != tqlayout.lineSpacing ) )
{
switch ( tqlayout.lineSpacingType )
{
case LayoutData::LS_CUSTOM:
{
// We have a custom line spacing (in points). However AbiWord cannot do it, so transform in "at-least"
props += "line-height=:";
props += TQString::number( tqlayout.lineSpacing ); // ### TODO: rounding?
props += "pt+; ";
break;
}
case LayoutData::LS_SINGLE:
{
props += "line-height:1.0; "; // One
break;
}
case LayoutData::LS_ONEANDHALF:
{
props += "line-height:1.5; "; // One-and-half
break;
}
case LayoutData::LS_DOUBLE:
{
props += "line-height:2.0; "; // Two
break;
}
case LayoutData::LS_MULTIPLE:
{
props += "line-height:";
props += TQString::number( tqlayout.lineSpacing ); // ### TODO: rounding?
props += "; ";
break;
}
case LayoutData::LS_FIXED:
{
// We have a fixed line height (in points)
props += "line-height:";
props += TQString::number( tqlayout.lineSpacing ); // ### TODO: rounding?
props += "pt; ";
break;
}
case LayoutData::LS_ATLEAST:
{
// We have an "at-least" line height (in points)
props += "line-height=:";
props += TQString::number( tqlayout.lineSpacing ); // ### TODO: rounding?
props += "pt+; "; // The + makes the difference
break;
}
default:
{
kdWarning(30506) << "Unsupported lineSpacingType: " << tqlayout.lineSpacingType << " (Ignoring!)" << endl;
break;
}
}
}
// Add all AbiWord properties collected in the element
props += textFormatToAbiProps(layoutOrigin.formatData.text,tqlayout.formatData.text,force);
return props;
}
bool AbiWordWorker::doFullParagraph(const TQString& paraText, const LayoutData& tqlayout,
const ValueListFormatData& paraFormatDataList)
{
TQString style=tqlayout.styleName;
const LayoutData& styleLayout=m_styleMap[style];
TQString props=layoutToCss(styleLayout,tqlayout,false);
*m_streamOut << "=0)
{
// Remove the last semi-comma and the space thereafter
props.remove(result,2);
}
*m_streamOut << " props=\"" << props << "\"";
}
*m_streamOut << ">"; //Warning: No trailing white space or else it's in the text!!!
// Before processing the text, test if we have a page break
if (tqlayout.pageBreakBefore)
{
// We have a page break before the paragraph
*m_streamOut << "";
}
processParagraphData(paraText, tqlayout.formatData.text, paraFormatDataList);
// Before closing the paragraph, test if we have a page break
if (tqlayout.pageBreakAfter)
{
// We have a page break after the paragraph
*m_streamOut << "";
}
*m_streamOut << "
\n";
return true;
}
bool AbiWordWorker::doFullDefineStyle(LayoutData& tqlayout)
{
//Register style in the style map
m_styleMap[tqlayout.styleName]=tqlayout;
*m_streamOut << "=0)
{
// Remove the last semi-comma and the space thereafter
abiprops.remove(result,2);
}
*m_streamOut << " props=\"" << abiprops << "\"";
*m_streamOut << "/>\n";
return true;
}
bool AbiWordWorker::doFullPaperFormat(const int format,
const double width, const double height, const int orientation)
{
TQString outputText = "\n"; // KWord has no page scale, so assume 100%
m_pagesize=outputText;
return true;
}
bool AbiWordWorker::doFullPaperBorders (const double top, const double left,
const double bottom, const double right)
{
m_paperBorderTop=top;
m_paperBorderLeft=left;
m_paperBorderBottom=bottom;
m_paperBorderRight=right;
return true;
}
bool AbiWordWorker::doCloseHead(void)
{
if (!m_pagesize.isEmpty())
{
*m_streamOut << m_pagesize;
}
return true;
}
bool AbiWordWorker::doOpenSpellCheckIgnoreList (void)
{
kdDebug(30506) << "AbiWordWorker::doOpenSpellCheckIgnoreList" << endl;
m_inIgnoreWords=false; // reset
return true;
}
bool AbiWordWorker::doCloseSpellCheckIgnoreList (void)
{
kdDebug(30506) << "AbiWordWorker::doCloseSpellCheckIgnoreList" << endl;
if (m_inIgnoreWords)
*m_streamOut << "\n";
return true;
}
bool AbiWordWorker::doFullSpellCheckIgnoreWord (const TQString& ignoreword)
{
kdDebug(30506) << "AbiWordWorker::doFullSpellCheckIgnoreWord: " << ignoreword << endl;
if (!m_inIgnoreWords)
{
*m_streamOut << "\n";
m_inIgnoreWords=true;
}
*m_streamOut << " " << ignoreword << "\n";
return true;
}
// Similar to TQDateTime::toString, but guaranteed *not* to be translated
TQString AbiWordWorker::transformToTextDate(const TQDateTime& dt)
{
if (dt.isValid())
{
TQString result;
const TQDate date(dt.date());
const char* dayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
const int dow = date.dayOfWeek() - 1;
if ((dow<0) || (dow>6))
result += "Mon"; // Unknown day, rename it Monday.
else
result += dayName[dow];
result += ' ';
const char* monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
const int month = date.month() - 1;
if ((month<0) || (month>11))
result += "Jan"; // Unknown month, rename it January
else
result += monthName[month];
result += ' ';
TQString temp;
temp = "00";
temp += TQString::number(date.day(), 10);
result += temp.right(2);
result += ' ';
const TQTime time(dt.time());
temp = "00";
temp += TQString::number(time.hour(), 10);
result += temp.right(2);
result += ':';
temp = "00";
temp += TQString::number(time.minute(), 10);
result += temp.right(2);
result += ':';
temp = "00";
temp += TQString::number(time.second(), 10);
result += temp.right(2);
result += ' ';
temp = "0000";
temp += TQString::number(date.year(), 10);
result += temp.right(4);
return result;
}
else
{
// Invalid, so give back 1970-01-01
return "Thu Jan 01 00:00:00 1970";
}
}
bool AbiWordWorker::doFullDocumentInfo(const KWEFDocumentInfo& docInfo)
{
m_docInfo=docInfo;
*m_streamOut << "\n";
// First all Dublin Core data
*m_streamOut << "application/x-abiword\n";
if (!m_docInfo.title.isEmpty())
{
*m_streamOut << "" << escapeAbiWordText(m_docInfo.title) << "\n";
}
if (!m_docInfo.abstract.isEmpty())
{
*m_streamOut << "" << escapeAbiWordText(m_docInfo.abstract) << "\n";
}
if ( !m_docInfo.keywords.isEmpty() )
{
*m_streamOut << "" << escapeAbiWordText(m_docInfo.keywords) << "\n";
}
if ( !m_docInfo.subject.isEmpty() )
{
*m_streamOut << "" << escapeAbiWordText(m_docInfo.subject) << "\n";
}
// Say who we are (with the CVS revision number) in case we have a bug in our filter output!
*m_streamOut << "KWord Export Filter";
TQString strVersion("$Revision: 508787 $");
// Remove the dollar signs
// (We don't want that the version number changes if the AbiWord file is itself put in a CVS storage.)
*m_streamOut << strVersion.mid(10).remove('$');
*m_streamOut << "\n";
TQDateTime now (TQDateTime::currentDateTime(Qt::UTC)); // current time in UTC
*m_streamOut << ""
<< escapeAbiWordText(transformToTextDate(now))
<< "\n";
*m_streamOut << "\n";
return true;
}
// ==========================================================================================
ABIWORDExport::ABIWORDExport(KoFilter */*parent*/, const char */*name*/, const TQStringList &) :
KoFilter() {
}
KoFilter::ConversionStatus ABIWORDExport::convert( const TQCString& from, const TQCString& to )
{
if ( to != "application/x-abiword" || from != "application/x-kword" )
{
return KoFilter::NotImplemented;
}
// We need KimageIO's help in AbiWordWorker::convertUnknownImage
KImageIO::registerFormats();
AbiWordWorker* worker=new AbiWordWorker();
if (!worker)
{
kdError(30506) << "Cannot create Worker! Aborting!" << endl;
return KoFilter::StupidError;
}
KWEFKWordLeader* leader=new KWEFKWordLeader(worker);
if (!leader)
{
kdError(30506) << "Cannot create Worker! Aborting!" << endl;
delete worker;
return KoFilter::StupidError;
}
KoFilter::ConversionStatus result=leader->convert(m_chain,from,to);
delete leader;
delete worker;
return result;
}