|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2001, 2002, 2003, 2004 Nicolas GOUTTE <goutte@kde.org>
|
|
|
|
|
|
|
|
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 <reggie@kde.org>
|
|
|
|
Copyright (c) 2000 ID-PRO Deutschland GmbH. All rights reserved.
|
|
|
|
Contact: Wolf-Michael Bolle <Bolle@ID-PRO.de>
|
|
|
|
|
|
|
|
The old file was licensed under the terms of the GNU Library General Public
|
|
|
|
License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <tqmap.h>
|
|
|
|
#include <tqiodevice.h>
|
|
|
|
#include <tqtextstream.h>
|
|
|
|
#include <tqdom.h>
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kmdcodec.h>
|
|
|
|
#include <kfilterdev.h>
|
|
|
|
#include <kgenericfactory.h>
|
|
|
|
#include <kimageio.h>
|
|
|
|
|
|
|
|
#include <KoPageLayout.h>
|
|
|
|
#include <KoFilterChain.h>
|
|
|
|
#include <KoPictureKey.h>
|
|
|
|
|
|
|
|
#include <KWEFStructures.h>
|
|
|
|
#include <KWEFUtil.h>
|
|
|
|
#include <KWEFBaseWorker.h>
|
|
|
|
#include <KWEFKWordLeader.h>
|
|
|
|
|
|
|
|
#include <abiwordexport.h>
|
|
|
|
#include <abiwordexport.moc>
|
|
|
|
|
|
|
|
class ABIWORDExportFactory : KGenericFactory<ABIWORDExport, KoFilter>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ABIWORDExportFactory(void) : KGenericFactory<ABIWORDExport, KoFilter> ("kwordabiwordexport")
|
|
|
|
{}
|
|
|
|
protected:
|
|
|
|
virtual void setupTranslations( void )
|
|
|
|
{
|
|
|
|
KGlobal::locale()->insertCatalogue( "kofficefilters" );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
K_EXPORT_COMPONENT_FACTORY( libabiwordexport, ABIWORDExportFactory() )
|
|
|
|
|
|
|
|
class StyleMap : public TQMap<TQString,LayoutData>
|
|
|
|
{
|
|
|
|
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 <section>
|
|
|
|
virtual bool doCloseTextFrameSet(void); // AbiWord's </section>
|
|
|
|
virtual bool doFullPaperFormat(const int format,
|
|
|
|
const double width, const double height, const int orientation); // Calc AbiWord's <papersize>
|
|
|
|
virtual bool doFullPaperBorders (const double top, const double left,
|
|
|
|
const double bottom, const double right); // Like KWord's <PAPERBORDERS>
|
|
|
|
virtual bool doCloseHead(void); // Write <papersize>
|
|
|
|
virtual bool doOpenStyles(void); // AbiWord's <styles>
|
|
|
|
virtual bool doCloseStyles(void); // AbiWord's </styles>
|
|
|
|
virtual bool doFullDefineStyle(LayoutData& tqlayout); // AbiWord's <s></s>
|
|
|
|
virtual bool doOpenSpellCheckIgnoreList (void); // AbiWord's <ignorewords>
|
|
|
|
virtual bool doCloseSpellCheckIgnoreList (void); // AbiWord's </ignorewords>
|
|
|
|
virtual bool doFullSpellCheckIgnoreWord (const TQString& ignoreword); // AbiWord's <iw>
|
|
|
|
virtual bool doFullDocumentInfo(const KWEFDocumentInfo& docInfo); // AbiWord's <metadata>
|
|
|
|
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 <pagesize> tag
|
|
|
|
TQMap<TQString,KoPictureKey> m_mapPictureData;
|
|
|
|
StyleMap m_styleMap;
|
|
|
|
double m_paperBorderTop,m_paperBorderLeft,m_paperBorderBottom,m_paperBorderRight;
|
|
|
|
bool m_inIgnoreWords; // true if <ignorewords> 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.tqfindRev('.');
|
|
|
|
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 << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
|
|
|
|
|
|
|
// NOTE: AbiWord CVS 2002-02-?? has a new DOCTYPE
|
|
|
|
*m_streamOut << "<!DOCTYPE abiword PUBLIC \"-//ABISOURCE//DTD AWML 1.0 Strict//EN\"";
|
|
|
|
*m_streamOut << " \"http://www.abisource.com/awml.dtd\">\n";
|
|
|
|
|
|
|
|
// First magic: "<abiword"
|
|
|
|
*m_streamOut << "<abiword";
|
|
|
|
// AbiWord CVS 2002-02-23 defines a default namespace.
|
|
|
|
*m_streamOut << " xmlns=\"http://www.abisource.com/awml.dtd\"";
|
|
|
|
// As we do not use xmlns:awml, do we need to define it?
|
|
|
|
// *m_streamOut << " xmlns:awml=\"http://www.abisource.com/awml.dtd\"";
|
|
|
|
*m_streamOut << " xmlns:xlink=\"http://www.w3.org/1999/xlink\"";
|
|
|
|
// AbiWord CVS 2002-02-22 defines other namespaces, which we are not using.
|
|
|
|
// AbiWord CVS 2002-12-23 has no fileformat attribute anymore
|
|
|
|
// ### TODO: add document language and document direction of writing.
|
|
|
|
*m_streamOut << " xml:space=\"preserve\" version=\"1.1.2\" template=\"false\" styles=\"unlocked\">\n";
|
|
|
|
// Second magic: "<!-- This file is an AbiWord document."
|
|
|
|
// TODO/FIXME: write as much spaces as AbiWord does for the following line.
|
|
|
|
*m_streamOut << "<!-- This file is an AbiWord document. -->\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.tqfindRev(".");
|
|
|
|
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 << "<d name=\"" << keyName << "\""
|
|
|
|
<< " base64=\"yes\""
|
|
|
|
<< " mime=\"image/png\">\n";
|
|
|
|
|
|
|
|
TQCString base64=KCodecs::base64Encode(image,true);
|
|
|
|
|
|
|
|
*m_streamOut << base64 << "\n"; // TQCString is taken as Latin1 by TQTextStream
|
|
|
|
|
|
|
|
*m_streamOut << "</d>\n";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdWarning(30506) << "Unable to load picture: " << koStoreName << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbiWordWorker::doCloseDocument(void)
|
|
|
|
{
|
|
|
|
// Before writing the <data> element,
|
|
|
|
// we must be sure that we have data and that we can retrieve it.
|
|
|
|
|
|
|
|
if (m_kwordLeader && !m_mapPictureData.isEmpty())
|
|
|
|
{
|
|
|
|
*m_streamOut << "<data>\n";
|
|
|
|
|
|
|
|
TQMap<TQString,KoPictureKey>::ConstIterator it;
|
|
|
|
TQMap<TQString,KoPictureKey>::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 << "</data>\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
*m_streamOut << "</abiword>\n"; //Close the file for XML
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbiWordWorker::doOpenTextFrameSet(void)
|
|
|
|
{
|
|
|
|
*m_streamOut << "<section props=\"";
|
|
|
|
*m_streamOut << "page-margin-top: ";
|
|
|
|
*m_streamOut << m_paperBorderTop;
|
|
|
|
*m_streamOut << "pt; ";
|
|
|
|
*m_streamOut << "page-margin-left: ";
|
|
|
|
*m_streamOut << m_paperBorderLeft;
|
|
|
|
*m_streamOut << "pt; ";
|
|
|
|
*m_streamOut << "page-margin-bottom: ";
|
|
|
|
*m_streamOut << m_paperBorderBottom;
|
|
|
|
*m_streamOut << "pt; ";
|
|
|
|
*m_streamOut << "page-margin-right: ";
|
|
|
|
*m_streamOut << m_paperBorderRight;
|
|
|
|
*m_streamOut << "pt"; // Last one, so no semi-comma
|
|
|
|
*m_streamOut << "\">\n";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbiWordWorker::doCloseTextFrameSet(void)
|
|
|
|
{
|
|
|
|
*m_streamOut << "</section>\n";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbiWordWorker::doOpenStyles(void)
|
|
|
|
{
|
|
|
|
*m_streamOut << "<styles>\n";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbiWordWorker::doCloseStyles(void)
|
|
|
|
{
|
|
|
|
*m_streamOut << "</styles>\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 << "</p>\n"; // Close previous paragraph ### TODO: do it correctly like for HTML
|
|
|
|
*m_streamOut << "<table>\n";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
TQValueList<TableCell>::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 << "<cell props=\"";
|
|
|
|
*m_streamOut << "left-attach:" << (*itCell).col << "; ";
|
|
|
|
*m_streamOut << "right-attach:" << (*itCell).col + 1 << "; ";
|
|
|
|
*m_streamOut << "top-attach:" << (*itCell).row << "; ";
|
|
|
|
*m_streamOut << "bot-attach:" << (*itCell).row + 1;
|
|
|
|
*m_streamOut << "\">\n";
|
|
|
|
#endif
|
|
|
|
if (!doFullAllParagraphs(*(*itCell).paraList))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
*m_streamOut << "</cell>\n";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
*m_streamOut << "</table>\n";
|
|
|
|
*m_streamOut << "<p>\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 << "<image dataid=\"" << anchor.picture.key.filename() << "\"";
|
|
|
|
*m_streamOut << " props= \"height:" << height << "pt;width:" << width << "pt\"";
|
|
|
|
*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.tqfindRev(";");
|
|
|
|
|
|
|
|
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.tqfind(TQChar(10)))>-1)
|
|
|
|
{
|
|
|
|
partialText.tqreplace(pos,1,"<br/>");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (formatData.text.missing)
|
|
|
|
{
|
|
|
|
// It's just normal text, so we do not need a <c> element!
|
|
|
|
*m_streamOut << partialText;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Text with properties, so use a <c> element!
|
|
|
|
*m_streamOut << "<c";
|
|
|
|
writeAbiProps(formatLayout,formatData.text);
|
|
|
|
*m_streamOut << ">" << partialText << "</c>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 << "<field type=\"date_ntdfl\"";
|
|
|
|
writeAbiProps(formatLayout,formatData.text);
|
|
|
|
*m_streamOut << "/>";
|
|
|
|
}
|
|
|
|
else if (2==formatData.variable.m_type)
|
|
|
|
{
|
|
|
|
// As AbiWord's field is inflexible, we cannot make the time custom
|
|
|
|
*m_streamOut << "<field type=\"time\"";
|
|
|
|
writeAbiProps(formatLayout,formatData.text);
|
|
|
|
*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 << "<field type=\"" << strFieldType <<"\"";
|
|
|
|
writeAbiProps(formatLayout,formatData.text);
|
|
|
|
*m_streamOut << "/>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (9==formatData.variable.m_type)
|
|
|
|
{
|
|
|
|
// A link
|
|
|
|
*m_streamOut << "<a xlink:href=\""
|
|
|
|
<< escapeAbiWordText(formatData.variable.getHrefName())
|
|
|
|
<< "\"><c"; // In AbiWord, an anchor <a> has always a <c> child
|
|
|
|
writeAbiProps(formatLayout,formatData.text);
|
|
|
|
*m_streamOut << ">"
|
|
|
|
<< escapeAbiWordText(formatData.variable.getLinkName())
|
|
|
|
<< "</c></a>";
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
else if (11==(*paraFormatDataIt).variable.m_type)
|
|
|
|
{
|
|
|
|
// Footnote
|
|
|
|
TQString value = (*paraFormatDataIt).variable.getFootnoteValue();
|
|
|
|
bool automatic = (*paraFormatDataIt).variable.getFootnoteAuto();
|
|
|
|
TQValueList<ParaData> *paraList = (*paraFormatDataIt).variable.getFootnotePara();
|
|
|
|
if( paraList )
|
|
|
|
{
|
|
|
|
TQString fstr;
|
|
|
|
TQValueList<ParaData>::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) // <IMAGE> or <PICTURE>
|
|
|
|
|| (5==formatData.frameAnchor.type) ) // <CLIPART>
|
|
|
|
{
|
|
|
|
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.tqalignment!=tqlayout.tqalignment))
|
|
|
|
{
|
|
|
|
// Check if the current tqalignment is a valid one for AbiWord.
|
|
|
|
if ((tqlayout.tqalignment == "left") || (tqlayout.tqalignment == "right")
|
|
|
|
|| (tqlayout.tqalignment == "center") || (tqlayout.tqalignment == "justify"))
|
|
|
|
{
|
|
|
|
props += "text-align:";
|
|
|
|
props += tqlayout.tqalignment;
|
|
|
|
props += "; ";
|
|
|
|
}
|
|
|
|
else if (tqlayout.tqalignment == "auto")
|
|
|
|
{
|
|
|
|
// We assume a left tqalignment as AbiWord is not really bi-di (and this filter even less.)
|
|
|
|
props += "text-align:left; ";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kdWarning(30506) << "Unknown tqalignment: " << tqlayout.tqalignment << 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; ").tqarg(tqlayout.indentLeft);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((tqlayout.indentRight>=0.0)
|
|
|
|
&& (force || (layoutOrigin.indentRight!=tqlayout.indentRight)))
|
|
|
|
{
|
|
|
|
props += TQString("margin-right:%1pt; ").tqarg(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; ").tqarg(tqlayout.marginBottom);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((tqlayout.marginTop>=0.0)
|
|
|
|
&& ( force || ( layoutOrigin.marginTop != tqlayout.marginTop ) ) )
|
|
|
|
{
|
|
|
|
props += TQString("margin-top:%1pt; ").tqarg(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 <FORMAT> 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 << "<p";
|
|
|
|
if (!style.isEmpty())
|
|
|
|
{
|
|
|
|
*m_streamOut << " style=\"" << EscapeXmlText(style,true,true) << "\"";
|
|
|
|
}
|
|
|
|
if (!props.isEmpty())
|
|
|
|
{
|
|
|
|
// Find the last semi-comma
|
|
|
|
// Note: as in CSS2, semi-commas only separates instructions (like in PASCAL) and do not terminate them (like in C)
|
|
|
|
const int result=props.tqfindRev(";");
|
|
|
|
if (result>=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 << "<pbr/>";
|
|
|
|
}
|
|
|
|
|
|
|
|
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 << "<pbr/>";
|
|
|
|
}
|
|
|
|
|
|
|
|
*m_streamOut << "</p>\n";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbiWordWorker::doFullDefineStyle(LayoutData& tqlayout)
|
|
|
|
{
|
|
|
|
//Register style in the style map
|
|
|
|
m_styleMap[tqlayout.styleName]=tqlayout;
|
|
|
|
|
|
|
|
*m_streamOut << "<s";
|
|
|
|
|
|
|
|
// TODO: cook the style name to the standard style names in AbiWord
|
|
|
|
*m_streamOut << " name=\"" << EscapeXmlText(tqlayout.styleName,true,true) << "\"";
|
|
|
|
*m_streamOut << " followedby=\"" << EscapeXmlText(tqlayout.styleFollowing,true,true) << "\"";
|
|
|
|
|
|
|
|
if ( (tqlayout.counter.numbering == CounterData::NUM_CHAPTER)
|
|
|
|
&& (tqlayout.counter.depth<10) )
|
|
|
|
{
|
|
|
|
*m_streamOut << " level=\"";
|
|
|
|
*m_streamOut << TQString::number(tqlayout.counter.depth+1,10);
|
|
|
|
*m_streamOut << "\"";
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString abiprops=layoutToCss(tqlayout,tqlayout,true);
|
|
|
|
|
|
|
|
const int result=abiprops.tqfindRev(";");
|
|
|
|
if (result>=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 = "<pagesize ";
|
|
|
|
|
|
|
|
switch (format)
|
|
|
|
{
|
|
|
|
// ISO A formats
|
|
|
|
case PG_DIN_A0: // ISO A0
|
|
|
|
case PG_DIN_A1: // ISO A1
|
|
|
|
case PG_DIN_A2: // ISO A2
|
|
|
|
case PG_DIN_A3: // ISO A3
|
|
|
|
case PG_DIN_A4: // ISO A4
|
|
|
|
case PG_DIN_A5: // ISO A5
|
|
|
|
case PG_DIN_A6: // ISO A6
|
|
|
|
// ISO B formats
|
|
|
|
case PG_DIN_B0: // ISO B0
|
|
|
|
case PG_DIN_B1: // ISO B1
|
|
|
|
case PG_DIN_B2: // ISO B2
|
|
|
|
case PG_DIN_B3: // ISO B3
|
|
|
|
case PG_DIN_B4: // ISO B4
|
|
|
|
case PG_DIN_B5: // ISO B5
|
|
|
|
case PG_DIN_B6: // ISO B6
|
|
|
|
// American formats
|
|
|
|
case PG_US_LETTER: // US Letter
|
|
|
|
case PG_US_LEGAL: // US Legal
|
|
|
|
{
|
|
|
|
TQString pagetype=KoPageFormat::formatString(KoFormat(format));
|
|
|
|
outputText+="pagetype=\"";
|
|
|
|
outputText+=pagetype;
|
|
|
|
|
|
|
|
TQString strWidth, strHeight, strUnits;
|
|
|
|
KWEFUtil::GetNativePaperFormat(format, strWidth, strHeight, strUnits);
|
|
|
|
outputText+="\" width=\"";
|
|
|
|
outputText+=strWidth;
|
|
|
|
outputText+="\" height=\"";
|
|
|
|
outputText+=strHeight;
|
|
|
|
outputText+="\" units=\"";
|
|
|
|
outputText+=strUnits;
|
|
|
|
outputText+="\" ";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PG_US_EXECUTIVE: // US Executive (does not exists in AbiWord!)
|
|
|
|
{
|
|
|
|
// FIXME/TODO: AbiWord (CVS 2001-04-25) seems not to like custom formats, so avoid them for now!
|
|
|
|
#if 0
|
|
|
|
outputText += "pagetype=\"Custom\" width=\"7.5\" height=\"10.0\" units=\"inch\" ";
|
|
|
|
#else
|
|
|
|
// As replacement, use the slightly bigger "letter" format.
|
|
|
|
outputText += "pagetype=\"Letter\" width=\"8.5\" height=\"11.0\" units=\"inch\" ";
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Other format not supported yet by AbiWord CVS 2001-04-25)
|
|
|
|
case PG_DIN_A7: // ISO A7
|
|
|
|
case PG_DIN_A8: // ISO A8
|
|
|
|
case PG_DIN_A9: // ISO A9
|
|
|
|
case PG_DIN_B10: // ISO B10
|
|
|
|
// Other formats
|
|
|
|
case PG_SCREEN: // Screen
|
|
|
|
case PG_CUSTOM: // Custom
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
// FIXME/TODO: AbiWord (CVS 2001-04-25) seems not to like custom formats, so avoid them for now!
|
|
|
|
if ((width<=1.0) || (height<=1.0) || true)
|
|
|
|
{
|
|
|
|
// Height or width is ridiculous, so assume A4 format
|
|
|
|
outputText += "pagetype=\"A4\" width=\"21.0\" height=\"29.7\" units=\"cm\" ";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // We prefer to use inches, as to limit rounding errors (page size is in points!)
|
|
|
|
outputText += TQString("pagetype=\"Custom\" width=\"%1\" height=\"%2\" units=\"inch\" ").tqarg(width/72.0).tqarg(height/72.0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
outputText += "orientation=\"";
|
|
|
|
if (1==orientation)
|
|
|
|
{
|
|
|
|
outputText += "landscape";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
outputText += "portrait";
|
|
|
|
}
|
|
|
|
outputText += "\" ";
|
|
|
|
|
|
|
|
outputText += "page-scale=\"1.0\"/>\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 << "</ignorewords>\n";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AbiWordWorker::doFullSpellCheckIgnoreWord (const TQString& ignoreword)
|
|
|
|
{
|
|
|
|
kdDebug(30506) << "AbiWordWorker::doFullSpellCheckIgnoreWord: " << ignoreword << endl;
|
|
|
|
if (!m_inIgnoreWords)
|
|
|
|
{
|
|
|
|
*m_streamOut << "<ignorewords>\n";
|
|
|
|
m_inIgnoreWords=true;
|
|
|
|
}
|
|
|
|
*m_streamOut << " <iw>" << ignoreword << "</iw>\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 << "<metadata>\n";
|
|
|
|
|
|
|
|
// First all Dublin Core data
|
|
|
|
*m_streamOut << "<m key=\"dc.format\">application/x-abiword</m>\n";
|
|
|
|
if (!m_docInfo.title.isEmpty())
|
|
|
|
{
|
|
|
|
*m_streamOut << "<m key=\"dc.title\">" << escapeAbiWordText(m_docInfo.title) << "</m>\n";
|
|
|
|
}
|
|
|
|
if (!m_docInfo.abstract.isEmpty())
|
|
|
|
{
|
|
|
|
*m_streamOut << "<m key=\"dc.description\">" << escapeAbiWordText(m_docInfo.abstract) << "</m>\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !m_docInfo.keywords.isEmpty() )
|
|
|
|
{
|
|
|
|
*m_streamOut << "<m key=\"abiword.keywords\">" << escapeAbiWordText(m_docInfo.keywords) << "</m>\n";
|
|
|
|
}
|
|
|
|
if ( !m_docInfo.subject.isEmpty() )
|
|
|
|
{
|
|
|
|
*m_streamOut << "<m key=\"dc.subject\">" << escapeAbiWordText(m_docInfo.subject) << "</m>\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Say who we are (with the CVS revision number) in case we have a bug in our filter output!
|
|
|
|
*m_streamOut << "<m key=\"abiword.generator\">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 << "</m>\n";
|
|
|
|
|
|
|
|
TQDateTime now (TQDateTime::tqcurrentDateTime(Qt::UTC)); // current time in UTC
|
|
|
|
*m_streamOut << "<m key=\"abiword.date_last_changed\">"
|
|
|
|
<< escapeAbiWordText(transformToTextDate(now))
|
|
|
|
<< "</m>\n";
|
|
|
|
|
|
|
|
*m_streamOut << "</metadata>\n";
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ==========================================================================================
|
|
|
|
|
|
|
|
ABIWORDExport::ABIWORDExport(KoFilter */*tqparent*/, const char */*name*/, const TQStringList &) :
|
|
|
|
KoFilter() {
|
|
|
|
}
|
|
|
|
|
|
|
|
KoFilter::ConversiontqStatus 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::ConversiontqStatus result=leader->convert(m_chain,from,to);
|
|
|
|
|
|
|
|
delete leader;
|
|
|
|
delete worker;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|