You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1976 lines
54 KiB
1976 lines
54 KiB
/* This file is part of the KDE project
|
|
Copyright (C) 2002-2003 Clarence Dang <dang@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 Version 2 as published by the Free Software Foundation.
|
|
|
|
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 Version 2 for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
Version 2 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.
|
|
*/
|
|
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <tqbuffer.h>
|
|
#include <tqcstring.h>
|
|
#include <tqfile.h>
|
|
#include <tqfont.h>
|
|
#include <tqimage.h>
|
|
#include <tqtextcodec.h>
|
|
#include <tqvaluelist.h>
|
|
#include <tqvaluestack.h>
|
|
|
|
#include <kdebug.h>
|
|
#include <kgenericfactory.h>
|
|
|
|
#include <KoFilterChain.h>
|
|
#include <kowmfpaint.h>
|
|
|
|
#include <KWEFStructures.h>
|
|
#include <KWEFBaseWorker.h>
|
|
#include <KWEFKWordLeader.h>
|
|
|
|
#include "libmswrite.h"
|
|
|
|
#include "mswriteexport.h"
|
|
|
|
|
|
class MSWriteExportFactory : KGenericFactory <MSWriteExport, KoFilter>
|
|
{
|
|
public:
|
|
MSWriteExportFactory () : KGenericFactory <MSWriteExport, KoFilter> ("kwordmswriteexport")
|
|
{
|
|
}
|
|
|
|
protected:
|
|
virtual void setupTranslations (void)
|
|
{
|
|
TDEGlobal::locale()->insertCatalogue ("kofficefilters");
|
|
}
|
|
};
|
|
|
|
K_EXPORT_COMPONENT_FACTORY (libmswriteexport, MSWriteExportFactory ())
|
|
|
|
|
|
class WRIDevice : public MSWrite::Device
|
|
{
|
|
private:
|
|
FILE *m_outfp;
|
|
long m_outfp_pos, m_outfp_eof;
|
|
|
|
public:
|
|
WRIDevice () : m_outfp (NULL), m_outfp_pos (0), m_outfp_eof (0)
|
|
{
|
|
}
|
|
|
|
virtual ~WRIDevice ()
|
|
{
|
|
closeFile ();
|
|
}
|
|
|
|
bool openFile (const char *fileName)
|
|
{
|
|
m_outfp = fopen (fileName, "wb");
|
|
if (!m_outfp)
|
|
{
|
|
error (MSWrite::Error::FileError, "could not open file for writing\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool closeFile (void)
|
|
{
|
|
if (m_outfp)
|
|
{
|
|
if (fclose (m_outfp))
|
|
{
|
|
error (MSWrite::Error::FileError, "could not close output file\n");
|
|
return false;
|
|
}
|
|
|
|
m_outfp = NULL;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool read (MSWrite::Byte *, const MSWrite::DWord)
|
|
{
|
|
error (MSWrite::Error::InternalError, "reading from an output file?\n");
|
|
return false;
|
|
}
|
|
|
|
bool write (const MSWrite::Byte *buf, const MSWrite::DWord numBytes)
|
|
{
|
|
size_t cwrite = fwrite (buf, 1, numBytes, m_outfp);
|
|
if (cwrite != numBytes)
|
|
{
|
|
error (MSWrite::Error::FileError, "could not write to output file\n");
|
|
return false;
|
|
}
|
|
|
|
// keep track of where we are up to in the output file and where EOF is
|
|
m_outfp_pos += numBytes;
|
|
if (m_outfp_pos > m_outfp_eof)
|
|
m_outfp_eof = m_outfp_pos;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool seek (const long offset, const int whence)
|
|
{
|
|
long absloc;
|
|
switch (whence)
|
|
{
|
|
case SEEK_SET:
|
|
absloc = offset;
|
|
break;
|
|
case SEEK_CUR:
|
|
absloc = m_outfp_pos + offset;
|
|
break;
|
|
case SEEK_END:
|
|
absloc = m_outfp_eof + offset;
|
|
break;
|
|
default:
|
|
error (MSWrite::Error::InternalError, "invalid whence passed to WRIDevice::seek\n");
|
|
return false;
|
|
}
|
|
|
|
if (absloc > m_outfp_eof)
|
|
{
|
|
kdDebug (30509) << "Want to seek to " << absloc
|
|
<< " but EOF is at " << m_outfp_eof
|
|
<< "; so writing " << absloc - m_outfp_eof
|
|
<< " zeros" << endl;
|
|
|
|
if (fseek (m_outfp, m_outfp_eof, SEEK_SET))
|
|
{
|
|
error (MSWrite::Error::FileError,
|
|
"could not seek to EOF in output file\n");
|
|
return false;
|
|
}
|
|
|
|
MSWrite::Byte *zero = new MSWrite::Byte [absloc - m_outfp_eof];
|
|
if (!zero)
|
|
{
|
|
error (MSWrite::Error::OutOfMemory,
|
|
"could not allocate memory for zeros\n");
|
|
return false;
|
|
}
|
|
memset (zero, 0, absloc - m_outfp_eof);
|
|
if (!write (zero, absloc - m_outfp_eof)) return false;
|
|
delete [] zero;
|
|
|
|
m_outfp_eof = absloc;
|
|
m_outfp_pos = absloc;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (fseek (m_outfp, offset, whence) == 0)
|
|
{
|
|
m_outfp_pos = absloc;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
error (MSWrite::Error::FileError, "could not seek output file\n");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
long tell (void)
|
|
{
|
|
return ftell (m_outfp);
|
|
}
|
|
|
|
void debug (const char *s)
|
|
{
|
|
kdDebug (30509) << s;
|
|
}
|
|
void debug (const int i)
|
|
{
|
|
kdDebug (30509) << i;
|
|
}
|
|
void error (const int errorCode, const char *message,
|
|
const char * /*file*/ = "", const int /*lineno*/ = 0,
|
|
MSWrite::DWord /*token*/ = MSWrite::Device::NoToken)
|
|
{
|
|
if (errorCode == MSWrite::Error::Warn)
|
|
kdWarning (30509) << message;
|
|
else
|
|
{
|
|
m_error = errorCode;
|
|
kdError (30509) << message;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
class KWordMSWriteWorker : public KWEFBaseWorker
|
|
{
|
|
private:
|
|
WRIDevice *m_device;
|
|
MSWrite::InternalGenerator *m_generator;
|
|
|
|
MSWrite::PageLayout m_pageLayout;
|
|
MSWrite::Word m_pageHeight, m_pageWidth,
|
|
m_topMargin, m_leftMargin, m_bottomMargin, m_rightMargin;
|
|
MSWrite::Word m_pageNumberStart;
|
|
|
|
// for charset conversion
|
|
TQTextCodec *m_codec;
|
|
TQTextEncoder *m_encoder;
|
|
|
|
TQValueList <HeaderData> m_headerData;
|
|
TQValueList <FooterData> m_footerData;
|
|
|
|
int m_headerType, m_footerType;
|
|
bool m_hasHeader, m_isHeaderOnFirstPage;
|
|
bool m_hasFooter, m_isFooterOnFirstPage;
|
|
|
|
enum inWhatPossiblities
|
|
{
|
|
Nothing,
|
|
Header,
|
|
Footer,
|
|
Body
|
|
} m_inWhat;
|
|
|
|
public:
|
|
KWordMSWriteWorker () : m_device (NULL), m_generator (NULL),
|
|
m_pageHeight (0xFFFF), m_pageWidth (0xFFFF),
|
|
m_topMargin (0xFFFF), m_leftMargin (0xFFFF),
|
|
m_bottomMargin (0xFFFF), m_rightMargin (0xFFFF),
|
|
m_encoder (NULL),
|
|
m_hasHeader (false), m_hasFooter (false),
|
|
m_inWhat (Nothing)
|
|
{
|
|
// just select windows-1252 until the "Select Encoding" dialog works
|
|
m_codec = TQTextCodec::codecForName ("CP 1252");
|
|
|
|
if (m_codec)
|
|
m_encoder = m_codec->makeEncoder();
|
|
else
|
|
kdWarning (30509) << "Cannot convert to Win Charset!" << endl;
|
|
|
|
m_device = new WRIDevice;
|
|
if (!m_device)
|
|
{
|
|
kdError (30509) << "Could not allocate memory for Device" << endl;
|
|
return;
|
|
}
|
|
|
|
m_generator = new MSWrite::InternalGenerator;
|
|
if (!m_generator)
|
|
{
|
|
m_device->error (MSWrite::Error::OutOfMemory, "could not allocate memory for InternalGenerator\n");
|
|
return;
|
|
}
|
|
|
|
m_generator->setDevice (m_device);
|
|
}
|
|
|
|
virtual ~KWordMSWriteWorker ()
|
|
{
|
|
delete m_generator;
|
|
delete m_device;
|
|
delete m_encoder;
|
|
}
|
|
|
|
int getError (void) const
|
|
{
|
|
return m_device->bad ();
|
|
}
|
|
|
|
bool doOpenFile (const TQString &outFileName, const TQString &)
|
|
{
|
|
// constructor failed?
|
|
if (!m_device || !m_generator)
|
|
return false;
|
|
|
|
if (!m_device->openFile (TQFile::encodeName (outFileName))) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool doCloseFile (void)
|
|
{
|
|
if (!m_device->closeFile ()) return false;
|
|
return true;
|
|
}
|
|
|
|
bool doOpenDocument (void)
|
|
{
|
|
kdDebug (30509) << "doOpenDocument ()" << endl;
|
|
|
|
// We can't open the document here because we don't yet have
|
|
// PageLayout * as doFullPaperFormat() and doFullPaperBorders()
|
|
// haven't been called yet.
|
|
//
|
|
// doTrulyOpenDocument truly opens the document and is called by
|
|
// doOpenBody()
|
|
|
|
return true;
|
|
}
|
|
|
|
bool doTrulyOpenDocument (void)
|
|
{
|
|
// TODO: Write's UI doesn't allow the user to change Height or Width so
|
|
// setting it here might not be a good idea...
|
|
m_pageLayout.setPageHeight (m_pageHeight);
|
|
m_pageLayout.setPageWidth (m_pageWidth);
|
|
m_pageLayout.setPageNumberStart (m_pageNumberStart);
|
|
m_pageLayout.setTopMargin (m_topMargin);
|
|
m_pageLayout.setLeftMargin (m_leftMargin);
|
|
m_pageLayout.setTextHeight (m_pageHeight - m_topMargin - m_bottomMargin);
|
|
m_pageLayout.setTextWidth (m_pageWidth - m_leftMargin - m_rightMargin);
|
|
|
|
// TODO: libexport
|
|
// headerFromTop
|
|
// footerFromTop
|
|
|
|
if (!m_generator->writeDocumentBegin (MSWrite::Format::Write_3_0,
|
|
&m_pageLayout)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool doCloseDocument (void)
|
|
{
|
|
kdDebug (30509) << "doCloseDocument ()" << endl;
|
|
|
|
if (!m_generator->writeDocumentEnd (MSWrite::Format::Write_3_0,
|
|
&m_pageLayout)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool doFullPaperFormat (const int format,
|
|
const double width, const double height,
|
|
const int orientation)
|
|
{
|
|
kdDebug (30509) << "doFullPaperFormat ("
|
|
<< format << ", "
|
|
<< width << ", "
|
|
<< height << ", "
|
|
<< orientation << ")" << endl;
|
|
|
|
// TODO: does "format" or "orientation" matter?
|
|
|
|
m_pageHeight = MSWrite::Word (Point2Twip (height));
|
|
m_pageWidth = MSWrite::Word (Point2Twip (width));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool doFullPaperBorders (const double top, const double left,
|
|
const double bottom, const double right)
|
|
{
|
|
kdDebug (30509) << "doFullPaperBorders ("
|
|
<< top << ", "
|
|
<< left << ", "
|
|
<< bottom << ", "
|
|
<< right << ")" << endl;
|
|
|
|
m_topMargin = MSWrite::Word (Point2Twip (top));
|
|
m_leftMargin = MSWrite::Word (Point2Twip (left));
|
|
m_bottomMargin = MSWrite::Word (Point2Twip (bottom));
|
|
m_rightMargin = MSWrite::Word (Point2Twip (right));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool doVariableSettings (const VariableSettingsData &varSettings)
|
|
{
|
|
m_pageNumberStart = MSWrite::Word (varSettings.startingPageNumber);
|
|
|
|
kdDebug (30509) << "doVariableSettings pageNumberStart="
|
|
<< m_pageNumberStart << endl;
|
|
return true;
|
|
}
|
|
|
|
// In Write the header/footer must be the same for every page except that
|
|
// you can choose to not display it on the first page
|
|
//
|
|
// /*This filter aims to be as lossless as possible so if we can't
|
|
// accommodate the types of headers/footers found in KWord, we at least
|
|
// print out the paragraphs in the body*/
|
|
//
|
|
// Not anymore. Dumping headers & footers in the body didn't
|
|
// turn out to be that useful, nor was it expected by users.
|
|
//
|
|
bool doPageInfo (int headerType, int footerType)
|
|
{
|
|
kdDebug (30509) << "doPageInfo (headerType=" << headerType
|
|
<< ", footerType=" << footerType
|
|
<< ")" << endl;
|
|
|
|
m_headerType = headerType;
|
|
switch (headerType)
|
|
{
|
|
case 0: // same on all pages
|
|
case 3: // different on even and odd pages
|
|
m_isHeaderOnFirstPage = true;
|
|
break;
|
|
case 1: // different on first, even and odd pages
|
|
case 2: // different on first and other pages
|
|
m_isHeaderOnFirstPage = false;
|
|
break;
|
|
default:
|
|
kdWarning (30509) << "Unknown headerType: " << headerType << endl;
|
|
m_isHeaderOnFirstPage = false; // just a guess
|
|
break;
|
|
}
|
|
|
|
m_footerType = footerType;
|
|
switch (footerType)
|
|
{
|
|
case 0: // same on all pages
|
|
case 3: // different on even and odd pages
|
|
m_isFooterOnFirstPage = true;
|
|
break;
|
|
case 1: // different on first, even and odd pages
|
|
case 2: // different on first and other pages
|
|
m_isFooterOnFirstPage = false;
|
|
break;
|
|
default:
|
|
kdWarning (30590) << "Unknown footerType: " << footerType << endl;
|
|
m_isFooterOnFirstPage = false; // just a guess
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool isParaListEmpty (const TQValueList <ParaData> ¶)
|
|
{
|
|
if (para.count () == 1)
|
|
{
|
|
if (para.first ().text.isEmpty ())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool doHeader (const HeaderData &header)
|
|
{
|
|
kdDebug (30509) << "doHeader (header.page=" << header.page << ")" << endl;
|
|
|
|
if (isParaListEmpty (header.para))
|
|
{
|
|
kdDebug (30509) << "\tEmpty, ignoring" << endl;
|
|
return true;
|
|
}
|
|
|
|
#if 0
|
|
switch (m_headerType)
|
|
{
|
|
case 0: // same on all pages
|
|
if (header.page != HeaderData::PAGE_ALL)
|
|
return true;
|
|
break;
|
|
case 3: // different on even and odd pages
|
|
if (header.page != HeaderData::PAGE_ODD &&
|
|
header.page != HeaderData::PAGE_EVEN)
|
|
return true;
|
|
break;
|
|
case 1: // different on first, even and odd pages
|
|
// accept everything
|
|
break;
|
|
case 2: // different on first and other pages
|
|
if (header.page != HeaderData::PAGE_FIRST &&
|
|
header.page != HeaderData::PAGE_ODD)
|
|
return true;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
m_hasHeader = true;
|
|
m_headerData.push_back (header);
|
|
return true;
|
|
}
|
|
|
|
bool doFooter (const FooterData &footer)
|
|
{
|
|
kdDebug (30509) << "doFooter (footer.page=" << footer.page << ")" << endl;
|
|
|
|
if (isParaListEmpty (footer.para))
|
|
{
|
|
kdDebug (30509) << "\tEmpty, ignoring" << endl;
|
|
return true;
|
|
}
|
|
|
|
#if 0
|
|
switch (m_footerType)
|
|
{
|
|
case 0: // same on all pages
|
|
if (footer.page != FooterData::PAGE_ALL)
|
|
return true;
|
|
break;
|
|
case 3: // different on even and odd pages
|
|
if (footer.page != FooterData::PAGE_ODD &&
|
|
footer.page != FooterData::PAGE_EVEN)
|
|
return true;
|
|
break;
|
|
case 1: // different on first, even and odd pages
|
|
// accept everything
|
|
break;
|
|
case 2: // different on first and other pages
|
|
if (footer.page != FooterData::PAGE_FIRST &&
|
|
footer.page != FooterData::PAGE_ODD)
|
|
return true;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
m_hasFooter = true;
|
|
m_footerData.push_back (footer);
|
|
return true;
|
|
}
|
|
|
|
bool doOpenBody (void)
|
|
{
|
|
kdDebug (30509) << "doOpenBody ()" << endl;
|
|
|
|
//
|
|
// Document Start
|
|
//
|
|
if (!doTrulyOpenDocument ()) return false;
|
|
|
|
|
|
//
|
|
// Footers followed by Headers (in this order)
|
|
//
|
|
|
|
bool wroteFooter = false;
|
|
m_inWhat = Footer;
|
|
|
|
for (TQValueList <FooterData>::Iterator it = m_footerData.begin ();
|
|
it != m_footerData.end ();
|
|
it++)
|
|
{
|
|
if ((*it).page != FooterData::PAGE_FIRST)
|
|
{
|
|
if (!wroteFooter)
|
|
{
|
|
if (!m_generator->writeFooterBegin ()) return false;
|
|
wroteFooter = true;
|
|
}
|
|
|
|
if (!doFullParagraphList ((*it).para)) return false;
|
|
it = --m_footerData.erase (it);
|
|
}
|
|
}
|
|
if (wroteFooter)
|
|
if (!m_generator->writeFooterEnd ()) return false;
|
|
|
|
bool wroteHeader = false;
|
|
m_inWhat = Header;
|
|
|
|
for (TQValueList <HeaderData>::Iterator it = m_headerData.begin ();
|
|
it != m_headerData.end ();
|
|
it++)
|
|
{
|
|
if ((*it).page != HeaderData::PAGE_FIRST)
|
|
{
|
|
if (!wroteHeader)
|
|
{
|
|
if (!m_generator->writeHeaderBegin ()) return false;
|
|
wroteHeader = true;
|
|
}
|
|
|
|
if (!doFullParagraphList ((*it).para)) return false;
|
|
it = --m_headerData.erase (it);
|
|
}
|
|
}
|
|
if (wroteHeader)
|
|
if (!m_generator->writeHeaderEnd ()) return false;
|
|
|
|
|
|
//
|
|
// Body Start
|
|
//
|
|
|
|
m_inWhat = Body;
|
|
if (!m_generator->writeBodyBegin ()) return false;
|
|
// KWord doesn't have a PageTable but we must emit the pageNew
|
|
// signal at least once
|
|
if (!m_generator->writePageNew ()) return false;
|
|
|
|
#if 0
|
|
// dump remaining header paragraphs at the start of the body
|
|
for (TQValueList <HeaderData>::Iterator it = m_headerData.begin ();
|
|
it != m_headerData.end ();
|
|
it++)
|
|
{
|
|
kdDebug (30509) << "BODY START ADDING HEADER: " << (*it).page << endl;
|
|
if (!doFullParagraphList ((*it).para)) return false;
|
|
it = --m_headerData.erase (it);
|
|
}
|
|
|
|
// dump remaining footer paragraphs too
|
|
for (TQValueList <FooterData>::Iterator it = m_footerData.begin ();
|
|
it != m_footerData.end ();
|
|
it++)
|
|
{
|
|
kdDebug (30509) << "BODY START ADDING FOOTER: " << (*it).page << endl;
|
|
if (!doFullParagraphList ((*it).para)) return false;
|
|
it = --m_footerData.erase (it);
|
|
}
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
bool doCloseBody (void)
|
|
{
|
|
kdDebug (30509) << "doCloseBody ()" << endl;
|
|
|
|
if (!m_generator->writeBodyEnd ()) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// device that can either read from or write to a TQBuffer
|
|
// (but not both at the same time, please :))
|
|
class TQBufferDevice : public MSWrite::Device
|
|
{
|
|
private:
|
|
TQBuffer *m_buffer;
|
|
|
|
public:
|
|
TQBufferDevice (TQBuffer *buffer)
|
|
{
|
|
m_buffer = buffer;
|
|
}
|
|
|
|
bool read (MSWrite::Byte *buf, const MSWrite::DWord numBytes)
|
|
{
|
|
if (m_buffer->readBlock ((char *) buf, (TQ_ULONG) numBytes) != TQ_LONG (numBytes))
|
|
{
|
|
error (MSWrite::Error::FileError, "could not read from TQBuffer (not really a FileError)\n");
|
|
return false;
|
|
}
|
|
else
|
|
return true;
|
|
}
|
|
|
|
bool write (const MSWrite::Byte *buf, const MSWrite::DWord numBytes)
|
|
{
|
|
if (m_buffer->writeBlock ((char *) buf, (TQ_ULONG) numBytes) != TQ_LONG (numBytes))
|
|
{
|
|
error (MSWrite::Error::FileError, "could not write to TQBuffer (not really a FileError)\n");
|
|
return false;
|
|
}
|
|
else
|
|
return true;
|
|
}
|
|
|
|
// normally we must write zeros if we seek past EOF
|
|
// but we know that won't happen :)
|
|
bool seek (const long offset, const int whence)
|
|
{
|
|
long absoffset;
|
|
switch (whence)
|
|
{
|
|
case SEEK_SET:
|
|
absoffset = offset;
|
|
break;
|
|
case SEEK_CUR:
|
|
absoffset = m_buffer->at () + offset;
|
|
break;
|
|
case SEEK_END:
|
|
absoffset = m_buffer->size () + offset;
|
|
break;
|
|
default:
|
|
error (MSWrite::Error::InternalError, "unknown seek\n");
|
|
return false;
|
|
}
|
|
|
|
if (absoffset > long (m_buffer->size ()))
|
|
{
|
|
error (MSWrite::Error::InternalError, "seek past EOF unimplemented\n");
|
|
return false;
|
|
}
|
|
|
|
if (!m_buffer->at (absoffset))
|
|
{
|
|
error (MSWrite::Error::FileError, "TQBuffer could not seek (not really a FileError)\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
long tell (void)
|
|
{
|
|
return long (m_buffer->at ());
|
|
}
|
|
|
|
void debug (const char *s)
|
|
{
|
|
kdDebug (30509) << s;
|
|
}
|
|
void debug (const int i)
|
|
{
|
|
kdDebug (30509) << i;
|
|
}
|
|
|
|
void error (const int errorCode, const char *message,
|
|
const char * /*file*/ = "", const int /*lineno*/ = 0,
|
|
MSWrite::DWord /*token*/ = MSWrite::Device::NoToken)
|
|
{
|
|
if (errorCode == MSWrite::Error::Warn)
|
|
kdWarning (30509) << message;
|
|
else
|
|
{
|
|
m_error = errorCode;
|
|
kdError (30509) << message;
|
|
}
|
|
}
|
|
};
|
|
|
|
class WMFRecord : public MSWrite::NeedsDevice
|
|
{
|
|
public:
|
|
static const int s_size = 6;
|
|
|
|
protected:
|
|
MSWrite::Byte m_data [s_size];
|
|
|
|
MSWrite::DWord m_size; // record size in Words including everything in this struct
|
|
MSWrite::Word m_function;
|
|
|
|
MSWrite::Short m_args [100]; // "ought to be enough for anybody"
|
|
int m_argUpto;
|
|
|
|
public:
|
|
WMFRecord () : m_argUpto (0)
|
|
{
|
|
}
|
|
|
|
WMFRecord (const MSWrite::DWord size, const MSWrite::Word function, MSWrite::Device *device)
|
|
: MSWrite::NeedsDevice (device),
|
|
m_size (size), m_function (function),
|
|
m_argUpto (0)
|
|
{
|
|
}
|
|
|
|
MSWrite::DWord getSize (void) const { return m_size; }
|
|
void setSize (const MSWrite::DWord size) { m_size = size; }
|
|
|
|
MSWrite::Word getFunction (void) const { return m_function; }
|
|
void setFunction (const MSWrite::Word function) { m_function = function; }
|
|
|
|
void add (const MSWrite::Short arg)
|
|
{
|
|
m_args [m_argUpto++] = arg;
|
|
}
|
|
|
|
bool readFromDevice (void)
|
|
{
|
|
if (!m_device->readInternal (m_data, 6)) return false;
|
|
MSWrite::ReadDWord (m_size, m_data + 0);
|
|
MSWrite::ReadWord (m_function, m_data + 4);
|
|
printf ("Size (Words): %i Size (Bytes): %i Function: %04X (func=%02X,numArgs=%i)\n",
|
|
m_size, m_size * sizeof (MSWrite::Word), m_function, m_function & 255, m_function >> 8);
|
|
#if 1
|
|
if (m_function == 0 && m_size == 3) // last record
|
|
return false;
|
|
#endif
|
|
|
|
switch (m_function)
|
|
{
|
|
case 0x0103:
|
|
printf ("\tSetMapMode\n");
|
|
break;
|
|
case 0x020c:
|
|
printf ("\tSetWindowExt\n");
|
|
break;
|
|
case 0x020b:
|
|
printf ("\tSetWindowOrg\n");
|
|
break;
|
|
case 0x0b41:
|
|
printf ("\tDibStretchBlt\n");
|
|
break;
|
|
default:
|
|
printf ("\tUnknown function\n");
|
|
}
|
|
|
|
long offset = m_device->tellInternal ();
|
|
|
|
for (int i = 0; i < ((m_function == 0x0b41) ? 10 : (m_function >> 8)); i++)
|
|
{
|
|
MSWrite::Byte data [2];
|
|
if (!m_device->readInternal (data, 2)) return false;
|
|
MSWrite::ReadShort (m_args [i], data);
|
|
printf ("\tArg (rev) #%i=%i\n", i, m_args [i]);
|
|
}
|
|
|
|
#if 0
|
|
// arguments are reversed normally
|
|
int u = 0;
|
|
for (int i = (m_function >> 8) - 1; i >= 0; i--, u++)
|
|
printf ("\tArg #%i=%u\n", u, m_args [i]);
|
|
#endif
|
|
|
|
#if 1
|
|
if (m_function == 0xb41)
|
|
{
|
|
// just curious but what's the infoHeader like?
|
|
MSWrite::BMP_BitmapInfoHeader bih;
|
|
bih.setDevice (m_device);
|
|
if (!bih.readFromDevice ()) return false;
|
|
}
|
|
#endif
|
|
|
|
m_size *= sizeof (MSWrite::Word); // in Bytes now
|
|
m_size -= 6; // skip past prefix
|
|
printf (">>> At: %li Next: %li\n", m_device->tellInternal (), offset + m_size);
|
|
if (!m_device->seekInternal (offset + m_size, SEEK_SET)) return false;
|
|
return true;
|
|
}
|
|
|
|
bool writeToDevice (void)
|
|
{
|
|
MSWrite::WriteDWord (m_size, m_data + 0);
|
|
MSWrite::WriteWord (m_function, m_data + 4);
|
|
if (!m_device->writeInternal (m_data, 6)) return false;
|
|
|
|
for (int i = 0; i < ((m_function == 0x0B41) ? 10/*not 11*/ : (m_function >> 8)); i++)
|
|
{
|
|
MSWrite::Byte data [2];
|
|
MSWrite::WriteShort (m_args [i], data);
|
|
if (!m_device->writeInternal (data, 2)) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
// converts a DIB to a Standard WMF
|
|
bool BMP2WMF (MSWrite::Device &readDevice, MSWrite::Device &writeDevice)
|
|
{
|
|
// read BMP's FileHeader
|
|
MSWrite::BMP_BitmapFileHeader bfh;
|
|
bfh.setDevice (&readDevice);
|
|
if (!bfh.readFromDevice ()) return false;
|
|
|
|
// WMF bitmap doesn't contain FileHeader
|
|
MSWrite::DWord totalBytes = bfh.getTotalBytes () - MSWrite::BMP_BitmapFileHeader::s_size;
|
|
|
|
// read BMP's InfoHeader to get some info...
|
|
MSWrite::BMP_BitmapInfoHeader bih;
|
|
bih.setDevice (&readDevice);
|
|
if (!bih.readFromDevice ()) return false;
|
|
|
|
// get some info about the image
|
|
MSWrite::Long width = bih.getWidth ();
|
|
MSWrite::Long height = bih.getHeight ();
|
|
|
|
|
|
// Note: not from LibMSWrite's wmf.cpp
|
|
kdDebug (30509) << "\t\tBIH: width(pt)=" << width
|
|
<< " height(pt)=" << height
|
|
<< " BPP=" << bih.getBitsPerPixel ()
|
|
<< endl;
|
|
kdDebug (30509) << "\t\tBIH: xPixelsPerMeter=" << bih.getXPixelsPerMeter ()
|
|
<< " yPixelsPerMeter=" << bih.getYPixelsPerMeter ()
|
|
<< endl;
|
|
|
|
|
|
// write WMF Header
|
|
MSWrite::WMFHeader wmfHeader;
|
|
wmfHeader.setDevice (&writeDevice);
|
|
|
|
MSWrite::DWord maxRecordSizeBytes
|
|
= (totalBytes
|
|
+ 10 * sizeof (MSWrite::Word)/*parameters for DibStretchBlt*/
|
|
+ WMFRecord::s_size);
|
|
wmfHeader.setFileSize ((MSWrite::WMFHeader::s_size
|
|
+ WMFRecord::s_size + 1 * sizeof (MSWrite::Word)/*SetMapMode*/
|
|
+ WMFRecord::s_size + 2 * sizeof (MSWrite::Word)/*SetWindowExt*/
|
|
+ WMFRecord::s_size + 2 * sizeof (MSWrite::Word)/*SetWindowOrg*/
|
|
+ maxRecordSizeBytes/*DibStretchBlt*/
|
|
+ WMFRecord::s_size/*Sentinel*/)
|
|
/ sizeof (MSWrite::Word));
|
|
wmfHeader.setMaxRecordSize (maxRecordSizeBytes / sizeof (MSWrite::Word));
|
|
if (!wmfHeader.writeToDevice ()) return false;
|
|
|
|
WMFRecord wmfRecordSetMapMode (4/*(Words)*/, 0x0103, &writeDevice);
|
|
wmfRecordSetMapMode.add (8/*MM_ANISOTROPIC*/);
|
|
if (!wmfRecordSetMapMode.writeToDevice ()) return false;
|
|
|
|
WMFRecord wmfRecordSetWindowExt (5/*(Words)*/, 0x020C, &writeDevice);
|
|
wmfRecordSetWindowExt.add (-height);
|
|
wmfRecordSetWindowExt.add (width);
|
|
if (!wmfRecordSetWindowExt.writeToDevice ()) return false;
|
|
|
|
WMFRecord wmfRecordSetWindowOrg (5/*(Words)*/, 0x020B, &writeDevice);
|
|
wmfRecordSetWindowOrg.add (0);
|
|
wmfRecordSetWindowOrg.add (0);
|
|
if (!wmfRecordSetWindowOrg.writeToDevice ()) return false;
|
|
|
|
WMFRecord wmfRecordBMP (maxRecordSizeBytes / sizeof (MSWrite::Word),
|
|
0x0B41/*DibStretchBlt*/,
|
|
&writeDevice);
|
|
wmfRecordBMP.add (32); // ?
|
|
wmfRecordBMP.add (204); // ?
|
|
wmfRecordBMP.add (height); // src height
|
|
wmfRecordBMP.add (width); // src width
|
|
wmfRecordBMP.add (0); // src y
|
|
wmfRecordBMP.add (0); // src x
|
|
wmfRecordBMP.add (-height); // dest height
|
|
wmfRecordBMP.add (width); // dest width
|
|
wmfRecordBMP.add (0); // dest y
|
|
wmfRecordBMP.add (0); // dest x
|
|
if (!wmfRecordBMP.writeToDevice ()) return false;
|
|
|
|
// write BMP InfoHeader back to the device
|
|
bih.setDevice (&writeDevice);
|
|
if (!bih.writeToDevice ()) return false;
|
|
|
|
long left = totalBytes - MSWrite::BMP_BitmapInfoHeader::s_size;
|
|
while (left)
|
|
{
|
|
MSWrite::Byte data [1024];
|
|
long amountToRead = left > 1024 ? 1024 : left;
|
|
if (!readDevice.readInternal (data, amountToRead)) return false;
|
|
if (!writeDevice.writeInternal (data, amountToRead)) return false;
|
|
|
|
left -= amountToRead;
|
|
}
|
|
|
|
WMFRecord wmfRecordSentinel (3/*(Words)*/, 0x0000, &writeDevice);
|
|
if (!wmfRecordSentinel.writeToDevice ()) return false;
|
|
|
|
#if 1
|
|
// bug with Word97?
|
|
MSWrite::Byte zero = 0;
|
|
if (!writeDevice.writeInternal (&zero, sizeof (MSWrite::Byte))) return false;
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
// all windows measurements depend on there being 72 dots/points per inch
|
|
static double getDimen72DPI (const int measurement, const int dotsPerMeter)
|
|
{
|
|
kdDebug (30509) << "\t\tgetDimen72DPI (measurement=" << measurement
|
|
<< ",dotsPerMeter=" << dotsPerMeter << ")" << endl;
|
|
|
|
// Can't get resolution?
|
|
// Assume that we are already 72dpi
|
|
if (dotsPerMeter <= 0)
|
|
return double (measurement);
|
|
|
|
// 2834.65 = 100 / 2.54 * 72
|
|
return double (measurement) * 2834.65 / double (dotsPerMeter);
|
|
}
|
|
|
|
//
|
|
// Note: if we suffer from a conversion error in this function (and can't
|
|
// export the image), we _still_ return true, not false because there is
|
|
// nothing worse than a filter that aborts due to its own incompetence [1]
|
|
// (don't flame the author please, just blame the function :)). But if we
|
|
// do suffer from a file-like error, we abort right away because something
|
|
// bad (memory corruption, internal error...) is happening!
|
|
//
|
|
// Why then _do_ we abort on text errors when images tell a thousand
|
|
// words? Because this saying is wrong and text is probably more
|
|
// important to the user.
|
|
//
|
|
// [1] yes, "worse than an itch you can't scratch"
|
|
//
|
|
bool processImage (const FrameAnchor &frameAnchor,
|
|
const MSWrite::FormatParaProperty *paraPropIn,
|
|
const MSWrite::FormatCharProperty *charPropIn,
|
|
const bool ignoreIndent)
|
|
{
|
|
kdDebug (30509) << "--------------------------" << endl
|
|
<< "processImage()" << endl;
|
|
|
|
|
|
// Write supports images in 3 formats:
|
|
//
|
|
// 1. Monochrome BMP (not very useful)
|
|
// 2. OLE (hard to work with and only supported in ver >= 3.1)
|
|
// 3. Standard WMF
|
|
//
|
|
// So we convert all images to WMF for convenience.
|
|
// We don't even bother saving Monochrome BMPs "as is" because
|
|
// there's no point (just save it in WMF to make life easier)
|
|
//
|
|
// But a Standard WMF is basically a BMP with some headers/GDI calls
|
|
// so the conversion process is like this:
|
|
//
|
|
// start->WMF->finish
|
|
// start->BMP->WMF->finish
|
|
// start->???->BMP->WMF->finish
|
|
//
|
|
|
|
double imageActualWidth = -1, imageActualHeight = -1;
|
|
MSWrite::DWord imageSize = 0;
|
|
|
|
TQString imageType;
|
|
int pos = frameAnchor.picture.koStoreName.findRev ('.');
|
|
if (pos != -1) imageType = frameAnchor.picture.koStoreName.mid (pos).lower ();
|
|
kdDebug (30509) << "\timageType: " << imageType << endl;
|
|
|
|
TQByteArray imageData;
|
|
kdDebug (30509) << "\tReading image: " << frameAnchor.picture.koStoreName << endl;
|
|
if (!loadSubFile (frameAnchor.picture.koStoreName, imageData))
|
|
ErrorAndQuit (MSWrite::Error::FileError, "could not open image from store\n");
|
|
|
|
// FSM
|
|
for (;;)
|
|
{
|
|
if (imageType == ".wmf")
|
|
{
|
|
imageSize = imageData.size ();
|
|
if (imageActualWidth == -1 && imageActualHeight == -1)
|
|
{
|
|
// load WMF
|
|
KoWmfPaint wmf;
|
|
if (!wmf.load (imageData))
|
|
{
|
|
kdError (30509) << "Could not open WMF - Invalid Format!" << endl;
|
|
return true;
|
|
}
|
|
|
|
// get raw dimensions
|
|
TQRect dimen = wmf.boundingRect ();
|
|
int width = abs (dimen.width ());
|
|
int height = abs (dimen.height ());
|
|
kdDebug (30509) << "\tRaw WMF dimensions: " << width << "x" << height << endl;
|
|
|
|
if (wmf.isPlaceable ())
|
|
{
|
|
kdDebug (30509) << "\tConverting Placeable WMF" << endl;
|
|
|
|
// convert twip measurements that aren't in 72dpi
|
|
int defaultDpi = wmf.defaultDpi ();
|
|
if (defaultDpi <= 0)
|
|
{
|
|
kdWarning (30509) << "Invalid defaultDPI: " << defaultDpi << endl;
|
|
defaultDpi = 1440;
|
|
}
|
|
imageActualWidth = width * 1440 / defaultDpi;
|
|
imageActualHeight = height * 1440 / defaultDpi;
|
|
|
|
// Remove Aldus Placeable WMF Header
|
|
for (int i = 0; i < int (imageSize) - 22; i++)
|
|
imageData [i] = imageData [i + 22];
|
|
|
|
imageData.resize (imageSize - 22);
|
|
imageSize -= 22;
|
|
}
|
|
else if (wmf.isEnhanced ())
|
|
{
|
|
kdError (30509) << "Enhanced WMF unsupported by TQWmf, internal error!" << endl;
|
|
|
|
return true;
|
|
}
|
|
// Standard WMF
|
|
else
|
|
{
|
|
kdDebug (30509) << "\tStandard WMF - no conversion required" << endl;
|
|
|
|
// assume width & height were in 72dpi points
|
|
imageActualWidth = Point2Twip (width);
|
|
imageActualHeight = Point2Twip (height);
|
|
}
|
|
}
|
|
|
|
kdDebug (30509) << "\tNow WMF: width=" << imageActualWidth
|
|
<< " height=" << imageActualHeight
|
|
<< " size=" << imageSize
|
|
<< endl;
|
|
|
|
// we're done!
|
|
break;
|
|
}
|
|
// TODO: DDB?
|
|
else if (imageType == ".bmp")
|
|
{
|
|
TQImage image (imageData);
|
|
if (image.isNull ())
|
|
{
|
|
kdError (30509) << "TQImage IsNull: Line=" << __LINE__ << endl;
|
|
return true;
|
|
}
|
|
|
|
if (imageActualWidth == -1 && imageActualHeight == -1)
|
|
{
|
|
imageActualWidth = Point2Twip (getDimen72DPI (image.width (), image.dotsPerMeterX ()));
|
|
imageActualHeight = Point2Twip (getDimen72DPI (image.height (), image.dotsPerMeterY ()));
|
|
}
|
|
|
|
kdDebug (30509) << "\tNow BMP: width=" << imageActualWidth
|
|
<< " height=" << imageActualHeight
|
|
<< " size=" << imageSize
|
|
<< endl;
|
|
|
|
TQByteArray imageWMF;
|
|
// input device
|
|
TQBuffer inBuffer (imageData);
|
|
inBuffer.open (IO_ReadOnly);
|
|
TQBufferDevice inDevice (&inBuffer);
|
|
|
|
// output device
|
|
TQBuffer outBuffer (imageWMF);
|
|
outBuffer.open (IO_WriteOnly);
|
|
TQBufferDevice outDevice (&outBuffer);
|
|
|
|
// BMP --> WMF
|
|
if (!BMP2WMF (inDevice, outDevice))
|
|
{
|
|
kdError (30509) << "BMP to WMF conversion error" << endl;
|
|
return true;
|
|
}
|
|
|
|
outBuffer.close ();
|
|
inBuffer.close ();
|
|
imageData = imageWMF.copy ();
|
|
|
|
imageType = ".wmf";
|
|
}
|
|
else
|
|
{
|
|
if (imageActualWidth == -1 && imageActualHeight == -1)
|
|
{
|
|
TQImage image (imageData);
|
|
if (image.isNull())
|
|
{
|
|
kdError (30509) << "TQImage isNull: Line=" << __LINE__ << endl;
|
|
return true;
|
|
}
|
|
|
|
imageActualWidth = Point2Twip (getDimen72DPI (image.width (), image.dotsPerMeterX ()));
|
|
imageActualHeight = Point2Twip (getDimen72DPI (image.height (), image.dotsPerMeterY ()));
|
|
}
|
|
|
|
kdDebug (30509) << "\tForeign format: width=" << imageActualWidth
|
|
<< " height=" << imageActualHeight
|
|
<< " size=" << imageSize
|
|
<< endl;
|
|
|
|
TQByteArray imageBMP;
|
|
// input device
|
|
TQBuffer inBuffer (imageData);
|
|
inBuffer.open (IO_ReadOnly);
|
|
|
|
// read foreign image
|
|
TQImageIO imageIO (&inBuffer, NULL);
|
|
if (!imageIO.read ())
|
|
{
|
|
kdError (30509) << "Could not read foreign format" << endl;
|
|
return true;
|
|
}
|
|
|
|
// output device
|
|
TQBuffer outBuffer (imageBMP);
|
|
outBuffer.open (IO_WriteOnly);
|
|
|
|
// write BMP
|
|
imageIO.setIODevice (TQT_TQIODEVICE(&outBuffer));
|
|
imageIO.setFormat ("BMP");
|
|
if (!imageIO.write ())
|
|
{
|
|
kdError (30509) << "Could not convert to BMP" << endl;
|
|
return true;
|
|
}
|
|
|
|
outBuffer.close ();
|
|
inBuffer.close ();
|
|
imageData = imageBMP.copy ();
|
|
|
|
imageType = ".bmp";
|
|
}
|
|
}
|
|
|
|
|
|
kdDebug (30509) << "\tActual dimensions: width=" << imageActualWidth
|
|
<< " height=" << imageActualHeight << endl;
|
|
|
|
kdDebug (30509) << "\tKOffice position: left=" << frameAnchor.frame.left
|
|
<< " right=" << frameAnchor.frame.right
|
|
<< " top=" << frameAnchor.frame.top
|
|
<< " bottom=" << frameAnchor.frame.bottom
|
|
<< endl;
|
|
|
|
kdDebug (30509) << "\tIndent=" << MSWrite::Word (Point2Twip (frameAnchor.frame.left)) - m_leftMargin << endl;
|
|
if (ignoreIndent)
|
|
kdDebug (30509) << "\t\tIgnoring indent - already exported at least one image in a KWord paragraph" << endl;
|
|
|
|
double displayedWidth = Point2Twip (frameAnchor.frame.right - frameAnchor.frame.left + 1);
|
|
double displayedHeight = Point2Twip (frameAnchor.frame.bottom - frameAnchor.frame.top + 1);
|
|
|
|
kdDebug (30509) << "\tdisplayedWidth=" << displayedWidth
|
|
<< " displayedHeight=" << displayedHeight
|
|
<< endl;
|
|
|
|
|
|
//
|
|
// Start writing out the image now
|
|
//
|
|
// Note: here, we can start returning false again because the errors
|
|
// won't be conversion-related
|
|
//
|
|
|
|
MSWrite::Image image;
|
|
image.setIsWMF (true);
|
|
if (!ignoreIndent)
|
|
{
|
|
if (paraPropIn->getAlignment () != MSWrite::Alignment::Centre)
|
|
image.setIndent (MSWrite::Word (Point2Twip (frameAnchor.frame.left)) - m_leftMargin);
|
|
else
|
|
{
|
|
// TODO: what is the image offset relative to (it's not always rel. to the left margin)?
|
|
kdDebug (30509) << "\tCentred paragraph, cannot position image" << endl;
|
|
}
|
|
}
|
|
|
|
image.setOriginalWidth (imageActualWidth);
|
|
image.setOriginalHeight (imageActualHeight);
|
|
image.setDisplayedWidth (displayedWidth);
|
|
image.setDisplayedHeight (displayedHeight);
|
|
image.setExternalImageSize (imageSize);
|
|
|
|
MSWrite::FormatParaProperty paraProp; paraProp = *paraPropIn;
|
|
paraProp.setIsObject (true);
|
|
paraProp.setLeftIndent (0); // not necessary but...
|
|
if (!m_generator->writeParaInfoBegin (¶Prop, NULL, &image))
|
|
return false;
|
|
|
|
// yes, images have character formatting as well
|
|
// (character formatting _must_ cover entire document)
|
|
// (but I think it's ignored)
|
|
MSWrite::FormatCharProperty charProp; charProp = *charPropIn;
|
|
if (!m_generator->writeCharInfoBegin (&charProp))
|
|
return false;
|
|
|
|
// actually write image
|
|
if (!m_generator->writeBinary ((const MSWrite::Byte *) (const char *) imageData.data (), imageSize)) return false;
|
|
|
|
// 2nd argument endOfParagraph is ignored by InternalGenerator so
|
|
// there's no need to specify it
|
|
if (!m_generator->writeCharInfoEnd (&charProp, true))
|
|
return false;
|
|
;
|
|
if (!m_generator->writeParaInfoEnd (¶Prop, NULL, &image))
|
|
return false;
|
|
|
|
|
|
kdDebug (30509) << "processImage() successful!" << endl
|
|
<< "==========================" << endl
|
|
<< endl
|
|
<< endl;
|
|
return true;
|
|
}
|
|
|
|
bool processTable (const Table &table)
|
|
{
|
|
// just dump the table out for now (no layout)
|
|
for (TQValueList <TableCell>::ConstIterator it = table.cellList.begin ();
|
|
it != table.cellList.end ();
|
|
it++)
|
|
{
|
|
if (!doFullParagraphList (*(*it).paraList)) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool processCounter (const CounterData &counter)
|
|
{
|
|
//kdDebug (30509) << "processCounter(counter.text=" << counter.text << ")" << endl;
|
|
|
|
if (!counter.text.isEmpty ())
|
|
{
|
|
// isn't this wonderful? :)
|
|
if (!processText (counter.text)) return false;
|
|
if (!processText (" ")) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
//#define KMF_DEBUG_FONT
|
|
#endif
|
|
void processFormatData (MSWrite::FormatCharProperty &charProp,
|
|
const TextFormatting &f)
|
|
{
|
|
if (!f.fontName.isEmpty ())
|
|
{
|
|
// create new Font with Name
|
|
MSWrite::Font font ((const MSWrite::Byte *) (const char *) f.fontName.utf8 ());
|
|
#ifdef KMF_DEBUG_FONT
|
|
kdDebug (30509) << "FontName " << f.fontName << endl;
|
|
#endif
|
|
|
|
// get Font Family
|
|
TQFont TQTFontInfo (f.fontName);
|
|
switch (TQTFontInfo.styleHint ())
|
|
{
|
|
case TQFont::Serif:
|
|
#ifdef KMF_DEBUG_FONT
|
|
kdDebug (30509) << "FontFamily Serif" << endl;
|
|
#endif
|
|
font.setFamily (MSWrite::Font::Roman);
|
|
break;
|
|
case TQFont::SansSerif:
|
|
#ifdef KMF_DEBUG_FONT
|
|
kdDebug (30509) << "FontFamily SansSerif" << endl;
|
|
#endif
|
|
font.setFamily (MSWrite::Font::Swiss);
|
|
break;
|
|
case TQFont::Courier:
|
|
#ifdef KMF_DEBUG_FONT
|
|
kdDebug (30509) << "FontFamily Courier" << endl;
|
|
#endif
|
|
font.setFamily (MSWrite::Font::Modern);
|
|
break;
|
|
case TQFont::OldEnglish:
|
|
#ifdef KMF_DEBUG_FONT
|
|
kdDebug (30509) << "FontFamily OldEnglish" << endl;
|
|
#endif
|
|
font.setFamily (MSWrite::Font::Decorative);
|
|
break;
|
|
default:
|
|
#ifdef KMF_DEBUG_FONT
|
|
kdDebug (30509) << "FontFamily DontKnow" << endl;
|
|
#endif
|
|
// it's either DontCare or MSWrite::Font::Script
|
|
font.setFamily (MSWrite::Font::DontCare);
|
|
break;
|
|
}
|
|
|
|
charProp.setFont (&font);
|
|
}
|
|
if (f.fontSize > 0) charProp.setFontSize (f.fontSize);
|
|
|
|
charProp.setIsItalic (f.italic);
|
|
charProp.setIsUnderlined (f.underline); // TODO: underlineWord
|
|
charProp.setIsBold (f.weight > (50/*normal*/ + 75/*bold*/) / 2);
|
|
|
|
switch (f.verticalAlignment)
|
|
{
|
|
case 0: // normal
|
|
charProp.setIsNormalPosition ();
|
|
break;
|
|
case 1: // subscript
|
|
charProp.setIsSubscript ();
|
|
break;
|
|
case 2: // superscript
|
|
charProp.setIsSuperscript ();
|
|
break;
|
|
}
|
|
|
|
// TODO: fontAttribute;
|
|
}
|
|
|
|
static MSWrite::Word getClosestLineSpacing (const double points)
|
|
{
|
|
const double twips = Point2Twip (points);
|
|
|
|
#if 1
|
|
if (twips < double ((MSWrite::LineSpacing::Single + MSWrite::LineSpacing::OneAndAHalf) / 2))
|
|
return MSWrite::LineSpacing::Single;
|
|
else if (twips < double ((MSWrite::LineSpacing::OneAndAHalf + MSWrite::LineSpacing::Double) / 2))
|
|
return MSWrite::LineSpacing::OneAndAHalf;
|
|
else
|
|
return MSWrite::LineSpacing::Double;
|
|
#else // or do we want a non-"standard" linespacing?
|
|
return MSWrite::Word (twips);
|
|
#endif
|
|
}
|
|
|
|
bool doFullParagraphList (const TQValueList <ParaData> ¶List)
|
|
{
|
|
for (TQValueList <ParaData>::ConstIterator it = paraList.begin ();
|
|
it != paraList.end ();
|
|
it ++)
|
|
{
|
|
if (!doFullParagraph (*it)) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool doFullParagraph (const ParaData ¶Data)
|
|
{
|
|
return doFullParagraph (paraData.text,
|
|
paraData.layout,
|
|
paraData.formattingList);
|
|
}
|
|
|
|
bool doFullParagraph (const TQString ¶Text,
|
|
const LayoutData &layout,
|
|
const ValueListFormatData ¶FormatDataList)
|
|
{
|
|
MSWrite::FormatParaProperty paraProp;
|
|
|
|
if (m_inWhat == Body)
|
|
paraProp.setIsNormalParagraph (true);
|
|
else
|
|
{
|
|
if (m_inWhat == Header)
|
|
{
|
|
paraProp.setIsHeader (true);
|
|
paraProp.setIsOnFirstPage (m_isHeaderOnFirstPage);
|
|
}
|
|
else if (m_inWhat == Footer)
|
|
{
|
|
paraProp.setIsFooter (true);
|
|
paraProp.setIsOnFirstPage (m_isFooterOnFirstPage);
|
|
}
|
|
}
|
|
|
|
paraProp.setIsText (true);
|
|
|
|
// Alignment
|
|
if (!layout.alignment.isEmpty ())
|
|
{
|
|
if (layout.alignment == "left")
|
|
// quite useless since MSWrite::Alignment::Left is the default anyway
|
|
paraProp.setAlignment (MSWrite::Alignment::Left);
|
|
else if (layout.alignment == "right")
|
|
paraProp.setAlignment (MSWrite::Alignment::Right);
|
|
else if (layout.alignment == "center")
|
|
paraProp.setAlignment (MSWrite::Alignment::Center);
|
|
else if (layout.alignment == "justify")
|
|
paraProp.setAlignment (MSWrite::Alignment::Justify);
|
|
else
|
|
kdWarning (30509) << "Unknown Alignment: " << layout.alignment << endl;
|
|
}
|
|
|
|
// Indentation
|
|
if (layout.indentFirst) paraProp.setLeftIndentFirstLine (MSWrite::Short (Point2Twip (layout.indentFirst)));
|
|
if (layout.indentLeft >= 0) paraProp.setLeftIndent (MSWrite::Word (Point2Twip (layout.indentLeft)));
|
|
if (layout.indentRight >= 0) paraProp.setRightIndent (MSWrite::Word (Point2Twip (layout.indentRight)));
|
|
#if 0
|
|
kdDebug (30509) << "Indent: " << Point2Twip (layout.indentFirst) << " "
|
|
<< Point2Twip (layout.indentLeft) << " "
|
|
<< Point2Twip (layout.indentRight) << endl;
|
|
#endif
|
|
|
|
// Line Spacing
|
|
MSWrite::Word lineSpacing = MSWrite::LineSpacing::Normal;
|
|
switch (layout.lineSpacingType)
|
|
{
|
|
case LayoutData::LS_SINGLE:
|
|
lineSpacing = MSWrite::LineSpacing::Normal;
|
|
break;
|
|
case LayoutData::LS_ONEANDHALF:
|
|
lineSpacing = MSWrite::LineSpacing::OneAndAHalf;
|
|
break;
|
|
case LayoutData::LS_DOUBLE:
|
|
lineSpacing = MSWrite::LineSpacing::Double;
|
|
break;
|
|
case LayoutData::LS_CUSTOM:
|
|
case LayoutData::LS_FIXED:
|
|
case LayoutData::LS_ATLEAST:
|
|
lineSpacing = getClosestLineSpacing (layout.lineSpacing);
|
|
break;
|
|
case LayoutData::LS_MULTIPLE:
|
|
break;
|
|
default:
|
|
kdWarning (30509) << "unknown lineSpacingType \'" << layout.lineSpacingType << "\'" << endl;
|
|
}
|
|
paraProp.setLineSpacing (lineSpacing);
|
|
|
|
// Tabs are a Document Property, not a Paragraph Property, in Write, yet are stored for each paragraph.
|
|
// It seems that Write applies the 1st paragraph's Tabulator settings to the _entire_ document
|
|
// Word97 and KWord, however, will treat them like a Paragraph Property
|
|
int numTabs = 0;
|
|
for (TabulatorList::ConstIterator tabIt = layout.tabulatorList.begin ();
|
|
tabIt != layout.tabulatorList.end ();
|
|
tabIt++)
|
|
{
|
|
MSWrite::FormatParaPropertyTabulator tab;
|
|
|
|
// Write's UI only supports 12 as opposed to the 14 supposedly
|
|
// supported in the file so let's play it safe and quit when
|
|
// we reach 12
|
|
// Actually, KWord's UI also only supports 12 so this should never be true
|
|
if (numTabs >= 12)
|
|
{
|
|
kdWarning (30509) << "Write does not support more 12 tabulators, not writing out all tabulators" << endl;
|
|
break;
|
|
}
|
|
|
|
// Write only supports Decimal and Left tabs
|
|
// TODO: KOffice 1.3 alignchar (modify libexport)
|
|
if ((*tabIt).m_type == 3 /* && (*tabIt).m_alignchar == '.' */)
|
|
tab.setIsDecimal ();
|
|
else
|
|
tab.setIsNormal ();
|
|
|
|
tab.setIndent (MSWrite::Word (Point2Twip ((*tabIt).m_ptpos)));
|
|
|
|
// int m_filling;
|
|
// double m_width;
|
|
if ((*tabIt).m_filling != TabulatorData::TF_NONE)
|
|
kdWarning (30509) << "Write does not support Tabulator Filling" << endl;
|
|
|
|
paraProp.addTabulator (&tab);
|
|
numTabs++;
|
|
}
|
|
|
|
// TODO: double marginTop; // space before the paragraph (a negative value means invalid)
|
|
// TODO: double marginBottom; // space after the paragraph (a negative value means invalid)
|
|
|
|
// TODO: TQString styleName;
|
|
// TODO: TQString styleFollowing;
|
|
|
|
if (!m_generator->writeParaInfoBegin (¶Prop)) return false;
|
|
|
|
// get this paragraph's "default formatting"
|
|
MSWrite::FormatCharProperty charPropDefault;
|
|
processFormatData (charPropDefault, layout.formatData.text);
|
|
|
|
MSWrite::DWord uptoByte = 0; // relative to start of KWord paragraph
|
|
MSWrite::DWord numBytes = paraText.length (); // relative to start of KWord paragraph
|
|
|
|
bool startOfWRIParagraph = true;
|
|
bool exportedAtLeastOneImage = false; // ...from the KWord paragraph
|
|
|
|
// empty paragraph
|
|
if (numBytes == 0)
|
|
{
|
|
//kdDebug (30509) << "Outputting empty paragraph!" << endl;
|
|
|
|
// write default character property start
|
|
if (!m_generator->writeCharInfoBegin (&charPropDefault)) return false;
|
|
|
|
// page break at start of paragraph?
|
|
if (layout.pageBreakBefore)
|
|
if (!m_generator->writePageBreak ()) return false;
|
|
|
|
// counter data
|
|
processCounter (layout.counter);
|
|
|
|
// end of line
|
|
if (!m_generator->writeCarriageReturn ()) return false;
|
|
if (!m_generator->writeNewLine (true/*end of paragraph*/)) return false;
|
|
|
|
// page break at end of paragraph?
|
|
if (layout.pageBreakAfter)
|
|
if (!m_generator->writePageBreak ()) return false;
|
|
|
|
// write default character property end
|
|
if (!m_generator->writeCharInfoEnd (&charPropDefault, true)) return false;
|
|
}
|
|
else
|
|
{
|
|
for (ValueListFormatData::ConstIterator formatIt = paraFormatDataList.begin ();
|
|
formatIt != paraFormatDataList.end ();
|
|
formatIt++)
|
|
{
|
|
bool textSegment = true;
|
|
|
|
// apply local <FORMAT> tag on top of "default formatting"
|
|
MSWrite::FormatCharProperty charProp; charProp = charPropDefault;
|
|
processFormatData (charProp, (*formatIt).text);
|
|
|
|
if (!m_generator->writeCharInfoBegin (&charProp)) return false;
|
|
|
|
if (uptoByte == 0)
|
|
{
|
|
// page break at start of paragraph?
|
|
if (layout.pageBreakBefore)
|
|
if (!m_generator->writePageBreak ()) return false;
|
|
|
|
// counter data
|
|
processCounter (layout.counter);
|
|
}
|
|
|
|
// yes, this is slightly premature but it doesn't matter
|
|
// ... just be careful when using uptoByte
|
|
uptoByte += (*formatIt).len;
|
|
|
|
switch ((*formatIt).id)
|
|
{
|
|
case 0: // none?
|
|
ErrorAndQuit (MSWrite::Error::InternalError, "Format ID = 0\n");
|
|
case 1: // text
|
|
if (!processText (paraText.mid ((*formatIt).pos, (*formatIt).len)))
|
|
/*uptoByte == numBytes))*/
|
|
return false;
|
|
|
|
startOfWRIParagraph = false;
|
|
break;
|
|
case 2: // picture (deprecated)
|
|
m_device->error (MSWrite::Error::Warn, "Picture (deprecated) unsupported\n");
|
|
break;
|
|
case 3: // tabulator (deprecated)
|
|
m_device->error (MSWrite::Error::Warn, "Tabulator (deprecated) unsupported\n");
|
|
break;
|
|
case 4: // variable
|
|
{
|
|
bool justPrintText = true;
|
|
|
|
// Page Number / Number of Pages
|
|
if ((*formatIt).variable.m_type == 4 &&
|
|
(*formatIt).variable.isPageNumber () &&
|
|
m_inWhat != Body/*Write replaces it with '*' in the body*/)
|
|
{
|
|
if (!m_generator->writeCharInfoEnd (&charProp)) return false;
|
|
charProp.setIsPageNumber (true);
|
|
// if you don't do this it will print out the character literally (char 1)
|
|
if (!m_generator->writeCharInfoBegin (&charProp)) return false;
|
|
|
|
// only variable Write supports (and only in headers/footers)
|
|
// if you don't write out char 1, Write will not treat it as a
|
|
// variable anchor and will print the character out literally
|
|
if (!m_generator->writePageNumber ()) return false;
|
|
|
|
if (!m_generator->writeCharInfoEnd (&charProp)) return false;
|
|
charProp.setIsPageNumber (false);
|
|
if (!m_generator->writeCharInfoBegin (&charProp)) return false;
|
|
|
|
justPrintText = false;
|
|
}
|
|
|
|
if (justPrintText)
|
|
{
|
|
if (!processText ((*formatIt).variable.m_text))
|
|
return false;
|
|
}
|
|
|
|
startOfWRIParagraph = false;
|
|
break;
|
|
}
|
|
case 5: // footnote (KOffice 1.1)
|
|
m_device->error (MSWrite::Error::Warn, "Footnote unsupported\n");
|
|
break;
|
|
case 6: // anchor for frame
|
|
//
|
|
// Write does not support inline frames so:
|
|
//
|
|
// - we end the current paragraph
|
|
// - dump the inline frame in a paragraph of its own
|
|
// - continue with a new paragraph
|
|
//
|
|
|
|
if (!startOfWRIParagraph)
|
|
{
|
|
kdDebug (30509) << "Writing CRLF to end text paragraph" << endl;
|
|
|
|
// If you don't have CRLF at the end of the text
|
|
// paragraph, Write will think that the next paragraph
|
|
// (the image) is part of the text...
|
|
if (!m_generator->writeCarriageReturn ()) return false;
|
|
if (!m_generator->writeNewLine (true/*end of paragraph*/)) return false;
|
|
}
|
|
else
|
|
kdDebug (30509) << "Inline frame is anchored at start of paragraph, no CRLF" << endl;
|
|
|
|
if (!m_generator->writeCharInfoEnd (&charProp)) return false;
|
|
if (!m_generator->writeParaInfoEnd (¶Prop)) return false;
|
|
|
|
|
|
if ((*formatIt).frameAnchor.type == 6)
|
|
{
|
|
kdDebug (30509) << "Table detected" << endl;
|
|
|
|
// this will make its own paragraph(s)...
|
|
processTable ((*formatIt).frameAnchor.table);
|
|
|
|
// HACK: inline tables are flushed to the left and right
|
|
// margins, despite being inline, hence the next image
|
|
// indent will be sensible and should not be ignored.
|
|
kdDebug (30509) << "Table hack: resetting image-ignore-indent flag" << endl;
|
|
exportedAtLeastOneImage = false;
|
|
}
|
|
else if ((*formatIt).frameAnchor.type == 2)
|
|
{
|
|
kdDebug (30509) << "Image detected" << endl;
|
|
|
|
// this will make its own paragraph...
|
|
if (!processImage ((*formatIt).frameAnchor, ¶Prop, &charProp,
|
|
exportedAtLeastOneImage)) return false;
|
|
|
|
exportedAtLeastOneImage = true;
|
|
}
|
|
else
|
|
kdWarning (30509) << "Unknown type of anchor: " << (*formatIt).frameAnchor.type << endl;
|
|
|
|
|
|
// recontinue paragraph
|
|
if (!m_generator->writeParaInfoBegin (¶Prop)) return false;
|
|
startOfWRIParagraph = true;
|
|
if (!m_generator->writeCharInfoBegin (&charProp)) return false;
|
|
|
|
textSegment = false;
|
|
break;
|
|
}
|
|
|
|
if (uptoByte == numBytes)
|
|
{
|
|
if (textSegment)
|
|
{
|
|
// end of line
|
|
if (!m_generator->writeCarriageReturn ()) return false;
|
|
if (!m_generator->writeNewLine (true/*end of paragraph*/)) return false;
|
|
}
|
|
|
|
// page break at end of paragraph?
|
|
if (layout.pageBreakAfter)
|
|
if (!m_generator->writePageBreak ()) return false;
|
|
}
|
|
|
|
if (!m_generator->writeCharInfoEnd (&charProp, uptoByte == numBytes)) return false;
|
|
}
|
|
}
|
|
|
|
if (!m_generator->writeParaInfoEnd (¶Prop)) return false;
|
|
//if (numBytes) kdDebug (30509) << "Just Output " << uptoByte << "/" << numBytes << " with text \'" << paraText.utf8 () << "\'" << endl;
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class dtype>
|
|
dtype min (const dtype a, const dtype b, const dtype c)
|
|
{
|
|
if (a <= b && a <= c) return a;
|
|
if (b <= a && b <= c) return b;
|
|
return c;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
//#define DEBUG_PROCESS_TEXT
|
|
#endif
|
|
bool processText (const TQString &stringUnicode)
|
|
{
|
|
//
|
|
// Look out for characters in the string and emit signals as appropriate:
|
|
//
|
|
// 1 pageNumber (already taken care of as a variable)
|
|
// 10 newLine
|
|
// 13 carriageReturn (TODO: Oh no! Can't happen!)
|
|
// 12 pageBreak (TODO: we are in real trouble: this can actually happen without forcing a new paragraph!)
|
|
// 31 optionalHyphen
|
|
// ? text
|
|
//
|
|
|
|
int softHyphen = -2, nonBreakingSpace = -2, newLine = -2;
|
|
|
|
int upto = 0;
|
|
int stringUnicodeLength = stringUnicode.length ();
|
|
while (upto < stringUnicodeLength)
|
|
{
|
|
//
|
|
// look for KWord's special characters as defined in the DTD
|
|
//
|
|
|
|
if (softHyphen == -2)
|
|
{
|
|
softHyphen = stringUnicode.find (TQChar (0xAD), upto);
|
|
if (softHyphen == -1) softHyphen = INT_MAX;
|
|
}
|
|
|
|
if (nonBreakingSpace == -2)
|
|
{
|
|
nonBreakingSpace = stringUnicode.find (TQChar (0xA0), upto);
|
|
if (nonBreakingSpace == -1) nonBreakingSpace = INT_MAX;
|
|
}
|
|
|
|
if (newLine == -2)
|
|
{
|
|
newLine = stringUnicode.find (TQChar ('\n'), upto);
|
|
if (newLine == -1) newLine = INT_MAX;
|
|
}
|
|
|
|
// look for the closest one
|
|
int specialLocation = min (softHyphen, nonBreakingSpace, newLine);
|
|
|
|
// get substring (either to the end of the original string or before
|
|
// the next closest special character, if any)
|
|
int length = stringUnicodeLength - upto;
|
|
if (specialLocation != INT_MAX)
|
|
length = specialLocation - upto;
|
|
TQString substring = stringUnicode.mid (upto, length);
|
|
|
|
#ifdef DEBUG_PROCESS_TEXT
|
|
kdDebug (30509) << "Parent string: upto=" << upto
|
|
<< ",length=" << stringUnicode.length () << endl;
|
|
kdDebug (30509) << "Child string: length=" << length
|
|
<< " (specialLoc=" << specialLocation << ")" << endl;
|
|
#endif
|
|
|
|
//
|
|
// convert substring to windows-1251
|
|
//
|
|
|
|
TQCString stringWin;
|
|
|
|
// there is a codec, therefore there is an encoder...
|
|
if (m_codec)
|
|
{
|
|
int len; // don't overwrite length, we need it later
|
|
|
|
// convert from Unicode (UTF8)
|
|
stringWin = m_encoder->fromUnicode (substring, len = length);
|
|
}
|
|
else
|
|
{
|
|
// output a plain string still in wrong Character Set
|
|
// (hopefully the user won't notice)
|
|
stringWin = substring.utf8 ();
|
|
}
|
|
|
|
|
|
// output encoded text
|
|
if (!m_generator->writeText ((const MSWrite::Byte *) (const char *) stringWin))
|
|
return false;
|
|
|
|
upto += length;
|
|
|
|
// special character?
|
|
if (specialLocation != INT_MAX)
|
|
{
|
|
#ifdef DEBUG_PROCESS_TEXT
|
|
kdDebug (30509) << "Found special character!" << endl;
|
|
#endif
|
|
|
|
// output special character
|
|
if (specialLocation == softHyphen)
|
|
{
|
|
#ifdef DEBUG_PROCESS_TEXT
|
|
kdDebug (30509) << "\tSoft Hyphen" << endl;
|
|
#endif
|
|
if (!m_generator->writeOptionalHyphen ()) return false;
|
|
softHyphen = -2;
|
|
}
|
|
else if (specialLocation == nonBreakingSpace)
|
|
{
|
|
#ifdef DEBUG_PROCESS_TEXT
|
|
kdDebug (30509) << "\tNon-breaking Space" << endl;
|
|
#endif
|
|
// don't think Write supports nonBreakingSpace
|
|
if (!m_generator->writeText ((const MSWrite::Byte *) " ")) return false;
|
|
nonBreakingSpace = -2;
|
|
}
|
|
else if (specialLocation == newLine)
|
|
{
|
|
#ifdef DEBUG_PROCESS_TEXT
|
|
kdDebug (30509) << "\tNew Line" << endl;
|
|
#endif
|
|
// \r\n, not just \n
|
|
if (!m_generator->writeCarriageReturn ()) return false;
|
|
if (!m_generator->writeNewLine (true/*InternalGenerator doesn't care*/)) return false;
|
|
newLine = -2;
|
|
}
|
|
else
|
|
{
|
|
ErrorAndQuit (MSWrite::Error::InternalError, "simply impossible specialLocation\n");
|
|
}
|
|
|
|
// skip past special character
|
|
upto++;
|
|
}
|
|
} // while (upto < stringUnicodeLength) {
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
|
|
MSWriteExport::MSWriteExport (KoFilter *, const char *, const TQStringList &)
|
|
: KoFilter()
|
|
{
|
|
}
|
|
|
|
MSWriteExport::~MSWriteExport ()
|
|
{
|
|
}
|
|
|
|
KoFilter::ConversionStatus MSWriteExport::convert (const TQCString &from, const TQCString &to)
|
|
{
|
|
kdDebug (30509) << "MSWriteExport $Date: 2006-02-12 19:28:12 +0100 (Sun, 12 Feb 2006) $ using LibMSWrite "
|
|
<< MSWrite::Version << endl;
|
|
|
|
if (to != "application/x-mswrite" || from != "application/x-kword")
|
|
{
|
|
kdError (30509) << "Internal error! Filter not implemented?" << endl;
|
|
return KoFilter::NotImplemented;
|
|
}
|
|
|
|
KWordMSWriteWorker *worker = new KWordMSWriteWorker;
|
|
if (!worker)
|
|
{
|
|
kdError (30509) << "Could not allocate memory for worker" << endl;
|
|
return KoFilter::OutOfMemory;
|
|
}
|
|
|
|
KWEFKWordLeader *leader = new KWEFKWordLeader (worker);
|
|
if (!leader)
|
|
{
|
|
kdError (30509) << "Could not allocate memory for leader" << endl;
|
|
delete worker;
|
|
return KoFilter::OutOfMemory;
|
|
}
|
|
|
|
KoFilter::ConversionStatus ret = leader->convert (m_chain, from, to);
|
|
int errorCode = worker->getError ();
|
|
|
|
delete leader;
|
|
delete worker;
|
|
|
|
// try to return somewhat more meaningful errors than KoFilter::StupidError
|
|
// for the day that KOffice actually reports them to the user properly
|
|
switch (errorCode)
|
|
{
|
|
case MSWrite::Error::Ok:
|
|
kdDebug (30509) << "Returning error code " << ret << endl;
|
|
return ret; // not KoFilter::OK in case KWEFKWordLeader wants to report something
|
|
|
|
case MSWrite::Error::Warn:
|
|
kdDebug (30509) << "Error::Warn" << endl;
|
|
return KoFilter::InternalError; // warnings should _never_ set m_error
|
|
|
|
case MSWrite::Error::InvalidFormat:
|
|
kdDebug (30509) << "Error::InvalidFormat" << endl;
|
|
return KoFilter::InternalError; // how can the file I'm _writing_ be of an invalid format?
|
|
|
|
case MSWrite::Error::OutOfMemory:
|
|
kdDebug (30509) << "Error::OutOfMemory" << endl;
|
|
return KoFilter::OutOfMemory;
|
|
|
|
case MSWrite::Error::InternalError:
|
|
kdDebug (30509) << "Error::InternalError" << endl;
|
|
return KoFilter::InternalError;
|
|
|
|
case MSWrite::Error::Unsupported:
|
|
kdDebug (30509) << "Error::Unsupported" << endl;
|
|
return KoFilter::InternalError;
|
|
|
|
case MSWrite::Error::FileError:
|
|
kdDebug (30509) << "Error::FileError" << endl;
|
|
return KoFilter::CreationError;
|
|
}
|
|
|
|
kdWarning (30509) << "Unknown error" << endl;
|
|
return KoFilter::StupidError;
|
|
}
|
|
|
|
#include <mswriteexport.moc>
|