summaryrefslogtreecommitdiffstats
path: root/filters/kword/abiword
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /filters/kword/abiword
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'filters/kword/abiword')
-rw-r--r--filters/kword/abiword/CHANGES9
-rw-r--r--filters/kword/abiword/FileFormats.html124
-rw-r--r--filters/kword/abiword/ImportField.cc216
-rw-r--r--filters/kword/abiword/ImportField.h31
-rw-r--r--filters/kword/abiword/ImportFormatting.cc421
-rw-r--r--filters/kword/abiword/ImportFormatting.h132
-rw-r--r--filters/kword/abiword/ImportHelpers.cc109
-rw-r--r--filters/kword/abiword/ImportHelpers.h85
-rw-r--r--filters/kword/abiword/ImportStyle.cc128
-rw-r--r--filters/kword/abiword/ImportStyle.h51
-rw-r--r--filters/kword/abiword/Makefile.am26
-rw-r--r--filters/kword/abiword/NOTES34
-rw-r--r--filters/kword/abiword/TODO1
-rw-r--r--filters/kword/abiword/abiwordexport.cc1261
-rw-r--r--filters/kword/abiword/abiwordexport.h51
-rw-r--r--filters/kword/abiword/abiwordimport.cc1875
-rw-r--r--filters/kword/abiword/abiwordimport.h54
-rw-r--r--filters/kword/abiword/kword_abiword_export.desktop73
-rw-r--r--filters/kword/abiword/kword_abiword_import.desktop73
-rw-r--r--filters/kword/abiword/status.html219
20 files changed, 4973 insertions, 0 deletions
diff --git a/filters/kword/abiword/CHANGES b/filters/kword/abiword/CHANGES
new file mode 100644
index 000000000..53dea7e91
--- /dev/null
+++ b/filters/kword/abiword/CHANGES
@@ -0,0 +1,9 @@
+=== Post-1.2 ===
+- import/export: support for <metadata>
+- export: file format like AbiWord 1.1.2
+- export: fix bug when font name has an &
+- export: table (just the structure, no colspan, no rowspan)
+
+=== KWord 1.4 Alpha ===
+- export: fix linespacing
+- import subject/keyword in docinformation
diff --git a/filters/kword/abiword/FileFormats.html b/filters/kword/abiword/FileFormats.html
new file mode 100644
index 000000000..3b45df878
--- /dev/null
+++ b/filters/kword/abiword/FileFormats.html
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
+<!-- $Id: FileFormats.html 428241 2005-06-23 14:07:40Z pino $ -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title>FileFormats.html</title>
+<style type="text/css">
+BODY
+{
+ background-color: #FFFFFF
+}
+DT
+{
+ font-weight:bold;
+}
+SPAN.bold
+{
+ font-weight: bold;
+}
+/* The colors are PROVISORY */
+SPAN.tags
+{
+ color:red;
+}
+SPAN.doctype
+{
+ color:green;
+}
+SPAN.attribute
+{
+ color:blue;
+}
+</style>
+</head>
+<body>
+<h1>1 Foreword</h1>
+<p>AbiWord's file format has evolved with the time. The older file formats are
+XML-like, the newer ones are in XML.</p>
+
+<p>The names given for each file format are <span class="bold">not</span>
+official, it is just how I have named them.</p>
+
+<p>They might be also other variations of the file format than those described below.</p>
+
+<p>The CVS dates are the dates when I have tested and found out things. So any
+feature described must have appeared earlier. The dates are in format year-month-day.</p>
+
+<h1>2 AbiWord's File Formats</h1>
+
+<p>Here are a few versions (from oldest to newest):</p>
+
+<dt>awml</dt>
+<dd>
+The "awml" format starts with a tag <span class="tags">&lt;awml&gt;</span>
+and has no other header before. Some tags have different names than in later
+versions.
+</dd>
+
+<dt> Anonymous</dt>
+<dd>
+The "anonymous" format is the same but the tag
+<span class="tags">&lt;awml&gt;</span> is now named
+<span class="tags">&lt;abiword&gt;</span>. Some of these files have upper case
+tag and attribute names.
+</dd>
+
+<dt>Numbered</dt>
+<dd>
+The "numbered" version has a special header embeded in XML comments and the
+tag <span class="tags">&lt;abiword&gt;</span> has now a
+<span class="attribute">version</span> attribute with a version number as
+parameter.
+</dd>
+
+<dt>Unnumbered</dt>
+<dd>
+The "unnumbered" version has the version number of the
+<span class="attribute">version</span> attribute with the value "unnumbered".
+</dd>
+
+<dt>XML</dt>
+<dd>
+The "xml" version has a XML declaration (
+<span class="tags">&lt;?xml</span> ) and but has still the special header after
+the XML declaration. Note: the encoding (e.g. UTF-8) is not always given.
+</dd>
+
+<dt>File Format 1.0</dt>
+<dd>
+The "fileformat 1.0" version: the <span class="tags">&lt;abiword&gt;</span>
+tag has an attribute <span class="attribute">fileformat</span> (set to 1.0)
+</dd>
+
+<dt>Wrong Doc Type</dt>
+<dd>
+The "wrong doctype": a DOCTYPE was added with a wrong public type of:
+<span class="doctype">"-//W3C//DTD ABW 1.0 Strict//EN"</span>.
+(Wrong is the W3C part! W3C has nothing to do with AbiWord. AbiWord Bug #1882)
+</dd>
+
+<dt>Correct Doc Type</dt>
+<dd>
+The "correct doctype": (AbiWord CVS 2001-08-21) with a DOCTYPE of:
+<span class="doctype">&lt;!DOCTYPE abw PUBLIC
+"-//ABISOURCE//DTD ABW 1.0 Strict//EN" "http://www.abisource.com/awml.dtd"&gt;
+</span>
+</dd>
+
+<dt>New Doc Type / Wrong Name Space Definition</dt>
+<dd>
+The "new doctype": (AbiWord CVS 2002-02-??) with a DOCTYPE of:
+<span class="doctype">&lt;!DOCTYPE abiword PUBLIC
+"-//ABISOURCE//DTD AWML 1.0 Strict//EN" "http://www.abisource.com/awml.dtd"&gt;
+</span>
+The name space definition is wrong because it uses <span class="attribute">xmlns:awml</span>.
+However it is the default name space of the file so it should be defined by
+<span class="attribute">xmlns</span>. The <span class="tags">&lt;abiword&gt;</span>
+tag has new attributes: <span class="attribute">version</span> and
+<span class="attribute">styles</span>.
+</dd>
+
+</body>
+</html>
diff --git a/filters/kword/abiword/ImportField.cc b/filters/kword/abiword/ImportField.cc
new file mode 100644
index 000000000..bfcc5a8c2
--- /dev/null
+++ b/filters/kword/abiword/ImportField.cc
@@ -0,0 +1,216 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 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.
+*/
+
+#include <qstring.h>
+#include <qdom.h>
+
+#include <klocale.h>
+
+#include "ImportField.h"
+
+QString getFootnoteFramesetName(const QString& id)
+{
+ return i18n("Frameset name","Footnote %1").arg(id);
+}
+
+static void InsertTimeVariable(QDomDocument& mainDocument,
+ QDomElement& variableElement, QString strKey)
+{
+ QDomElement typeElement=mainDocument.createElement("TYPE");
+ typeElement.setAttribute("key",strKey);
+ typeElement.setAttribute("type",2); // Time
+ typeElement.setAttribute("text","-"); // Dummy, we let KWord do the work!
+ variableElement.appendChild(typeElement); //Append to <VARIABLE>
+ QDomElement timeElement=mainDocument.createElement("TIME");
+ // We cannot calculate the time, so default to midnight
+ timeElement.setAttribute("hour",0);
+ timeElement.setAttribute("minute",0);
+ timeElement.setAttribute("second",0);
+ timeElement.setAttribute("fix",0); // AbiWord's <field> is never fixed
+ variableElement.appendChild(timeElement); //Append to <VARIABLE>
+}
+
+static void InsertDateVariable(QDomDocument& mainDocument,
+ QDomElement& variableElement, QString strKey)
+{
+ QDomElement typeElement=mainDocument.createElement("TYPE");
+ typeElement.setAttribute("key",strKey);
+ typeElement.setAttribute("type",0); // date
+ typeElement.setAttribute("text","-"); // Just a dummy, KWord will do the work
+ variableElement.appendChild(typeElement); //Append to <VARIABLE>
+ QDomElement dateElement=mainDocument.createElement("DATE");
+ // As we have no idea about the current date, use the *nix epoch 1970-01-01
+ dateElement.setAttribute("year",1970);
+ dateElement.setAttribute("month",1);
+ dateElement.setAttribute("day",1);
+ dateElement.setAttribute("fix",0); // AbiWord's <field> is never fixed
+ variableElement.appendChild(dateElement); //Append to <VARIABLE>
+}
+
+static bool ProcessTimeField(QDomDocument& mainDocument,
+ QDomElement& variableElement, QString strType)
+// strType: AbiWord's type
+{
+ if (strType=="time")
+ {
+ InsertTimeVariable(mainDocument, variableElement, "TIMELocale");
+ }
+ else if (strType=="time_miltime")
+ {
+ // AbiWord's military time is just the standard 24h time (with seconds)
+ InsertTimeVariable(mainDocument, variableElement, "TIMEhh:mm:ss");
+ }
+ else if (strType=="time_ampm")
+ {
+ InsertTimeVariable(mainDocument, variableElement, "TIMEam");
+ }
+ else
+ {
+ // time_zone: not supported due to KWord
+ // time_epoch: not supported due to KWord (%Z)
+ return false;
+ }
+ return true;
+}
+
+static bool ProcessDateField(QDomDocument& mainDocument,
+ QDomElement& variableElement, QString strType)
+// strType: AbiWord's type
+// Help for the % formats:
+// man date
+// or
+// info date
+{
+ if (strType=="date")
+ {
+ InsertDateVariable(mainDocument, variableElement, "DATE0dddd mmmm dd, yyyy");
+ }
+ else if (strType=="date_mmddyy")
+ {
+ InsertDateVariable(mainDocument, variableElement, "DATE0mm/dd/yy");
+ }
+ else if (strType=="date_ddmmyy")
+ {
+ InsertDateVariable(mainDocument, variableElement, "DATE0dd/mm/yy");
+ }
+ else if (strType=="date_mdy")
+ {
+ InsertDateVariable(mainDocument, variableElement, "DATE0mmmm dd, yyyy");
+ }
+ else if (strType=="date_mthdy")
+ {
+ InsertDateVariable(mainDocument, variableElement, "DATE0mmm dd, yyyy");
+ }
+ else if (strType=="date_dfl")
+ { // Should be %c, but we cannot do time zones, so for now: Locale, no time! (TODO)
+ InsertDateVariable(mainDocument, variableElement, "DATE0Locale");
+ }
+ else if (strType=="date_ntdfl")
+ {
+ InsertDateVariable(mainDocument, variableElement, "DATE0Locale");
+ }
+ else if (strType=="date_wkday")
+ {
+ InsertDateVariable(mainDocument, variableElement, "DATE0dddd");
+ }
+ else
+ {
+ // date_doy: not supported (%j)
+ return false;
+ }
+ return true;
+}
+
+bool ProcessField(QDomDocument& mainDocument,
+ QDomElement& variableElement, QString strType, const QXmlAttributes& attributes)
+{
+ // In AbiWord:
+ // field names are in the file: src/text/fmt/xp/fp_Fields.h
+ // field contents are in the file: src/text/fmt/xp/fp_Run.cpp
+
+ bool done=false;
+ if (strType.startsWith("time"))
+ {
+ done=ProcessTimeField(mainDocument, variableElement, strType);
+ }
+ else if (strType.startsWith("date"))
+ {
+ done=ProcessDateField(mainDocument, variableElement, strType);
+ }
+ else if ((strType=="page_number")||(strType=="page_count"))
+ {
+ QDomElement typeElement=mainDocument.createElement("TYPE");
+ typeElement.setAttribute("key","NUMBER");
+ typeElement.setAttribute("type",4); // page number/count
+ typeElement.setAttribute("text",1); // We cannot count the pages, so give a default value
+ variableElement.appendChild(typeElement); //Append to <VARIABLE>
+ QDomElement pgnumElement=mainDocument.createElement("PGNUM");
+ pgnumElement.setAttribute("subtype",(strType=="page_count")?1:0);
+ pgnumElement.setAttribute("value",1);
+ variableElement.appendChild(pgnumElement); //Append to <VARIABLE>
+ done=true;
+ }
+ else if (strType=="file_name")
+ {
+ QDomElement typeElement=mainDocument.createElement("TYPE");
+ typeElement.setAttribute("key","STRING");
+ typeElement.setAttribute("type",8);
+ typeElement.setAttribute("text","?"); // TODO: do we need this information right now?
+ variableElement.appendChild(typeElement); //Append to <VARIABLE>
+ QDomElement fieldElement=mainDocument.createElement("FIELD");
+ fieldElement.setAttribute("subtype",0);
+ fieldElement.setAttribute("value","?"); // Should be the same as the text attribute
+ variableElement.appendChild(fieldElement); //Append to <VARIABLE>
+ done=true;
+ }
+ else if (strType=="endnote_ref")
+ {
+ QDomElement typeElement=mainDocument.createElement("TYPE");
+ typeElement.setAttribute("key","STRING");
+ typeElement.setAttribute("type",11);
+ typeElement.setAttribute("text","?"); // ### TODO: do we need this information right now?
+ variableElement.appendChild(typeElement); //Append to <VARIABLE>
+ QDomElement element=mainDocument.createElement("FOOTNOTE");
+ element.setAttribute("numberingtype","auto"); // ### TODO: support other types
+ element.setAttribute("notetype","footnote");
+ QString reference(attributes.value("endnote-id").stripWhiteSpace());
+ element.setAttribute("frameset", getFootnoteFramesetName(reference)); // ### TODO: better name
+ element.setAttribute("value","?"); // Should be the same as the text attribute
+ variableElement.appendChild(element); //Append to <VARIABLE>
+ done=true;
+ }
+
+ // Not supported:
+ // app_ver
+ // app_id
+ // app_options
+ // app_target
+ // app_compiledate
+ // app_compiletime
+ // list_label
+ // word_count
+ // char_count
+ // line_count
+ // para_count
+ // nbsp_count
+ // page_ref
+ // ...
+
+ return done;
+}
diff --git a/filters/kword/abiword/ImportField.h b/filters/kword/abiword/ImportField.h
new file mode 100644
index 000000000..e357754d2
--- /dev/null
+++ b/filters/kword/abiword/ImportField.h
@@ -0,0 +1,31 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001, 2002 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.
+*/
+
+#ifndef IMPORTFIELD_H
+#define IMPORTFIELD_H
+
+#include <qxml.h>
+
+QString getFootnoteFramesetName(const QString& id);
+bool ProcessField(QDomDocument& mainDocument,
+ QDomElement& variableElement, QString strType, const QXmlAttributes& attributes);
+
+
+#endif /* IMPORTFIELD_H */
+
diff --git a/filters/kword/abiword/ImportFormatting.cc b/filters/kword/abiword/ImportFormatting.cc
new file mode 100644
index 000000000..950d41cc8
--- /dev/null
+++ b/filters/kword/abiword/ImportFormatting.cc
@@ -0,0 +1,421 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001, 2002, 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.
+*/
+
+#include <kdebug.h>
+
+#include "ImportFormatting.h"
+#include "ImportStyle.h"
+
+StackItem::StackItem() : fontSize(0), /* No explicit font size */
+ pos(0), italic(false), bold(false), underline(false), strikeout(false),
+ textPosition(0)
+{
+}
+
+StackItem::~StackItem()
+{
+}
+
+void PopulateProperties(StackItem* stackItem, const QString& strStyleProps,
+ const QXmlAttributes& attributes, AbiPropsMap& abiPropsMap,
+ const bool allowInit)
+// TODO: find a better name for this function
+{
+ if (allowInit)
+ {
+ // Initialize the QStrings with the previous values of the properties
+ // TODO: any others needed?
+ if (stackItem->italic)
+ {
+ abiPropsMap.setProperty("font-style","italic");
+ }
+ if (stackItem->bold)
+ {
+ abiPropsMap.setProperty("font-weight","bold");
+ }
+
+ if (stackItem->underline)
+ {
+ abiPropsMap.setProperty("text-decoration","underline");
+ }
+ else if (stackItem->strikeout)
+ {
+ abiPropsMap.setProperty("text-decoration","line-through");
+ }
+ }
+
+ // Style goes first
+ kdDebug(30506)<< "===== from style=\"" << strStyleProps << "\"" << endl;
+ abiPropsMap.splitAndAddAbiProps(strStyleProps);
+ // Treat the props attributes in the two available flavors: lower case and upper case.
+ kdDebug(30506)<< "========== props=\"" << attributes.value("props") << "\"" << endl;
+ abiPropsMap.splitAndAddAbiProps(attributes.value("props"));
+ abiPropsMap.splitAndAddAbiProps(attributes.value("PROPS")); // PROPS is deprecated
+
+ stackItem->italic=(abiPropsMap["font-style"].getValue()=="italic");
+ stackItem->bold=(abiPropsMap["font-weight"].getValue()=="bold");
+
+ QString strDecoration=abiPropsMap["text-decoration"].getValue();
+ stackItem->underline=(strDecoration=="underline");
+ stackItem->strikeout=(strDecoration=="line-through");
+
+ QString strTextPosition=abiPropsMap["text-position"].getValue();
+ if (strTextPosition=="subscript")
+ {
+ stackItem->textPosition=1;
+ }
+ else if (strTextPosition=="superscript")
+ {
+ stackItem->textPosition=2;
+ }
+ else if (!strTextPosition.isEmpty())
+ {
+ // we have any other new value, assume it means normal!
+ stackItem->textPosition=0;
+ }
+
+ QString strColour=abiPropsMap["color"].getValue();
+ if (!strColour.isEmpty())
+ {
+ // The colour information is *not* lead by a hash (#)
+ stackItem->fgColor.setNamedColor("#"+strColour);
+ }
+
+ QString strBackgroundTextColor=abiPropsMap["bgcolor"].getValue();
+ if (strBackgroundTextColor=="transparent")
+ {
+ // KWord has no idea what transparency is, so we use white
+ stackItem->bgColor.setRgb(255,255,255);
+ }
+ else if(!strBackgroundTextColor.isEmpty())
+ {
+ // The colour information is *not* lead by a hash (#)
+ stackItem->bgColor.setNamedColor("#"+strBackgroundTextColor);
+ }
+
+ QString strFontSize=abiPropsMap["font-size"].getValue();
+ if (!strFontSize.isEmpty())
+ {
+ const int size=int(ValueWithLengthUnit(strFontSize));
+ if (size>0)
+ {
+ stackItem->fontSize=size;
+ }
+ }
+
+ QString strFontFamily=abiPropsMap["font-family"].getValue();
+ if (!strFontFamily.isEmpty() && (strFontFamily!="(null)"))
+ {
+ // TODO: transform the font-family in a font that we have on the system on which KWord runs.
+ stackItem->fontName=strFontFamily;
+ }
+}
+
+void AddFormat(QDomElement& formatElementOut, StackItem* stackItem, QDomDocument& mainDocument)
+{
+ QDomElement element;
+ if (!stackItem->fontName.isEmpty())
+ {
+ element=mainDocument.createElement("FONT");
+ element.setAttribute("name",stackItem->fontName); // Font name
+ formatElementOut.appendChild(element); //Append to <FORMAT>
+ }
+
+ if (stackItem->fontSize>0)
+ {
+ element=mainDocument.createElement("SIZE");
+ element.setAttribute("value",stackItem->fontSize);
+ formatElementOut.appendChild(element); //Append to <FORMAT>
+ }
+
+ element=mainDocument.createElement("ITALIC");
+ element.setAttribute("value",stackItem->italic?1:0);
+ formatElementOut.appendChild(element); //Append to <FORMAT>
+
+ element=mainDocument.createElement("WEIGHT");
+ element.setAttribute("value",stackItem->bold?75:50);
+ formatElementOut.appendChild(element); //Append to <FORMAT>
+
+ element=mainDocument.createElement("UNDERLINE");
+ element.setAttribute("value",stackItem->underline?1:0);
+ formatElementOut.appendChild(element); //Append to <FORMAT>
+
+ element=mainDocument.createElement("STRIKEOUT");
+ element.setAttribute("value",stackItem->strikeout?1:0);
+ formatElementOut.appendChild(element); //Append to <FORMAT>
+
+ if ((stackItem->textPosition>=0) && (stackItem->textPosition<=2))
+ {
+ element=mainDocument.createElement("VERTALIGN");
+ element.setAttribute("value",stackItem->textPosition);
+ formatElementOut.appendChild(element); //Append to <FORMAT>
+ }
+
+ if (stackItem->fgColor.isValid())
+ {
+ element=mainDocument.createElement("COLOR");
+ element.setAttribute("red", stackItem->fgColor.red());
+ element.setAttribute("green",stackItem->fgColor.green());
+ element.setAttribute("blue", stackItem->fgColor.blue());
+ formatElementOut.appendChild(element); //Append to <FORMAT>
+ }
+
+ if (stackItem->bgColor.isValid())
+ {
+ element=mainDocument.createElement("TEXTBACKGROUNDCOLOR");
+ element.setAttribute("red", stackItem->bgColor.red());
+ element.setAttribute("green",stackItem->bgColor.green());
+ element.setAttribute("blue", stackItem->bgColor.blue());
+ formatElementOut.appendChild(element); //Append to <FORMAT>
+ }
+}
+
+void AddLayout(const QString& strStyleName, QDomElement& layoutElement,
+ StackItem* stackItem, QDomDocument& mainDocument,
+ const AbiPropsMap& abiPropsMap, const int level, const bool isStyle)
+{
+ QDomElement element;
+ element=mainDocument.createElement("NAME");
+ element.setAttribute("value",strStyleName);
+ layoutElement.appendChild(element);
+
+ QString strFollowing=abiPropsMap["followedby"].getValue();
+ QDomElement followingElement=mainDocument.createElement("FOLLOWING");
+ followingElement.setAttribute("name",strFollowing);
+ if ((strFollowing.isEmpty())
+ || (strFollowing=="Current Settings")) // "Current Settings" is only a pseudo-style!
+ {
+ // We have no idea what style follows
+ if (isStyle)
+ {
+ // We are a style, so we need a default
+ followingElement.setAttribute("name","Normal");
+ layoutElement.appendChild(followingElement);
+ }
+ // Else: we are a layout, so we leave the work to KWord (from the style)
+ }
+ else
+ {
+ // Following style is defined
+ // TODO: we should be sure that this style is defined!
+ layoutElement.appendChild(followingElement);
+ }
+
+ QString strFlow=abiPropsMap["text-align"].getValue();
+ element=mainDocument.createElement("FLOW");
+ if ((strFlow=="left") || (strFlow=="center") || (strFlow=="right") || (strFlow=="justify"))
+ {
+ element.setAttribute("align",strFlow);
+ }
+ else
+ {
+ element.setAttribute("align","left");
+ }
+ layoutElement.appendChild(element);
+
+ int kwordDepth;
+ int kwordNumberingType;
+ int kwordType;
+ QString kwordRightText;
+ // level is 1 based like AbiWord, any value lower than 1 means no level!
+ if ((level<=0) || (level>=15))
+ {
+ kwordDepth=0;
+ kwordNumberingType=2;
+ kwordType=0;
+ }
+ else
+ {
+ kwordDepth=level-1;
+ kwordNumberingType=1;
+ kwordType=1; // PROVISORY
+ kwordRightText=".";
+ }
+
+ element=mainDocument.createElement("COUNTER");
+ element.setAttribute("type",kwordType);
+ element.setAttribute("depth",kwordDepth);
+ element.setAttribute("start",1);
+ element.setAttribute("numberingtype",kwordNumberingType);
+ element.setAttribute("lefttext","");
+ element.setAttribute("righttext",kwordRightText);
+ element.setAttribute("bullet",64);
+ element.setAttribute("bulletfont","Symbol");
+ element.setAttribute("customdef","");
+ layoutElement.appendChild(element);
+
+ QString strLeftMargin=abiPropsMap["margin-left"].getValue();
+ QString strRightMargin=abiPropsMap["margin-right"].getValue();
+ QString strTextIndent=abiPropsMap["text-indent"].getValue();
+
+ if ( !strLeftMargin.isEmpty()
+ || !strRightMargin.isEmpty()
+ || !strTextIndent.isEmpty() )
+ {
+ element=mainDocument.createElement("INDENTS");
+ if (!strLeftMargin.isEmpty())
+ element.setAttribute("left",ValueWithLengthUnit(strLeftMargin));
+ if (!strRightMargin.isEmpty())
+ element.setAttribute("right",ValueWithLengthUnit(strRightMargin));
+ if (!strTextIndent.isEmpty())
+ element.setAttribute("first",ValueWithLengthUnit(strTextIndent));
+ layoutElement.appendChild(element);
+ }
+
+ QString strTopMargin=abiPropsMap["margin-top"].getValue();
+ QString strBottomMargin=abiPropsMap["margin-bottom"].getValue();
+ if (!strTopMargin.isEmpty() || !strBottomMargin.isEmpty() )
+ {
+ element=mainDocument.createElement("OFFSETS");
+ const double margin_top=ValueWithLengthUnit(strTopMargin);
+ const double margin_bottom=ValueWithLengthUnit(strBottomMargin);
+ // Zero is propably a valid value!
+ if (!strBottomMargin.isEmpty())
+ element.setAttribute("after",margin_bottom);
+ if (!strTopMargin.isEmpty())
+ element.setAttribute("before",margin_top);
+ layoutElement.appendChild(element);
+ }
+
+ QString strLineHeight=abiPropsMap["line-height"].getValue();
+ if(!strLineHeight.isEmpty())
+ {
+ element=mainDocument.createElement("LINESPACING");
+ double lineHeight;
+ // Do we have a unit symbol or not?
+ bool flag=false;
+ lineHeight=strLineHeight.toDouble(&flag);
+
+ if (flag)
+ {
+ if ( lineHeight == 1.0 )
+ {
+ element.setAttribute( "value", "single" );
+ element.setAttribute( "type", "single" );
+ }
+ else if (lineHeight==1.5)
+ {
+ element.setAttribute( "value", "oneandhalf" );
+ element.setAttribute( "type", "oneandhalf" );
+ }
+ else if (lineHeight==2.0)
+ {
+ element.setAttribute( "value", "double" );
+ element.setAttribute( "type", "double" );
+ }
+ else if ( lineHeight > 0.0 )
+ {
+ element.setAttribute( "type", "multiple" );
+ element.setAttribute( "spacingvalue", lineHeight );
+ }
+ else
+ {
+ kdWarning(30506) << "Unsupported line height " << lineHeight << " (Ignoring !)" << endl;
+ }
+ }
+ else
+ {
+ // Something went wrong, so we assume that an unit is specified
+ bool atleast = false;
+ lineHeight = ValueWithLengthUnit( strLineHeight, &atleast );
+ if (lineHeight>1.0)
+ {
+ if ( atleast )
+ {
+ kdDebug(30506) << "at-least" << endl;
+ element.setAttribute( "type", "atleast" );
+ }
+ else
+ {
+ element.setAttribute( "type", "exact" );
+ }
+
+ // We have a meaningful value, so use it!
+ //element.setAttribute( "value", lineHeight );
+ element.setAttribute( "spacingvalue", lineHeight );
+ }
+ }
+ layoutElement.appendChild(element);
+ }
+
+ QString strTab=abiPropsMap["tabstops"].getValue();
+ if(!strTab.isEmpty())
+ {
+ QStringList listTab=QStringList::split(",",strTab);
+ for ( QStringList::Iterator it = listTab.begin(); it != listTab.end(); ++it )
+ {
+ QStringList tab=QStringList::split("/",*it);
+ const QChar tabType=tab[1].at(0);
+ const QChar tabFilling=tab[1].at(1); // Might be empty in old AbiWord files
+ int type;
+ if (tabType=='L') // left
+ type=0;
+ else if (tabType=='C') // center
+ type=1;
+ else if (tabType=='R') // right
+ type=2;
+ else if(tabType=='D') // decimal
+ type=3;
+ else if(tabType=='B') // bar (unsupported by KWord)
+ type=0;
+ else
+ {
+ kdWarning(30506)<<"Unknown tabulator type: " << QString(tabType) << endl;
+ type=0;
+ }
+ int filling;
+ int width=72; // Any non-null value
+ if (tabFilling.isNull() || tabFilling=='0') // No filling
+ filling=0;
+ else if (tabFilling=='1') // dot
+ {
+ filling=1;
+ width=2; // TODO: which width?
+ }
+ else if (tabFilling=='3') // underline
+ filling=2;
+ else
+ filling=0;
+ element=mainDocument.createElement("TABULATOR");
+ element.setAttribute("ptpos",ValueWithLengthUnit(tab[0]));
+ element.setAttribute("type",type);
+ element.setAttribute("filling",filling);
+ element.setAttribute("width",width);
+ layoutElement.appendChild(element);
+ }
+ }
+
+ QDomElement formatElementOut=mainDocument.createElement("FORMAT");
+ layoutElement.appendChild(formatElementOut);
+
+ AddFormat(formatElementOut, stackItem, mainDocument);
+}
+
+void AddStyle(QDomElement& styleElement, const QString& strStyleName,
+ const StyleData& styleData, QDomDocument& mainDocument)
+{
+ // NOTE; styleElement is <STYLE> (singular), not <STYLES> (plural)
+
+ StackItem stackItem;
+ QXmlAttributes attributes; // This is just a dummy for reusing already existing functions (TODO)
+ AbiPropsMap abiPropsMap;
+
+ PopulateProperties(&stackItem, styleData.m_props, attributes, abiPropsMap, false);
+ AddLayout(strStyleName, styleElement, &stackItem, mainDocument, abiPropsMap, styleData.m_level, true);
+}
diff --git a/filters/kword/abiword/ImportFormatting.h b/filters/kword/abiword/ImportFormatting.h
new file mode 100644
index 000000000..e7f9e000d
--- /dev/null
+++ b/filters/kword/abiword/ImportFormatting.h
@@ -0,0 +1,132 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001, 2002, 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.
+*/
+
+#ifndef _IMPORT_FORMATTING_H
+#define _IMPORT_FORMATTING_H
+
+#include <qptrstack.h>
+#include <qstring.h>
+#include <qcolor.h>
+#include <qxml.h>
+#include <qdom.h>
+
+#include "ImportHelpers.h"
+
+// Tags in lower case (e.g. <c>) are AbiWord's ones.
+// Tags in upper case (e.g. <TEXT>) are KWord's ones.
+
+// Note: as we are not validating anything, we are quite tolerant about the file
+// that we will read.
+
+/**
+ * States
+ *
+ * Tags that we do not care of:
+ * \<abiword\> (or \<awml\>), \<data\>, \<styles\>, \<ignorewords\>, \<lists\>, \<metadata\>
+ *
+ * Tags that we do not support (however KWord could):
+ * \<bookmark\>, \<l\>
+ *
+ * Tags that we cannot support (lack of support in KWord):
+ * N/A
+ *
+ * Properties that we do not or cannot support:
+ * page-margin-footer, page-margin-header, lang, font-stretch, keep-with-next...
+ */
+enum StackItemElementType{
+ ElementTypeUnknown = 0,
+ ElementTypeBottom, ///< Bottom of the stack
+ ElementTypeIgnore, ///< Element is known but ignored
+ ElementTypeEmpty, ///< Element is empty (\<pagesize\>, \<s\>, \<image\>, \<field\>, \<br\>, \<cbr\>, \<pbr\>)
+ ElementTypeSection, ///< \<section\>
+ ElementTypeParagraph, ///< \<p\>
+ ElementTypeContent, ///< \<c\> (not child of \<a\>), also \<a\> if it points to a bookmark
+ ElementTypeRealData, ///< \<d\>
+ ElementTypeAnchor, ///< \<a\>
+ ElementTypeAnchorContent,///< \<c\> when child of \<a\>
+ ElementTypeIgnoreWord, ///< \<iw\>
+ ElementTypeRealMetaData,///< \<m\>
+ ElementTypeFoot, ///< \<foot\>
+ ElementTypeTable, ///< \<table\>
+ ElementTypeCell ///< \<cell\>
+};
+
+
+class StackItem
+{
+public:
+ StackItem();
+ ~StackItem();
+public:
+ QString itemName; ///< Name of the tag (only for error purposes)
+ StackItemElementType elementType;
+ QDomElement m_frameset; ///< current \<FRAMESET\>
+ QDomElement stackElementParagraph; ///< \<PARAGRAPH\>
+ QDomElement stackElementText; ///< \<TEXT\>
+ QDomElement stackElementFormatsPlural; ///< \<FORMATS\>
+ QString fontName; ///< font name but for \<d\>: name
+ int fontSize;
+ int pos; ///< Position
+ bool italic;
+ bool bold; ///< bold but for \<d\>: is base64 coded?
+ bool underline;
+ bool strikeout;
+ QColor fgColor;
+ QColor bgColor;
+ int textPosition; ///< Normal (0), subscript(1), superscript (2)
+ QString strTemp1; /**< for \<d\>: mime type
+ * for \<a\>: link reference
+ * for \<m\>: key
+ * for \<table\>: KWord's table name
+ */
+ QString strTemp2; /**< for \<d\>: collecting the data
+ * for \<a\>: link name
+ * for \<iw\>: collecting the data (i.e. word to ignore)
+ * for \<m\>: value of the meta data
+ * for \<table\>: Number of the table (needed as I18N does not allow adding phrases)
+ */
+ /**
+ * for tables (\<table\>, \<cell\>): defines the widths of the columns.
+ * Be careful: we are using the shallow copy mechanism of Qt. Use QMemArray::detach when needed to avoid modifying the parents
+ */
+ QMemArray<double> m_doubleArray;
+};
+
+class StackItemStack : public QPtrStack<StackItem>
+{
+public:
+ StackItemStack(void) { }
+ virtual ~StackItemStack(void) { }
+};
+
+class StyleData;
+
+void PopulateProperties(StackItem* stackItem, const QString& strStyleProps,
+ const QXmlAttributes& attributes, AbiPropsMap& abiPropsMap,
+ const bool allowInit);
+void AddFormat(QDomElement& formatElementOut, StackItem* stackItem,
+ QDomDocument& mainDocument);
+void AddLayout(const QString& strStyleName, QDomElement& layoutElement,
+ StackItem* stackItem, QDomDocument& mainDocument,
+ const AbiPropsMap& abiPropsMap, const int level, const bool isStyle);
+void AddStyle(QDomElement& styleElement, const QString& strStyleName,
+ const StyleData& styleData, QDomDocument& mainDocument);
+
+
+#endif // _IMPORT_FORMATTING_H
diff --git a/filters/kword/abiword/ImportHelpers.cc b/filters/kword/abiword/ImportHelpers.cc
new file mode 100644
index 000000000..19b4bac46
--- /dev/null
+++ b/filters/kword/abiword/ImportHelpers.cc
@@ -0,0 +1,109 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 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.
+*/
+
+#include <qstringlist.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+
+#include "ImportHelpers.h"
+
+bool AbiPropsMap::setProperty(const QString& newName, const QString& newValue)
+{
+ replace(newName,AbiProps(newValue));
+ return true;
+}
+
+// Treat the "props" attribute of AbiWord's tags and split it in separates names and values
+void AbiPropsMap::splitAndAddAbiProps(const QString& strProps)
+{
+ if (strProps.isEmpty())
+ return;
+ // Split the properties (we do not want empty ones)
+ QStringList list=QStringList::split(';',strProps,false);
+ QString name,value;
+
+ QStringList::ConstIterator it;
+ QStringList::ConstIterator end(list.end());
+ for (it=list.begin();it!=end;++it)
+ {
+ const int result=(*it).find(':');
+ if (result==-1)
+ {
+ name=(*it);
+ value=QString::null;
+ kdWarning(30506) << "Property without value: " << name << endl;
+ }
+ else
+ {
+ name=(*it).left(result);
+ value=(*it).mid(result+1);
+ }
+ // kdDebug(30506) << "========== (Property :" << name.stripWhiteSpace()<< "=" << value.stripWhiteSpace() <<":)"<<endl;
+ // Now set the property
+ setProperty(name.stripWhiteSpace(),value.stripWhiteSpace());
+ }
+}
+
+double ValueWithLengthUnit( const QString& _str, bool* atleast )
+{
+ if ( atleast )
+ *atleast = false;
+
+ double result;
+ // We search an unit (defined by a sequence of lower case characters), with possibly a + sign after it
+ QRegExp unitExp("([a-z]+)\\s*(\\+?)");
+ const int pos=unitExp.search(_str);
+ if (pos==-1)
+ {
+ bool flag=false;
+ result=_str.toDouble(&flag);
+ if (!flag)
+ kdWarning(30506) << "Unknown value: " << _str << " (ValueWithLengthUnit)" << endl;
+ }
+ else
+ {
+ const double rawValue=_str.left(pos).toDouble();
+ const QString strUnit ( unitExp.cap(1) );
+ if (strUnit=="cm")
+ result=CentimetresToPoints(rawValue);
+ else if (strUnit=="in")
+ result=InchesToPoints(rawValue);
+ else if (strUnit=="mm")
+ result=MillimetresToPoints(rawValue);
+ else if (strUnit=="pt")
+ result=rawValue;
+ else if(strUnit=="pi")
+ result=PicaToPoints(rawValue);
+ else
+ {
+ kdWarning(30506) << "Value " << _str << " has non-supported unit: "
+ << strUnit << " (ValueWithLengthUnit)" << endl;
+ result=rawValue;
+ }
+
+ if ( atleast )
+ {
+ *atleast = ( unitExp.cap(2) == "+" );
+ }
+
+ // kdDebug(30506) << "Value: " << _str << " Unit: " << strUnit << " Result: " << result << endl;
+ }
+ return result;
+}
diff --git a/filters/kword/abiword/ImportHelpers.h b/filters/kword/abiword/ImportHelpers.h
new file mode 100644
index 000000000..bc72c4ab3
--- /dev/null
+++ b/filters/kword/abiword/ImportHelpers.h
@@ -0,0 +1,85 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001, 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.
+*/
+
+#ifndef _IMPORT_HELPERS_H
+#define _IMPORT_HELPERS_H
+
+#include <qstring.h>
+#include <qmap.h>
+
+/**
+ * \file ImportHelpers.h
+ * Helpers for the AbiWord import filter
+ *
+ * Rough rule for including code in this file:
+ * use nothing of QT except QMap, QValueList and QString
+ */
+
+class AbiProps
+{
+public:
+ AbiProps() {};
+ AbiProps(QString newValue) : m_value(newValue) {};
+ virtual ~AbiProps() {};
+public:
+ inline QString getValue(void) const { return m_value; }
+private:
+ QString m_value;
+};
+
+class AbiPropsMap : public QMap<QString,AbiProps>
+{
+public:
+ AbiPropsMap() {};
+ virtual ~AbiPropsMap() {};
+public:
+ bool setProperty(const QString& newName, const QString& newValue);
+ void splitAndAddAbiProps(const QString& strProps);
+};
+
+inline double CentimetresToPoints(const double d)
+{
+ return d * 72.0 / 2.54;
+}
+
+inline double MillimetresToPoints(const double d)
+{
+ return d * 72.0 / 25.4;
+}
+
+inline double InchesToPoints(const double d)
+{
+ return d * 72.0;
+}
+
+inline double PicaToPoints(const double d)
+{
+ // 1 pica = 12 pt
+ return d * 12.0;
+}
+
+/**
+ * Transform a value with unit (for example "12cm") into a double
+ * @param _str the value as string
+ * @param atleast was there a + character after the unit to denote an "at-least" property
+ * @return the value as double (in points)
+ */
+double ValueWithLengthUnit( const QString& _str, bool* atleast = NULL );
+
+#endif // _IMPORT_HELPERS_H
diff --git a/filters/kword/abiword/ImportStyle.cc b/filters/kword/abiword/ImportStyle.cc
new file mode 100644
index 000000000..e5d371de1
--- /dev/null
+++ b/filters/kword/abiword/ImportStyle.cc
@@ -0,0 +1,128 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 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.
+*/
+
+#include <qfontinfo.h>
+
+#include <kglobalsettings.h>
+#include <kdebug.h>
+
+#include <KoGlobal.h>
+
+#include "ImportStyle.h"
+
+StyleData::StyleData(void): m_level(-1)
+{
+}
+
+StyleDataMap::StyleDataMap(void)
+{
+}
+
+QString StyleDataMap::getDefaultStyle(void)
+{
+ // We use QFontInfo, as it return real values
+ QFontInfo fontInfo(KoGlobal::defaultFont());
+ QString strReturn;
+
+ strReturn += "font-family:";
+ strReturn += fontInfo.family(); // TODO: should be "Times New Roman"
+ strReturn += "; font-size: 12pt;";
+ // Note: the last property must have a semi-colon!
+
+ return strReturn;
+}
+
+void StyleDataMap::defineNewStyleFromOld(const QString& strName, const QString& strOld,
+ const int level, const QString& strProps)
+{
+ if (strOld.isEmpty())
+ {
+ defineNewStyle(strName,level,strProps);
+ return;
+ }
+
+ StyleDataMap::Iterator it=find(strOld);
+ if (it==end())
+ {
+ defineNewStyle(strName,level,strProps);
+ }
+ else
+ {
+ QString strAllProps=it.data().m_props;
+ strAllProps+=strProps;
+ defineNewStyle(strName,level,strAllProps);
+ }
+}
+
+
+void StyleDataMap::defineNewStyle(const QString& strName, const int level,
+ const QString& strProps)
+{
+ // Despite its name, this method can be called multiple times
+ // We must take care that KWord just gets it only one time.
+ StyleDataMap::Iterator it=find(strName);
+ if (it==end())
+ {
+ // The style does not exist yet, so we must define it.
+ it=insert(strName,StyleData());
+ }
+ StyleData& styleData=it.data();
+ styleData.m_level=level;
+ styleData.m_props+=getDefaultStyle();
+ if (!strProps.isEmpty())
+ {
+ styleData.m_props+=strProps;
+ styleData.m_props+=";"; // Security if other properties are appended later
+ }
+}
+
+StyleDataMap::Iterator StyleDataMap::useOrCreateStyle(const QString& strName)
+{
+ // We are using a style but we are not sure if it is defined
+ StyleDataMap::Iterator it=find(strName);
+ if (it==end())
+ {
+ // The style is not yet defined!
+ StyleData data;
+ data.m_level=-1;
+ data.m_props=getDefaultStyle();
+ it=insert(strName,data);
+ }
+ return it;
+}
+
+void StyleDataMap::defineDefaultStyles(void)
+{
+ // Add a few of AbiWord predefined style sheets
+ // AbiWord file: src/text/ptbl/xp/pt_PT_Styles.cpp
+ defineNewStyle("Normal",-1,QString::null);
+ // TODO: font should be "Arial"
+ // TODO: "keep with next"
+ QString strHeading("font-weight: bold; margin-top: 22pt; margin-bottom: 3pt; ");
+ defineNewStyle("Heading 1",1,strHeading+"font-size: 17pt");
+ defineNewStyle("Heading 2",2,strHeading+"font-size: 14pt");
+ defineNewStyle("Heading 3",3,strHeading+"font-size: 12pt");
+ defineNewStyle("Block Text",-1,"margin-left: 1in; margin-right: 1in; margin-bottom: 6pt");
+ QFontInfo fixedInfo(KGlobalSettings::fixedFont());
+ QString strPlainText=QString("font-family: %1")
+ .arg(fixedInfo.family()); // TODO: should be "Courier New"
+ kdDebug(30506) << "Plain Text: " << strPlainText << endl;
+ defineNewStyle("Plain Text",-1,strPlainText);
+ // TODO: all list and numbered types
+}
diff --git a/filters/kword/abiword/ImportStyle.h b/filters/kword/abiword/ImportStyle.h
new file mode 100644
index 000000000..b812640ad
--- /dev/null
+++ b/filters/kword/abiword/ImportStyle.h
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 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.
+*/
+
+#ifndef _IMPORT_STYLE_H
+#define _IMPORT_STYLE_H
+
+#include <qvaluelist.h>
+#include <qstring.h>
+#include <qmap.h>
+
+class StyleData
+{
+public:
+ StyleData(void);
+public:
+ int m_level; // Depth of heading (as defined by AbiWord!)
+ QString m_props; // properties
+};
+
+class StyleDataMap : public QMap<QString,StyleData>
+{
+public:
+ StyleDataMap(void);
+public:
+ void defineNewStyle(const QString& strName, const int level, const QString& strProps);
+ void defineNewStyleFromOld(const QString& strName, const QString& strOld,
+ const int level, const QString& strProps);
+ StyleDataMap::Iterator useOrCreateStyle(const QString& strName);
+ void defineDefaultStyles(void);
+private:
+ QString getDefaultStyle(void);
+};
+
+#endif // _IMPORT_STYLE_H
+
diff --git a/filters/kword/abiword/Makefile.am b/filters/kword/abiword/Makefile.am
new file mode 100644
index 000000000..0a0f1f824
--- /dev/null
+++ b/filters/kword/abiword/Makefile.am
@@ -0,0 +1,26 @@
+####### General stuff
+
+INCLUDES= -I$(srcdir) $(KOFFICE_INCLUDES) -I$(srcdir)/../libexport $(all_includes)
+
+libabiwordimport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libabiwordimport_la_LIBADD = $(KOFFICE_LIBS)
+
+libabiwordexport_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+libabiwordexport_la_LIBADD = $(KOFFICE_LIBS) ../libexport/libkwordexportfilters.la
+
+####### Files
+
+kde_module_LTLIBRARIES = libabiwordimport.la libabiwordexport.la
+
+libabiwordimport_la_SOURCES = abiwordimport.cc ImportHelpers.cc\
+ImportFormatting.cc ImportStyle.cc ImportField.cc
+
+libabiwordexport_la_SOURCES = abiwordexport.cc
+
+noinst_HEADERS = abiwordimport.h ImportHelpers.h ImportFormatting.h\
+ImportStyle.h ImportField.h abiwordexport.h
+
+METASOURCES = AUTO
+
+service_DATA = kword_abiword_import.desktop kword_abiword_export.desktop
+servicedir = $(kde_servicesdir)
diff --git a/filters/kword/abiword/NOTES b/filters/kword/abiword/NOTES
new file mode 100644
index 000000000..bdca2d26f
--- /dev/null
+++ b/filters/kword/abiword/NOTES
@@ -0,0 +1,34 @@
+1. Welcome
+
+ Welcome to KWord's AbiWord import/export filter.
+
+ For now, this file is just a storage for some technical notes.
+
+2. AbiWord's Multiple File Formats
+
+ AbiWord's file format has evolved with the time. The older file formats are
+ XML-like, the newer ones are in XML.
+
+ See the file FileFormats.html for an overview!
+
+ The AbiWord filter for KWord *must* be able to read all those formats. A user
+ will not be happy if you tell him that his sub-version is not supported!
+
+ However to make it easier all these formats differ mainly only in the header.
+ (Only the "awml" format has different names for some tags.)
+
+ Additionally, some files ("anonymous" ones?) seems to have tags and attributes
+ in upper case. This must also be taken care of.
+
+ Files in all those formats can be found in the source distribution of AbiWord
+ (www.abisource.com), see in AbiWord's source code under the sub-directory
+ test/wp and under its own sub-directories.
+
+3. A Few Problems
+
+ AbiWord is still in development. Be careful that future file formats does not
+ contain potential problems. At least they should not crash the import filter.
+
+ You must really look into AbiWord's source code, as you will have the surprise
+ to find that the documented file format (also in the source distribution) does
+ not tell everything.
diff --git a/filters/kword/abiword/TODO b/filters/kword/abiword/TODO
new file mode 100644
index 000000000..b3dcbffcf
--- /dev/null
+++ b/filters/kword/abiword/TODO
@@ -0,0 +1 @@
+- substitution of fonts at import (also at export?)
diff --git a/filters/kword/abiword/abiwordexport.cc b/filters/kword/abiword/abiwordexport.cc
new file mode 100644
index 000000000..31733bd6e
--- /dev/null
+++ b/filters/kword/abiword/abiwordexport.cc
@@ -0,0 +1,1261 @@
+/* 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 <qmap.h>
+#include <qiodevice.h>
+#include <qtextstream.h>
+#include <qdom.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 QMap<QString,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 QString& filenameOut, const QString& to);
+ virtual bool doCloseFile(void); // Close file in normal conditions
+ virtual bool doOpenDocument(void);
+ virtual bool doCloseDocument(void);
+ virtual bool doFullParagraph(const QString& paraText, const LayoutData& layout,
+ 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& layout); // AbiWord's <s></s>
+ virtual bool doOpenSpellCheckIgnoreList (void); // AbiWord's <ignorewords>
+ virtual bool doCloseSpellCheckIgnoreList (void); // AbiWord's </ignorewords>
+ virtual bool doFullSpellCheckIgnoreWord (const QString& ignoreword); // AbiWord's <iw>
+ virtual bool doFullDocumentInfo(const KWEFDocumentInfo& docInfo); // AbiWord's <metadata>
+private:
+ void processParagraphData (const QString& paraText,
+ const TextFormatting& formatLayout,
+ const ValueListFormatData& paraFormatDataList);
+ void processNormalText ( const QString& paraText,
+ const TextFormatting& formatLayout,
+ const FormatData& formatData);
+ void processVariable ( const QString& paraText,
+ const TextFormatting& formatLayout,
+ const FormatData& formatData);
+ void processAnchor ( const QString& paraText,
+ const TextFormatting& formatLayout,
+ const FormatData& formatData);
+ QString textFormatToAbiProps(const TextFormatting& formatOrigin,
+ const TextFormatting& formatData, const bool force) const;
+ QString layoutToCss(const LayoutData& layoutOrigin,
+ const LayoutData& layout, const bool force) const;
+ QString escapeAbiWordText(const QString& strText) const;
+ bool makeTable(const FrameAnchor& anchor);
+ bool makePicture(const FrameAnchor& anchor);
+ void writeAbiProps(const TextFormatting& formatLayout, const TextFormatting& format);
+ void writePictureData(const QString& koStoreName, const QString& keyName);
+ QString transformToTextDate(const QDateTime& dt);
+private:
+ QIODevice* m_ioDevice;
+ QTextStream* m_streamOut;
+ QString m_pagesize; // Buffer for the <pagesize> tag
+ QMap<QString,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)
+{
+}
+
+QString AbiWordWorker::escapeAbiWordText(const QString& strText) const
+{
+ // Escape quotes (needed in attributes)
+ // Escape apostrophs (allowed by XML)
+ return KWEFUtil::EscapeSgmlText(NULL,strText,true,true);
+}
+
+bool AbiWordWorker::doOpenFile(const QString& filenameOut, const QString& )
+{
+ kdDebug(30506) << "Opening file: " << filenameOut
+ << " (in AbiWordWorker::doOpenFile)" << endl;
+ //Find the last extension
+ QString strExt;
+ const int result=filenameOut.findRev('.');
+ if (result>=0)
+ {
+ strExt=filenameOut.mid(result);
+ }
+
+ QString 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 QTextStream(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( QTextStream::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 QString& koStoreName, const QString& keyName)
+{
+ kdDebug(30506) << "AbiWordWorker::writeImageData" << endl;
+
+ QByteArray image;
+
+ QString strExtension(koStoreName.lower());
+ const int result=koStoreName.findRev(".");
+ if (result>=0)
+ {
+ strExtension=koStoreName.mid(result+1);
+ }
+
+ bool isImageLoaded=false;
+
+ if (strExtension=="png")
+ {
+ isImageLoaded=loadSubFile(koStoreName,image);
+ }
+ else
+ {
+ // All other picture types must be converted to PNG
+ // (yes, even JPEG, SVG or WMF!)
+ isImageLoaded=loadAndConvertToImage(koStoreName,strExtension,"PNG",image);
+ }
+
+ if (isImageLoaded)
+ {
+ *m_streamOut << "<d name=\"" << keyName << "\""
+ << " base64=\"yes\""
+ << " mime=\"image/png\">\n";
+
+ QCString base64=KCodecs::base64Encode(image,true);
+
+ *m_streamOut << base64 << "\n"; // QCString is taken as Latin1 by QTextStream
+
+ *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";
+
+ QMap<QString,KoPictureKey>::ConstIterator it;
+ QMap<QString,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;
+}
+
+QString AbiWordWorker::textFormatToAbiProps(const TextFormatting& formatOrigin,
+ const TextFormatting& formatData, const bool force) const
+{
+ // TODO: rename variable formatData
+ QString strElement; // TODO: rename this variable
+
+ // Font name
+ QString 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+=QString::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 += QString::number((red&0xf0)>>4,16);
+ strElement += QString::number(red&0x0f,16);
+
+ const int green=formatData.fgColor.green();
+ strElement += QString::number((green&0xf0)>>4,16);
+ strElement += QString::number(green&0x0f,16);
+
+ const int blue=formatData.fgColor.blue();
+ strElement += QString::number((blue&0xf0)>>4,16);
+ strElement += QString::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 += QString::number((red&0xf0)>>4,16);
+ strElement += QString::number(red&0x0f,16);
+
+ const int green=formatData.bgColor.green();
+ strElement += QString::number((green&0xf0)>>4,16);
+ strElement += QString::number(green&0x0f,16);
+
+ const int blue=formatData.bgColor.blue();
+ strElement += QString::number((blue&0xf0)>>4,16);
+ strElement += QString::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
+
+ QValueList<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)
+{
+ QString abiprops=textFormatToAbiProps(formatLayout,format,false);
+
+ // Erase the last semi-comma (as in CSS2, semi-commas only separate instructions and do not terminate them)
+ const int result=abiprops.findRev(";");
+
+ if (result>=0)
+ {
+ // Remove the last semi-comma and the space thereafter
+ abiprops.remove(result,2);
+ }
+
+ if (!abiprops.isEmpty())
+ {
+ *m_streamOut << " props=\"" << abiprops << "\"";
+ }
+}
+
+void AbiWordWorker::processNormalText ( const QString &paraText,
+ const TextFormatting& formatLayout,
+ const FormatData& formatData)
+{
+ // Retrieve text and escape it
+ QString partialText=escapeAbiWordText(paraText.mid(formatData.pos,formatData.len));
+
+ // Replace line feeds by line breaks
+ int pos;
+ while ((pos=partialText.find(QChar(10)))>-1)
+ {
+ partialText.replace(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 QString&,
+ 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
+ QString 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
+ QString value = (*paraFormatDataIt).variable.getFootnoteValue();
+ bool automatic = (*paraFormatDataIt).variable.getFootnoteAuto();
+ QValueList<ParaData> *paraList = (*paraFormatDataIt).variable.getFootnotePara();
+ if( paraList )
+ {
+ QString fstr;
+ QValueList<ParaData>::ConstIterator it;
+ for (it=paraList->begin();it!=paraList->end();it++)
+ fstr += ProcessParagraphData( (*it).text, (*it).layout,(*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 QString&,
+ 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 QString &paraText,
+ const TextFormatting& formatLayout,
+ const ValueListFormatData &paraFormatDataList)
+{
+ 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));
+ }
+ }
+ }
+}
+
+QString AbiWordWorker::layoutToCss(const LayoutData& layoutOrigin,
+ const LayoutData& layout, const bool force) const
+{
+ QString props;
+
+ if (force || (layoutOrigin.alignment!=layout.alignment))
+ {
+ // Check if the current alignment is a valid one for AbiWord.
+ if ((layout.alignment == "left") || (layout.alignment == "right")
+ || (layout.alignment == "center") || (layout.alignment == "justify"))
+ {
+ props += "text-align:";
+ props += layout.alignment;
+ props += "; ";
+ }
+ else if (layout.alignment == "auto")
+ {
+ // We assume a left alignment as AbiWord is not really bi-di (and this filter even less.)
+ props += "text-align:left; ";
+ }
+ else
+ {
+ kdWarning(30506) << "Unknown alignment: " << layout.alignment << endl;
+ }
+ }
+
+ // TODO/FIXME: what if all tabulators must be erased?
+#if 0
+ // DEPRECATED!
+ if (!layout.tabulator.isEmpty()
+ && (force || (layoutOrigin.tabulator!=layout.tabulator)))
+ {
+ props += "tabstops:";
+ props += layout.tabulator;
+ props += "; ";
+ }
+#endif
+ if (!layout.tabulatorList.isEmpty()
+ && (force || (layoutOrigin.tabulatorList!=layout.tabulatorList) ))
+ {
+ props += "tabstops:";
+ bool first=true;
+ TabulatorList::ConstIterator it;
+ TabulatorList::ConstIterator end(layout.tabulatorList.end());
+ for (it=layout.tabulatorList.begin();it!=end;++it)
+ {
+ if (first)
+ {
+ first=false;
+ }
+ else
+ {
+ props += ",";
+ }
+ props += QString::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 ((layout.indentLeft>=0.0)
+ && (force || (layoutOrigin.indentLeft!=layout.indentLeft)))
+ {
+ props += QString("margin-left:%1pt; ").arg(layout.indentLeft);
+ }
+
+ if ((layout.indentRight>=0.0)
+ && (force || (layoutOrigin.indentRight!=layout.indentRight)))
+ {
+ props += QString("margin-right:%1pt; ").arg(layout.indentRight);
+ }
+
+ if (force || (layoutOrigin.indentLeft!=layout.indentLeft))
+ {
+ props += "text-indent: ";
+ props += QString::number(layout.indentFirst);
+ props += "pt; ";
+ }
+
+ if ((layout.marginBottom>=0.0)
+ && ( force || ( layoutOrigin.marginBottom != layout.marginBottom ) ) )
+ {
+ props += QString("margin-bottom:%1pt; ").arg(layout.marginBottom);
+ }
+
+ if ((layout.marginTop>=0.0)
+ && ( force || ( layoutOrigin.marginTop != layout.marginTop ) ) )
+ {
+ props += QString("margin-top:%1pt; ").arg(layout.marginTop);
+ }
+
+ if (force
+ || ( layoutOrigin.lineSpacingType != layout.lineSpacingType )
+ || ( layoutOrigin.lineSpacing != layout.lineSpacing ) )
+ {
+ switch ( layout.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 += QString::number( layout.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 += QString::number( layout.lineSpacing ); // ### TODO: rounding?
+ props += "; ";
+ break;
+ }
+ case LayoutData::LS_FIXED:
+ {
+ // We have a fixed line height (in points)
+ props += "line-height:";
+ props += QString::number( layout.lineSpacing ); // ### TODO: rounding?
+ props += "pt; ";
+ break;
+ }
+ case LayoutData::LS_ATLEAST:
+ {
+ // We have an "at-least" line height (in points)
+ props += "line-height=:";
+ props += QString::number( layout.lineSpacing ); // ### TODO: rounding?
+ props += "pt+; "; // The + makes the difference
+ break;
+ }
+ default:
+ {
+ kdWarning(30506) << "Unsupported lineSpacingType: " << layout.lineSpacingType << " (Ignoring!)" << endl;
+ break;
+ }
+ }
+ }
+
+ // Add all AbiWord properties collected in the <FORMAT> element
+ props += textFormatToAbiProps(layoutOrigin.formatData.text,layout.formatData.text,force);
+
+ return props;
+}
+
+bool AbiWordWorker::doFullParagraph(const QString& paraText, const LayoutData& layout,
+ const ValueListFormatData& paraFormatDataList)
+{
+ QString style=layout.styleName;
+
+ const LayoutData& styleLayout=m_styleMap[style];
+
+ QString props=layoutToCss(styleLayout,layout,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.findRev(";");
+ 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 (layout.pageBreakBefore)
+ {
+ // We have a page break before the paragraph
+ *m_streamOut << "<pbr/>";
+ }
+
+ processParagraphData(paraText, layout.formatData.text, paraFormatDataList);
+
+ // Before closing the paragraph, test if we have a page break
+ if (layout.pageBreakAfter)
+ {
+ // We have a page break after the paragraph
+ *m_streamOut << "<pbr/>";
+ }
+
+ *m_streamOut << "</p>\n";
+ return true;
+}
+
+bool AbiWordWorker::doFullDefineStyle(LayoutData& layout)
+{
+ //Register style in the style map
+ m_styleMap[layout.styleName]=layout;
+
+ *m_streamOut << "<s";
+
+ // TODO: cook the style name to the standard style names in AbiWord
+ *m_streamOut << " name=\"" << EscapeXmlText(layout.styleName,true,true) << "\"";
+ *m_streamOut << " followedby=\"" << EscapeXmlText(layout.styleFollowing,true,true) << "\"";
+
+ if ( (layout.counter.numbering == CounterData::NUM_CHAPTER)
+ && (layout.counter.depth<10) )
+ {
+ *m_streamOut << " level=\"";
+ *m_streamOut << QString::number(layout.counter.depth+1,10);
+ *m_streamOut << "\"";
+ }
+
+ QString abiprops=layoutToCss(layout,layout,true);
+
+ const int result=abiprops.findRev(";");
+ 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)
+{
+ QString 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
+ {
+ QString pagetype=KoPageFormat::formatString(KoFormat(format));
+ outputText+="pagetype=\"";
+ outputText+=pagetype;
+
+ QString 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 += QString("pagetype=\"Custom\" width=\"%1\" height=\"%2\" units=\"inch\" ").arg(width/72.0).arg(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 QString& 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 QDateTime::toString, but guaranteed *not* to be translated
+QString AbiWordWorker::transformToTextDate(const QDateTime& dt)
+{
+ if (dt.isValid())
+ {
+ QString result;
+
+ const QDate 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 += ' ';
+
+ QString temp;
+
+ temp = "00";
+ temp += QString::number(date.day(), 10);
+ result += temp.right(2);
+ result += ' ';
+
+ const QTime time(dt.time());
+
+ temp = "00";
+ temp += QString::number(time.hour(), 10);
+ result += temp.right(2);
+ result += ':';
+
+ temp = "00";
+ temp += QString::number(time.minute(), 10);
+ result += temp.right(2);
+ result += ':';
+
+ temp = "00";
+ temp += QString::number(time.second(), 10);
+ result += temp.right(2);
+ result += ' ';
+
+ temp = "0000";
+ temp += QString::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";
+
+ QString 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";
+
+ QDateTime now (QDateTime::currentDateTime(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 */*parent*/, const char */*name*/, const QStringList &) :
+ KoFilter() {
+}
+
+KoFilter::ConversionStatus ABIWORDExport::convert( const QCString& from, const QCString& to )
+{
+ if ( to != "application/x-abiword" || from != "application/x-kword" )
+ {
+ return KoFilter::NotImplemented;
+ }
+
+ // We need KimageIO's help in AbiWordWorker::convertUnknownImage
+ KImageIO::registerFormats();
+
+ AbiWordWorker* worker=new AbiWordWorker();
+
+ if (!worker)
+ {
+ kdError(30506) << "Cannot create Worker! Aborting!" << endl;
+ return KoFilter::StupidError;
+ }
+
+ KWEFKWordLeader* leader=new KWEFKWordLeader(worker);
+
+ if (!leader)
+ {
+ kdError(30506) << "Cannot create Worker! Aborting!" << endl;
+ delete worker;
+ return KoFilter::StupidError;
+ }
+
+ KoFilter::ConversionStatus result=leader->convert(m_chain,from,to);
+
+ delete leader;
+ delete worker;
+
+ return result;
+}
diff --git a/filters/kword/abiword/abiwordexport.h b/filters/kword/abiword/abiwordexport.h
new file mode 100644
index 000000000..a373f5e45
--- /dev/null
+++ b/filters/kword/abiword/abiwordexport.h
@@ -0,0 +1,51 @@
+/*
+ This file is part of the KDE project
+ Copyright (C) 2001 Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+/*
+ This file is based on the old file:
+ koffice/filters/kword/ascii/asciiexport.h
+
+ The old file was copyrighted by
+ Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
+
+ The old file was licensed under the terms of the GNU Library General Public
+ License version 2.
+*/
+
+#ifndef ABIWORDEXPORT_H
+#define ABIWORDEXPORT_H
+
+#include <qstring.h>
+#include <qcstring.h>
+
+#include <KoFilter.h>
+
+
+class ABIWORDExport : public KoFilter {
+
+ Q_OBJECT
+
+public:
+ ABIWORDExport(KoFilter *parent, const char *name, const QStringList &);
+ virtual ~ABIWORDExport() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+};
+#endif // ABIWORDEXPORT_H
diff --git a/filters/kword/abiword/abiwordimport.cc b/filters/kword/abiword/abiwordimport.cc
new file mode 100644
index 000000000..b872e8750
--- /dev/null
+++ b/filters/kword/abiword/abiwordimport.cc
@@ -0,0 +1,1875 @@
+/* This file is part of the KDE project
+ Copyright 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.
+*/
+
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <qmap.h>
+#include <qbuffer.h>
+#include <qpicture.h>
+#include <qxml.h>
+#include <qdom.h>
+#include <qdatetime.h>
+
+#include <kdebug.h>
+#include <kmdcodec.h>
+#include <kfilterdev.h>
+#include <kgenericfactory.h>
+#include <kmessagebox.h>
+
+#include <KoPageLayout.h>
+#include <KoStore.h>
+#include <KoFilterChain.h>
+
+#include "ImportHelpers.h"
+#include "ImportFormatting.h"
+#include "ImportStyle.h"
+#include "ImportField.h"
+
+#include "abiwordimport.h"
+
+class ABIWORDImportFactory : KGenericFactory<ABIWORDImport, KoFilter>
+{
+public:
+ ABIWORDImportFactory(void) : KGenericFactory<ABIWORDImport, KoFilter> ("kwordabiwordimport")
+ {}
+protected:
+ virtual void setupTranslations( void )
+ {
+ KGlobal::locale()->insertCatalogue( "kofficefilters" );
+ }
+};
+
+K_EXPORT_COMPONENT_FACTORY( libabiwordimport, ABIWORDImportFactory() )
+
+// *Note for the reader of this code*
+// Tags in lower case (e.g. <c>) are AbiWord's ones.
+// Tags in upper case (e.g. <TEXT>) are KWord's ones.
+
+// enum StackItemElementType is now in the file ImportFormatting.h
+
+class StructureParser : public QXmlDefaultHandler
+{
+public:
+ StructureParser(KoFilterChain* chain)
+ : m_chain(chain), m_pictureNumber(0), m_pictureFrameNumber(0), m_tableGroupNumber(0),
+ m_timepoint(QDateTime::currentDateTime(Qt::UTC)), m_fatalerror(false)
+ {
+ createDocument();
+ structureStack.setAutoDelete(true);
+ StackItem *stackItem=new(StackItem);
+ stackItem->elementType=ElementTypeBottom;
+ stackItem->m_frameset=mainFramesetElement; // The default frame set.
+ stackItem->stackElementText=mainFramesetElement; // This is more for DEBUG
+ structureStack.push(stackItem); //Security item (not to empty the stack)
+ }
+ virtual ~StructureParser()
+ {
+ structureStack.clear();
+ }
+public:
+ virtual bool startDocument(void);
+ virtual bool endDocument(void);
+ virtual bool startElement( const QString&, const QString&, const QString& name, const QXmlAttributes& attributes);
+ virtual bool endElement( const QString&, const QString& , const QString& qName);
+ virtual bool characters ( const QString & ch );
+ virtual bool warning(const QXmlParseException& exception);
+ virtual bool error(const QXmlParseException& exception);
+ virtual bool fatalError(const QXmlParseException& exception);
+public:
+ inline QDomDocument getDocInfo(void) const { return m_info; }
+ inline QDomDocument getDocument(void) const { return mainDocument; }
+ inline bool wasFatalError(void) const { return m_fatalerror; }
+protected:
+ bool clearStackUntilParagraph(StackItemStack& auxilaryStack);
+ bool complexForcedPageBreak(StackItem* stackItem);
+private:
+ // The methods that would need too much parameters are private instead of being static outside the class
+ bool StartElementC(StackItem* stackItem, StackItem* stackCurrent,
+ const QXmlAttributes& attributes);
+ bool StartElementA(StackItem* stackItem, StackItem* stackCurrent,
+ const QXmlAttributes& attributes);
+ bool StartElementImage(StackItem* stackItem, StackItem* stackCurrent,
+ const QXmlAttributes& attributes);
+ bool EndElementD (StackItem* stackItem);
+ bool EndElementM (StackItem* stackItem);
+ bool StartElementSection(StackItem* stackItem, StackItem* stackCurrent,
+ const QXmlAttributes& attributes);
+ bool StartElementFoot(StackItem* stackItem, StackItem* stackCurrent,
+ const QXmlAttributes& attributes);
+ bool StartElementTable(StackItem* stackItem, StackItem* stackCurrent, const QXmlAttributes& attributes);
+ bool StartElementCell(StackItem* stackItem, StackItem* stackCurrent,const QXmlAttributes& attributes);
+private:
+ void createDocument(void);
+ void createDocInfo(void);
+ QString indent; //DEBUG
+ StackItemStack structureStack;
+ QDomDocument mainDocument;
+ QDomDocument m_info;
+ QDomElement framesetsPluralElement; // <FRAMESETS>
+ QDomElement mainFramesetElement; // The main <FRAMESET> where the body text will be under.
+ QDomElement m_picturesElement; // <PICTURES>
+ QDomElement m_paperElement; // <PAPER>
+ QDomElement m_paperBordersElement; // <PAPERBORDER>
+ QDomElement m_ignoreWordsElement; // <SPELLCHECKIGNORELIST>
+ StyleDataMap styleDataMap;
+ KoFilterChain* m_chain;
+ uint m_pictureNumber; // unique: increment *before* use
+ uint m_pictureFrameNumber; // unique: increment *before* use
+ uint m_tableGroupNumber; // unique: increment *before* use
+ QMap<QString,QString> m_metadataMap; // Map for <m> elements
+ QDateTime m_timepoint; // Date/time (for pictures)
+ bool m_fatalerror; // Did a XML parsing fatal error happened?
+};
+
+// Element <c>
+
+bool StructureParser::StartElementC(StackItem* stackItem, StackItem* stackCurrent, const QXmlAttributes& attributes)
+{
+ // <c> elements can be nested in <p> elements, in <a> elements or in other <c> elements
+ // AbiWord does not nest <c> elements in other <c> elements, but explicitly allows external programs to do it!
+
+ // <p> or <c> (not child of <a>)
+ if ((stackCurrent->elementType==ElementTypeParagraph)||(stackCurrent->elementType==ElementTypeContent))
+ {
+ // Contents can have styles, however KWord cannot have character style.
+ // Therefore we use the style if it exist, but we do not create it if not.
+ QString strStyleProps;
+ QString strStyleName=attributes.value("style").stripWhiteSpace();
+ if (!strStyleName.isEmpty())
+ {
+ StyleDataMap::Iterator it=styleDataMap.find(strStyleName);
+ if (it!=styleDataMap.end())
+ {
+ strStyleProps=it.data().m_props;
+ }
+ }
+
+ AbiPropsMap abiPropsMap;
+ PopulateProperties(stackItem,strStyleProps,attributes,abiPropsMap,true);
+
+ stackItem->elementType=ElementTypeContent;
+ stackItem->stackElementParagraph=stackCurrent->stackElementParagraph; // <PARAGRAPH>
+ stackItem->stackElementText=stackCurrent->stackElementText; // <TEXT>
+ stackItem->stackElementFormatsPlural=stackCurrent->stackElementFormatsPlural; // <FORMATS>
+ stackItem->pos=stackCurrent->pos; //Propagate the position
+ }
+ // <a> or <c> when child of <a>
+ else if ((stackCurrent->elementType==ElementTypeAnchor)||(stackCurrent->elementType==ElementTypeAnchorContent))
+ {
+ stackItem->elementType=ElementTypeAnchorContent;
+ }
+ else
+ {//we are not nested correctly, so consider it a parse error!
+ kdError(30506) << "parse error <c> tag nested neither in <p> nor in <c> nor in <a> but in "
+ << stackCurrent->itemName << endl;
+ return false;
+ }
+ return true;
+}
+
+bool charactersElementC (StackItem* stackItem, QDomDocument& mainDocument, const QString & ch)
+{
+ if (stackItem->elementType==ElementTypeContent)
+ { // Normal <c>
+ QDomElement elementText=stackItem->stackElementText;
+ QDomElement elementFormatsPlural=stackItem->stackElementFormatsPlural;
+ elementText.appendChild(mainDocument.createTextNode(ch));
+
+ QDomElement formatElementOut=mainDocument.createElement("FORMAT");
+ formatElementOut.setAttribute("id",1); // Normal text!
+ formatElementOut.setAttribute("pos",stackItem->pos); // Start position
+ formatElementOut.setAttribute("len",ch.length()); // Start position
+ elementFormatsPlural.appendChild(formatElementOut); //Append to <FORMATS>
+ stackItem->pos+=ch.length(); // Adapt new starting position
+
+ AddFormat(formatElementOut, stackItem, mainDocument);
+ }
+ else if (stackItem->elementType==ElementTypeAnchorContent)
+ {
+ // Add characters to the link name
+ stackItem->strTemp2+=ch;
+ // TODO: how can we care about the text format?
+ }
+ else
+ {
+ kdError(30506) << "Internal error (in charactersElementC)" << endl;
+ }
+
+ return true;
+}
+
+bool EndElementC (StackItem* stackItem, StackItem* stackCurrent)
+{
+ if (stackItem->elementType==ElementTypeContent)
+ {
+ stackItem->stackElementText.normalize();
+ stackCurrent->pos=stackItem->pos; //Propagate the position back to the parent element
+ }
+ else if (stackItem->elementType==ElementTypeAnchorContent)
+ {
+ stackCurrent->strTemp2+=stackItem->strTemp2; //Propagate the link name back to the parent element
+ }
+ else
+ {
+ kdError(30506) << "Wrong element type!! Aborting! (</c> in StructureParser::endElement)" << endl;
+ return false;
+ }
+ return true;
+}
+
+// Element <a>
+bool StructureParser::StartElementA(StackItem* stackItem, StackItem* stackCurrent, const QXmlAttributes& attributes)
+{
+ // <a> elements can be nested in <p> elements
+ if (stackCurrent->elementType==ElementTypeParagraph)
+ {
+
+ //AbiPropsMap abiPropsMap;
+ //PopulateProperties(stackItem,QString::null,attributes,abiPropsMap,true);
+
+ stackItem->elementType=ElementTypeAnchor;
+ stackItem->stackElementParagraph=stackCurrent->stackElementParagraph; // <PARAGRAPH>
+ stackItem->stackElementText=stackCurrent->stackElementText; // <TEXT>
+ stackItem->stackElementFormatsPlural=stackCurrent->stackElementFormatsPlural; // <FORMATS>
+ stackItem->pos=stackCurrent->pos; //Propagate the position
+ stackItem->strTemp1=attributes.value("xlink:href").stripWhiteSpace(); // link reference
+ stackItem->strTemp2=QString::null; // link name
+
+ // We must be careful: AbiWord permits anchors to bookmarks.
+ // However, KWord does not know what a bookmark is.
+ if (stackItem->strTemp1[0]=='#')
+ {
+ kdWarning(30506) << "Anchor <a> to bookmark: " << stackItem->strTemp1 << endl
+ << " Processing <a> like <c>" << endl;
+ // We have a reference to a bookmark. Therefore treat it as a normal content <c>
+ return StartElementC(stackItem, stackCurrent, attributes);
+ }
+ }
+ else
+ {//we are not nested correctly, so consider it a parse error!
+ kdError(30506) << "parse error <a> tag not a child of <p> but of "
+ << stackCurrent->itemName << endl;
+ return false;
+ }
+ return true;
+}
+
+static bool charactersElementA (StackItem* stackItem, const QString & ch)
+{
+ // Add characters to the link name
+ stackItem->strTemp2+=ch;
+ return true;
+}
+
+static bool EndElementA (StackItem* stackItem, StackItem* stackCurrent, QDomDocument& mainDocument)
+{
+ if (!stackItem->elementType==ElementTypeAnchor)
+ {
+ kdError(30506) << "Wrong element type!! Aborting! (</a> in StructureParser::endElement)" << endl;
+ return false;
+ }
+
+ QDomElement elementText=stackItem->stackElementText;
+ elementText.appendChild(mainDocument.createTextNode("#"));
+
+ QDomElement formatElement=mainDocument.createElement("FORMAT");
+ formatElement.setAttribute("id",4); // Variable
+ formatElement.setAttribute("pos",stackItem->pos); // Start position
+ formatElement.setAttribute("len",1); // Start position
+
+ QDomElement variableElement=mainDocument.createElement("VARIABLE");
+ formatElement.appendChild(variableElement);
+
+ QDomElement typeElement=mainDocument.createElement("TYPE");
+ typeElement.setAttribute("key","STRING");
+ typeElement.setAttribute("type",9); // link
+ typeElement.setAttribute("text",stackItem->strTemp2);
+ variableElement.appendChild(typeElement); //Append to <VARIABLE>
+
+ QDomElement linkElement=mainDocument.createElement("LINK");
+ linkElement.setAttribute("hrefName",stackItem->strTemp1);
+ linkElement.setAttribute("linkName",stackItem->strTemp2);
+ variableElement.appendChild(linkElement); //Append to <VARIABLE>
+
+ // Now work on stackCurrent
+ stackCurrent->stackElementFormatsPlural.appendChild(formatElement);
+ stackCurrent->pos++; //Propagate the position back to the parent element
+
+ return true;
+}
+
+// Element <p>
+
+bool StartElementP(StackItem* stackItem, StackItem* stackCurrent,
+ QDomDocument& mainDocument,
+ StyleDataMap& styleDataMap, const QXmlAttributes& attributes)
+{
+ // We must prepare the style
+ QString strStyle=attributes.value("style");
+ if (strStyle.isEmpty())
+ {
+ strStyle="Normal";
+ }
+ StyleDataMap::ConstIterator it=styleDataMap.useOrCreateStyle(strStyle);
+
+ QString strLevel=attributes.value("level");
+ int level;
+ if (strLevel.isEmpty())
+ {
+ // We have not "level" attribute, so we must use the style's level.
+ level=it.data().m_level;
+ }
+ else
+ {
+ // We have a "level" attribute, so it overrides the style's level.
+ level=strStyle.toInt();
+ }
+
+ QDomElement elementText=stackCurrent->stackElementText;
+ QDomElement paragraphElementOut=mainDocument.createElement("PARAGRAPH");
+ stackCurrent->m_frameset.appendChild(paragraphElementOut);
+
+ QDomElement textElementOut=mainDocument.createElement("TEXT");
+ paragraphElementOut.appendChild(textElementOut);
+ QDomElement formatsPluralElementOut=mainDocument.createElement("FORMATS");
+ paragraphElementOut.appendChild(formatsPluralElementOut);
+
+ AbiPropsMap abiPropsMap;
+ PopulateProperties(stackItem,it.data().m_props,attributes,abiPropsMap,false);
+
+ stackItem->elementType=ElementTypeParagraph;
+ stackItem->stackElementParagraph=paragraphElementOut; // <PARAGRAPH>
+ stackItem->stackElementText=textElementOut; // <TEXT>
+ stackItem->stackElementFormatsPlural=formatsPluralElementOut; // <FORMATS>
+ stackItem->pos=0; // No text characters yet
+
+ // Now we populate the layout
+ QDomElement layoutElement=mainDocument.createElement("LAYOUT");
+ paragraphElementOut.appendChild(layoutElement);
+
+ AddLayout(strStyle,layoutElement, stackItem, mainDocument, abiPropsMap, level, false);
+
+ return true;
+}
+
+bool charactersElementP (StackItem* stackItem, QDomDocument& mainDocument, const QString & ch)
+{
+ QDomElement elementText=stackItem->stackElementText;
+
+ elementText.appendChild(mainDocument.createTextNode(ch));
+
+ stackItem->pos+=ch.length(); // Adapt new starting position
+
+ return true;
+}
+
+bool EndElementP (StackItem* stackItem)
+{
+ if (!stackItem->elementType==ElementTypeParagraph)
+ {
+ kdError(30506) << "Wrong element type!! Aborting! (in endElementP)" << endl;
+ return false;
+ }
+ stackItem->stackElementText.normalize();
+ return true;
+}
+
+static bool StartElementField(StackItem* stackItem, StackItem* stackCurrent,
+ QDomDocument& mainDocument, const QXmlAttributes& attributes)
+{
+ // <field> element elements can be nested in <p>
+ if (stackCurrent->elementType==ElementTypeParagraph)
+ {
+ QString strType=attributes.value("type").stripWhiteSpace();
+ kdDebug(30506)<<"<field> type:"<<strType<<endl;
+
+ AbiPropsMap abiPropsMap;
+ PopulateProperties(stackItem,QString::null,attributes,abiPropsMap,true);
+
+ stackItem->elementType=ElementTypeEmpty;
+
+ // We create a format element
+ QDomElement variableElement=mainDocument.createElement("VARIABLE");
+
+ if (!ProcessField(mainDocument, variableElement, strType, attributes))
+ {
+ // The field type was not recognised,
+ // therefore write the field type in red as normal text
+ kdWarning(30506) << "Unknown <field> type: " << strType << endl;
+ QDomElement formatElement=mainDocument.createElement("FORMAT");
+ formatElement.setAttribute("id",1); // Variable
+ formatElement.setAttribute("pos",stackItem->pos); // Start position
+ formatElement.setAttribute("len",strType.length());
+
+ formatElement.appendChild(variableElement);
+
+ // Now work on stackCurrent
+ stackCurrent->stackElementFormatsPlural.appendChild(formatElement);
+ stackCurrent->stackElementText.appendChild(mainDocument.createTextNode(strType));
+ stackCurrent->pos+=strType.length(); // Adjust position
+
+ // Add formating (use stackItem)
+ stackItem->fgColor.setRgb(255,0,0);
+ AddFormat(formatElement, stackItem, mainDocument);
+ return true;
+ }
+
+ // We create a format element
+ QDomElement formatElement=mainDocument.createElement("FORMAT");
+ formatElement.setAttribute("id",4); // Variable
+ formatElement.setAttribute("pos",stackItem->pos); // Start position
+ formatElement.setAttribute("len",1);
+
+ formatElement.appendChild(variableElement);
+
+ // Now work on stackCurrent
+ stackCurrent->stackElementFormatsPlural.appendChild(formatElement);
+ stackCurrent->stackElementText.appendChild(mainDocument.createTextNode("#"));
+ stackCurrent->pos++; // Adjust position
+
+ // Add formating (use stackItem)
+ AddFormat(formatElement, stackItem, mainDocument);
+
+ }
+ else
+ {//we are not nested correctly, so consider it a parse error!
+ kdError(30506) << "parse error <field> tag not nested in <p> but in "
+ << stackCurrent->itemName << endl;
+ return false;
+ }
+ return true;
+}
+
+// <s> (style)
+static bool StartElementS(StackItem* stackItem, StackItem* /*stackCurrent*/,
+ const QXmlAttributes& attributes, StyleDataMap& styleDataMap)
+{
+ // We do not assume when we are called.
+ // We also do not care if a style is defined multiple times.
+ stackItem->elementType=ElementTypeEmpty;
+
+ QString strStyleName=attributes.value("name").stripWhiteSpace();
+
+ if (strStyleName.isEmpty())
+ {
+ kdWarning(30506) << "Style has no name!" << endl;
+ }
+ else
+ {
+ QString strLevel=attributes.value("level");
+ int level;
+ if (strLevel.isEmpty())
+ level=-1; //TODO/FIXME: might be wrong if the style is based on another
+ else
+ level=strLevel.toInt();
+ QString strBasedOn=attributes.value("basedon").simplifyWhiteSpace();
+ styleDataMap.defineNewStyleFromOld(strStyleName,strBasedOn,level,attributes.value("props"));
+ kdDebug(30506) << " Style name: " << strStyleName << endl
+ << " Based on: " << strBasedOn << endl
+ << " Level: " << level << endl
+ << " Props: " << attributes.value("props") << endl;
+ }
+
+ return true;
+}
+
+// <image>
+bool StructureParser::StartElementImage(StackItem* stackItem, StackItem* stackCurrent,
+ const QXmlAttributes& attributes)
+{
+ // <image> elements can be nested in <p> or <c> elements
+ if ((stackCurrent->elementType!=ElementTypeParagraph) && (stackCurrent->elementType!=ElementTypeContent))
+ {//we are not nested correctly, so consider it a parse error!
+ kdError(30506) << "parse error <image> tag nested neither in <p> nor in <c> but in "
+ << stackCurrent->itemName << endl;
+ return false;
+ }
+ stackItem->elementType=ElementTypeEmpty;
+
+ QString strDataId=attributes.value("dataid").stripWhiteSpace();
+
+ AbiPropsMap abiPropsMap;
+ abiPropsMap.splitAndAddAbiProps(attributes.value("props"));
+
+ double height=ValueWithLengthUnit(abiPropsMap["height"].getValue());
+ double width =ValueWithLengthUnit(abiPropsMap["width" ].getValue());
+
+ kdDebug(30506) << "Image: " << strDataId << " height: " << height << " width: " << width << endl;
+
+ // TODO: image properties
+
+ if (strDataId.isEmpty())
+ {
+ kdWarning(30506) << "Image has no data id!" << endl;
+ }
+ else
+ {
+ kdDebug(30506) << "Image: " << strDataId << endl;
+ }
+
+ QString strPictureFrameName(i18n("Frameset name","Picture %1").arg(++m_pictureFrameNumber));
+
+ // Create the frame set of the image
+
+ QDomElement framesetElement=mainDocument.createElement("FRAMESET");
+ framesetElement.setAttribute("frameType",2);
+ framesetElement.setAttribute("frameInfo",0);
+ framesetElement.setAttribute("visible",1);
+ framesetElement.setAttribute("name",strPictureFrameName);
+ framesetsPluralElement.appendChild(framesetElement);
+
+ QDomElement frameElementOut=mainDocument.createElement("FRAME");
+ frameElementOut.setAttribute("left",0);
+ frameElementOut.setAttribute("top",0);
+ frameElementOut.setAttribute("bottom",height);
+ frameElementOut.setAttribute("right" ,width );
+ frameElementOut.setAttribute("runaround",1);
+ // TODO: a few attributes are missing
+ framesetElement.appendChild(frameElementOut);
+
+ QDomElement element=mainDocument.createElement("PICTURE");
+ element.setAttribute("keepAspectRatio","true");
+ framesetElement.setAttribute("frameType",2); // Picture
+ framesetElement.appendChild(element);
+
+ QDomElement key=mainDocument.createElement("KEY");
+ key.setAttribute("filename",strDataId);
+ key.setAttribute("year",m_timepoint.date().year());
+ key.setAttribute("month",m_timepoint.date().month());
+ key.setAttribute("day",m_timepoint.date().day());
+ key.setAttribute("hour",m_timepoint.time().hour());
+ key.setAttribute("minute",m_timepoint.time().minute());
+ key.setAttribute("second",m_timepoint.time().second());
+ key.setAttribute("msec",m_timepoint.time().msec());
+ element.appendChild(key);
+
+ // Now use the image's frame set
+ QDomElement elementText=stackItem->stackElementText;
+ QDomElement elementFormatsPlural=stackItem->stackElementFormatsPlural;
+ elementText.appendChild(mainDocument.createTextNode("#"));
+
+ QDomElement formatElementOut=mainDocument.createElement("FORMAT");
+ formatElementOut.setAttribute("id",6); // Normal text!
+ formatElementOut.setAttribute("pos",stackItem->pos); // Start position
+ formatElementOut.setAttribute("len",1); // Start position
+ elementFormatsPlural.appendChild(formatElementOut); //Append to <FORMATS>
+
+ // WARNING: we must change the position in stackCurrent!
+ stackCurrent->pos++; // Adapt new starting position
+
+ QDomElement anchor=mainDocument.createElement("ANCHOR");
+ // No name attribute!
+ anchor.setAttribute("type","frameset");
+ anchor.setAttribute("instance",strPictureFrameName);
+ formatElementOut.appendChild(anchor);
+
+ return true;
+}
+
+// <d>
+static bool StartElementD(StackItem* stackItem, StackItem* /*stackCurrent*/,
+ const QXmlAttributes& attributes)
+{
+ // We do not assume when we are called or if we are or not a child of <data>
+ // However, we assume that we are after all <image> elements
+ stackItem->elementType=ElementTypeRealData;
+
+ QString strName=attributes.value("name").stripWhiteSpace();
+ kdDebug(30506) << "Data: " << strName << endl;
+
+ QString strBase64=attributes.value("base64").stripWhiteSpace();
+ QString strMime=attributes.value("mime").stripWhiteSpace();
+
+ if (strName.isEmpty())
+ {
+ kdWarning(30506) << "Data has no name!" << endl;
+ stackItem->elementType=ElementTypeEmpty;
+ return true;
+ }
+
+ if (strMime.isEmpty())
+ {
+ // Old AbiWord files had no mime types for images but the data were base64-coded PNG
+ strMime="image/png";
+ strBase64="yes";
+ }
+
+ stackItem->fontName=strName; // Store the data name as font name.
+ stackItem->bold=(strBase64=="yes"); // Store base64-coded as bold
+ stackItem->strTemp1=strMime; // Mime type
+ stackItem->strTemp2=QString::null; // Image data
+
+ return true;
+}
+
+static bool CharactersElementD (StackItem* stackItem, QDomDocument& /*mainDocument*/, const QString & ch)
+{
+ // As we have no guarantee to have the whole stream in one call, we must store the data.
+ stackItem->strTemp2+=ch;
+ return true;
+}
+
+bool StructureParser::EndElementD (StackItem* stackItem)
+{
+ if (!stackItem->elementType==ElementTypeRealData)
+ {
+ kdError(30506) << "Wrong element type!! Aborting! (in endElementD)" << endl;
+ return false;
+ }
+ if (!m_chain)
+ {
+ kdError(30506) << "No filter chain! Aborting! (in endElementD)" << endl;
+ return false;
+ }
+
+ bool isSvg=false; // SVG ?
+
+ QString extension;
+
+ // stackItem->strTemp1 contains the mime type
+ if (stackItem->strTemp1=="image/png")
+ {
+ extension=".png";
+ }
+ else if (stackItem->strTemp1=="image/jpeg") // ### FIXME: in fact it does not exist in AbiWord
+ {
+ extension=".jpeg";
+ }
+ else if (stackItem->strTemp1=="image/svg-xml") //Yes it is - not +
+ {
+ extension=".svg";
+ isSvg=true;
+ }
+ else
+ {
+ kdWarning(30506) << "Unknown or unsupported mime type: "
+ << stackItem->strTemp1 << endl;
+ return true;
+ }
+
+ QString strStoreName;
+ strStoreName="pictures/picture";
+ strStoreName+=QString::number(++m_pictureNumber);
+ strStoreName+=extension;
+
+ QString strDataId=stackItem->fontName; // AbiWord's data id
+ QDomElement key=mainDocument.createElement("KEY");
+ key.setAttribute("filename",strDataId);
+ key.setAttribute("year",m_timepoint.date().year());
+ key.setAttribute("month",m_timepoint.date().month());
+ key.setAttribute("day",m_timepoint.date().day());
+ key.setAttribute("hour",m_timepoint.time().hour());
+ key.setAttribute("minute",m_timepoint.time().minute());
+ key.setAttribute("second",m_timepoint.time().second());
+ key.setAttribute("msec",m_timepoint.time().msec());
+ key.setAttribute("name",strStoreName);
+ m_picturesElement.appendChild(key);
+
+ KoStoreDevice* out=m_chain->storageFile(strStoreName, KoStore::Write);
+ if(!out)
+ {
+ kdError(30506) << "Unable to open output file for: " << stackItem->fontName << " Storage: " << strStoreName << endl;
+ return false;
+ }
+
+ if (stackItem->bold) // Is base64-coded?
+ {
+ kdDebug(30506) << "Decode and write base64 stream: " << stackItem->fontName << endl;
+ // We need to decode the base64 stream
+ // However KCodecs has no QString to QByteArray decoder!
+ QByteArray base64Stream=stackItem->strTemp2.utf8(); // Use utf8 to avoid corruption of data
+ QByteArray binaryStream;
+ KCodecs::base64Decode(base64Stream, binaryStream);
+ out->writeBlock(binaryStream, binaryStream.count());
+ }
+ else
+ {
+ // Unknown text format!
+ kdDebug(30506) << "Write character stream: " << stackItem->fontName << endl;
+ // We strip the white space in front to avoid white space before a XML declaration
+ QCString strOut=stackItem->strTemp2.stripWhiteSpace().utf8();
+ out->writeBlock(strOut,strOut.length());
+ }
+
+ return true;
+}
+
+// <m>
+static bool StartElementM(StackItem* stackItem, StackItem* /*stackCurrent*/,
+ const QXmlAttributes& attributes)
+{
+ // We do not assume when we are called or if we are or not a child of <metadata>
+ stackItem->elementType=ElementTypeRealMetaData;
+
+ QString strKey=attributes.value("key").stripWhiteSpace();
+ kdDebug(30506) << "Metadata key: " << strKey << endl;
+
+ if (strKey.isEmpty())
+ {
+ kdWarning(30506) << "Metadata has no key!" << endl;
+ stackItem->elementType=ElementTypeIgnore;
+ return true;
+ }
+
+ stackItem->strTemp1=strKey; // Key
+ stackItem->strTemp2=QString::null; // Meta data
+
+ return true;
+}
+
+static bool CharactersElementM (StackItem* stackItem, const QString & ch)
+{
+ // As we have no guarantee to have the whole data in one call, we must store the data.
+ stackItem->strTemp2+=ch;
+ return true;
+}
+
+bool StructureParser::EndElementM (StackItem* stackItem)
+{
+ if (!stackItem->elementType==ElementTypeRealData)
+ {
+ kdError(30506) << "Wrong element type!! Aborting! (in endElementM)" << endl;
+ return false;
+ }
+
+ if (stackItem->strTemp1.isEmpty())
+ {
+ // Probably an internal error!
+ kdError(30506) << "Key name was erased! Aborting! (in endElementM)" << endl;
+ return false;
+ }
+
+ // Just add it to the metadata map, we do not do something special with the values.
+ m_metadataMap[stackItem->strTemp1]=stackItem->strTemp2;
+
+ return true;
+}
+
+// <br> (forced line break)
+static bool StartElementBR(StackItem* stackItem, StackItem* stackCurrent,
+ QDomDocument& mainDocument)
+{
+ // <br> elements are mostly in <c> but can also be in <p>
+ if ((stackCurrent->elementType==ElementTypeParagraph)
+ || (stackCurrent->elementType==ElementTypeContent))
+ {
+ stackItem->elementType=ElementTypeEmpty;
+
+ // Now work on stackCurrent
+
+ if (stackCurrent->elementType==ElementTypeContent)
+ {
+ // Child <c>, so we have to add formating of <c>
+ QDomElement formatElement=mainDocument.createElement("FORMAT");
+ formatElement.setAttribute("id",1); // Normal text!
+ formatElement.setAttribute("pos",stackCurrent->pos); // Start position
+ formatElement.setAttribute("len",1);
+ AddFormat(formatElement, stackCurrent, mainDocument); // Add the format of the parent <c>
+ stackCurrent->stackElementFormatsPlural.appendChild(formatElement); //Append to <FORMATS>
+ }
+
+ stackCurrent->stackElementText.appendChild(mainDocument.createTextNode(QChar(10))); // Add a LINE FEED
+ stackCurrent->pos++; // Adjust position
+
+ }
+ else
+ {//we are not nested correctly, so consider it a parse error!
+ kdError(30506) << "parse error <br> tag not nested in <p> or <c> but in "
+ << stackCurrent->itemName << endl;
+ return false;
+ }
+ return true;
+}
+
+// <cbr> (forced column break, not supported)
+// <pbr> (forced page break)
+static bool StartElementPBR(StackItem* /*stackItem*/, StackItem* stackCurrent,
+ QDomDocument& mainDocument)
+{
+ // We are sure to be the child of a <p> element
+
+ // The following code is similar to the one in StartElementP
+ // We use mainFramesetElement here not to be dependant that <section> has happened before
+ QDomElement paragraphElementOut=mainDocument.createElement("PARAGRAPH");
+ stackCurrent->m_frameset.appendChild(paragraphElementOut);
+ QDomElement textElementOut=mainDocument.createElement("TEXT");
+ paragraphElementOut.appendChild(textElementOut);
+ QDomElement formatsPluralElementOut=mainDocument.createElement("FORMATS");
+ paragraphElementOut.appendChild(formatsPluralElementOut);
+
+ // We must now copy/clone the layout of elementText.
+
+ QDomNodeList nodeList=stackCurrent->stackElementParagraph.elementsByTagName("LAYOUT");
+
+ if (!nodeList.count())
+ {
+ kdError(30506) << "Unable to find <LAYOUT> element! Aborting! (in StartElementPBR)" <<endl;
+ return false;
+ }
+
+ // Now clone it
+ QDomNode newNode=nodeList.item(0).cloneNode(true); // We make a deep cloning of the first element/node
+ if (newNode.isNull())
+ {
+ kdError(30506) << "Unable to clone <LAYOUT> element! Aborting! (in StartElementPBR)" <<endl;
+ return false;
+ }
+ paragraphElementOut.appendChild(newNode);
+
+ // We need a page break!
+ QDomElement oldLayoutElement=nodeList.item(0).toElement();
+ if (oldLayoutElement.isNull())
+ {
+ kdError(30506) << "Cannot find old <LAYOUT> element! Aborting! (in StartElementPBR)" <<endl;
+ return false;
+ }
+ // We have now to add a element <PAGEBREAKING>
+ // TODO/FIXME: what if there is already one?
+ QDomElement pagebreakingElement=mainDocument.createElement("PAGEBREAKING");
+ pagebreakingElement.setAttribute("linesTogether","false");
+ pagebreakingElement.setAttribute("hardFrameBreak","false");
+ pagebreakingElement.setAttribute("hardFrameBreakAfter","true");
+ oldLayoutElement.appendChild(pagebreakingElement);
+
+ // Now that we have done with the old paragraph,
+ // we can write stackCurrent with the data of the new one!
+ // NOTE: The following code is similar to the one in StartElementP but we are working on stackCurrent!
+ stackCurrent->elementType=ElementTypeParagraph;
+ stackCurrent->stackElementParagraph=paragraphElementOut; // <PARAGRAPH>
+ stackCurrent->stackElementText=textElementOut; // <TEXT>
+ stackCurrent->stackElementFormatsPlural=formatsPluralElementOut; // <FORMATS>
+ stackCurrent->pos=0; // No text character yet
+
+ return true;
+}
+
+// <pagesize>
+static bool StartElementPageSize(QDomElement& paperElement, const QXmlAttributes& attributes)
+{
+ if (attributes.value("page-scale").toDouble()!=1.0)
+ {
+ kdWarning(30506) << "Ignoring unsupported page scale: " << attributes.value("page-scale") << endl;
+ }
+
+ int kwordOrientation;
+ QString strOrientation=attributes.value("orientation").stripWhiteSpace();
+
+ if (strOrientation=="portrait")
+ {
+ kwordOrientation=0;
+ }
+ else if (strOrientation=="landscape")
+ {
+ kwordOrientation=1;
+ }
+ else
+ {
+ kdWarning(30506) << "Unknown page orientation: " << strOrientation << "! Ignoring! " << endl;
+ kwordOrientation=0;
+ }
+
+ double kwordHeight;
+ double kwordWidth;
+
+ QString strPageType=attributes.value("pagetype").stripWhiteSpace();
+
+ // Do we know the page size or do we need to measure?
+ // For page formats that KWord knows, use our own values in case the values in the file would be wrong.
+
+ KoFormat kwordFormat = KoPageFormat::formatFromString(strPageType);
+
+ if (kwordFormat==PG_CUSTOM)
+ {
+ kdDebug(30506) << "Custom or other page format found: " << strPageType << endl;
+
+ double height = attributes.value("height").toDouble();
+ double width = attributes.value("width" ).toDouble();
+
+ QString strUnits = attributes.value("units").stripWhiteSpace();
+
+ kdDebug(30506) << "Explicit page size: "
+ << height << " " << strUnits << " x " << width << " " << strUnits
+ << endl;
+
+ if (strUnits=="cm")
+ {
+ kwordHeight = CentimetresToPoints(height);
+ kwordWidth = CentimetresToPoints(width);
+ }
+ else if (strUnits=="inch")
+ {
+ kwordHeight = InchesToPoints(height);
+ kwordWidth = InchesToPoints(width);
+ }
+ else if (strUnits=="mm")
+ {
+ kwordHeight = MillimetresToPoints(height);
+ kwordWidth = MillimetresToPoints(width);
+ }
+ else
+ {
+ kwordHeight = 0.0;
+ kwordWidth = 0.0;
+ kdWarning(30506) << "Unknown unit type: " << strUnits << endl;
+ }
+ }
+ else
+ {
+ // We have a format known by KOffice, so use KOffice's functions
+ kwordHeight = MillimetresToPoints(KoPageFormat::height(kwordFormat,PG_PORTRAIT));
+ kwordWidth = MillimetresToPoints(KoPageFormat::width (kwordFormat,PG_PORTRAIT));
+ }
+
+ if ((kwordHeight <= 1.0) || (kwordWidth <= 1.0))
+ // At least one of the two values is ridiculous
+ {
+ kdWarning(30506) << "Page width or height is too small: "
+ << kwordHeight << "x" << kwordWidth << endl;
+ // As we have no correct page size, we assume we have A4
+ kwordFormat = PG_DIN_A4;
+ kwordHeight = CentimetresToPoints(29.7);
+ kwordWidth = CentimetresToPoints(21.0);
+ }
+
+ // Now that we have gathered all the page size data, put it in the right element!
+
+ if (paperElement.isNull())
+ {
+ kdError(30506) << "<PAPER> element cannot be accessed! Aborting!" << endl;
+ return false;
+ }
+
+ paperElement.setAttribute("format",kwordFormat);
+ paperElement.setAttribute("width",kwordWidth);
+ paperElement.setAttribute("height",kwordHeight);
+ paperElement.setAttribute("orientation",kwordOrientation);
+
+ return true;
+}
+
+
+bool StructureParser::complexForcedPageBreak(StackItem* stackItem)
+{
+ // We are not a child of a <p> element, so we cannot use StartElementPBR directly
+
+ StackItemStack auxilaryStack;
+
+ if (!clearStackUntilParagraph(auxilaryStack))
+ {
+ kdError(30506) << "Could not clear stack until a paragraph!" << endl;
+ return false;
+ }
+
+ // Now we are a child of a <p> element!
+
+ bool success=StartElementPBR(stackItem,structureStack.current(),mainDocument);
+
+ // Now restore the stack
+
+ StackItem* stackCurrent=structureStack.current();
+ StackItem* item;
+ while (auxilaryStack.count()>0)
+ {
+ item=auxilaryStack.pop();
+ // We cannot put back the item on the stack like that.
+ // We must set a few values for each item.
+ item->pos=0; // Start at position 0
+ item->stackElementParagraph=stackCurrent->stackElementParagraph; // new <PARAGRAPH>
+ item->stackElementText=stackCurrent->stackElementText; // new <TEXT>
+ item->stackElementFormatsPlural=stackCurrent->stackElementFormatsPlural; // new <FORMATS>
+ structureStack.push(item);
+ }
+
+ return success;
+}
+
+
+// <section>
+bool StructureParser::StartElementSection(StackItem* stackItem, StackItem* /*stackCurrent*/,
+ const QXmlAttributes& attributes)
+{
+ //TODO: non main text sections (e.g. footers)
+ stackItem->elementType=ElementTypeSection;
+
+ AbiPropsMap abiPropsMap;
+ // Treat the props attributes in the two available flavors: lower case and upper case.
+ kdDebug(30506)<< "========== props=\"" << attributes.value("props") << "\"" << endl;
+ abiPropsMap.splitAndAddAbiProps(attributes.value("props"));
+ abiPropsMap.splitAndAddAbiProps(attributes.value("PROPS")); // PROPS is deprecated
+
+ // TODO: only the first main text section should change the page margins
+ // TODO; (as KWord does not allow different page sizes/margins for the same document)
+ if (true && (!m_paperBordersElement.isNull()))
+ {
+ QString str;
+ str=abiPropsMap["page-margin-top"].getValue();
+ if (!str.isEmpty())
+ {
+ m_paperBordersElement.setAttribute("top",ValueWithLengthUnit(str));
+ }
+ str=abiPropsMap["page-margin-left"].getValue();
+ if (!str.isEmpty())
+ {
+ m_paperBordersElement.setAttribute("left",ValueWithLengthUnit(str));
+ }
+ str=abiPropsMap["page-margin-bottom"].getValue();
+ if (!str.isEmpty())
+ {
+ m_paperBordersElement.setAttribute("bottom",ValueWithLengthUnit(str));
+ }
+ str=abiPropsMap["page-margin-right"].getValue();
+ if (!str.isEmpty())
+ {
+ m_paperBordersElement.setAttribute("right",ValueWithLengthUnit(str));
+ }
+ }
+ return true;
+}
+
+// <iw>
+
+static bool EndElementIW(StackItem* stackItem, StackItem* /*stackCurrent*/,
+ QDomDocument& mainDocument, QDomElement& m_ignoreWordsElement)
+{
+ if (!stackItem->elementType==ElementTypeIgnoreWord)
+ {
+ kdError(30506) << "Wrong element type!! Aborting! (in endElementIW)" << endl;
+ return false;
+ }
+ QDomElement wordElement=mainDocument.createElement("SPELLCHECKIGNOREWORD");
+ wordElement.setAttribute("word",stackItem->strTemp2.stripWhiteSpace());
+ m_ignoreWordsElement.appendChild(wordElement);
+ return true;
+}
+
+// <foot>
+bool StructureParser::StartElementFoot(StackItem* stackItem, StackItem* /*stackCurrent*/,
+ const QXmlAttributes& /*attributes*/)
+{
+#if 0
+ stackItem->elementType=ElementTypeFoot;
+
+ const QString id(attributes.value("endnote-id").stripWhiteSpace());
+ kdDebug(30506) << "Foot note id: " << id << endl;
+
+ if (id.isEmpty())
+ {
+ kdWarning(30506) << "Footnote has no id!" << endl;
+ stackItem->elementType=ElementTypeIgnore;
+ return true;
+ }
+
+ // We need to create a frameset for the foot note.
+ QDomElement framesetElement(mainDocument.createElement("FRAMESET"));
+ framesetElement.setAttribute("frameType",1);
+ framesetElement.setAttribute("frameInfo",7);
+ framesetElement.setAttribute("visible",1);
+ framesetElement.setAttribute("name",getFootnoteFramesetName(id));
+ framesetsPluralElement.appendChild(framesetElement);
+
+ QDomElement frameElementOut(mainDocument.createElement("FRAME"));
+ //frameElementOut.setAttribute("left",28);
+ //frameElementOut.setAttribute("top",42);
+ //frameElementOut.setAttribute("bottom",566);
+ //frameElementOut.setAttribute("right",798);
+ frameElementOut.setAttribute("runaround",1);
+ // ### TODO: a few attributes are missing
+ framesetElement.appendChild(frameElementOut);
+
+ stackItem->m_frameset=framesetElement;
+#else
+ stackItem->elementType=ElementTypeIgnore;
+#endif
+ return true;
+}
+
+// Element <table>
+bool StructureParser::StartElementTable(StackItem* stackItem, StackItem* stackCurrent,
+ const QXmlAttributes& attributes)
+{
+#if 1
+ // In KWord, inline tables are inside a paragraph.
+ // In AbiWord, tables are outside any paragraph.
+
+ QStringList widthList;
+ widthList.split('/', attributes.value("table-column-props"), false);
+ const uint columns = widthList.size();
+ stackItem->m_doubleArray.detach(); // Be sure not to modify parents
+ stackItem->m_doubleArray.resize(columns+1); // All left positions but the last right one
+ stackItem->m_doubleArray[0] = 0.0;
+ QStringList::ConstIterator it;
+ uint i;
+ for ( i=0, it=widthList.begin(); i<columns; ++i, ++it )
+ {
+ kdDebug(30506) << "Column width: " << (*it) << " cooked " << ValueWithLengthUnit(*it) << endl;
+ stackItem->m_doubleArray[i+1] = ValueWithLengthUnit(*it) + stackItem->m_doubleArray[i];
+ }
+ // ### TODO: in case of automatic column widths, we have not any width given by AbiWord
+
+ const uint tableNumber(++m_tableGroupNumber);
+ const QString tableName(i18n("Table %1").arg(tableNumber));
+
+ QDomElement elementText=stackCurrent->stackElementText;
+ QDomElement paragraphElementOut=mainDocument.createElement("PARAGRAPH");
+ stackCurrent->m_frameset.appendChild(paragraphElementOut);
+
+ QDomElement textElementOut(mainDocument.createElement("TEXT"));
+ textElementOut.appendChild(mainDocument.createTextNode("#"));
+ paragraphElementOut.appendChild(textElementOut);
+
+ QDomElement formatsPluralElementOut=mainDocument.createElement("FORMATS");
+ paragraphElementOut.appendChild(formatsPluralElementOut);
+
+ QDomElement elementFormat(mainDocument.createElement("FORMAT"));
+ elementFormat.setAttribute("id",6);
+ elementFormat.setAttribute("pos",0);
+ elementFormat.setAttribute("len",1);
+ formatsPluralElementOut.appendChild(elementFormat);
+
+ QDomElement elementAnchor(mainDocument.createElement("ANCHOR"));
+ elementAnchor.setAttribute("type","frameset");
+ elementAnchor.setAttribute("instance",tableName);
+ elementFormat.appendChild(elementAnchor);
+
+ stackItem->elementType=ElementTypeTable;
+ stackItem->stackElementParagraph=paragraphElementOut; // <PARAGRAPH>
+ stackItem->stackElementText=textElementOut; // <TEXT>
+ stackItem->stackElementFormatsPlural=formatsPluralElementOut; // <FORMATS>
+ stackItem->strTemp1=tableName;
+ stackItem->strTemp2=QString::number(tableNumber); // needed as I18N does not allow adding phrases
+ stackItem->pos=1; // Just #
+
+ // Now we populate the layout
+ QDomElement layoutElement=mainDocument.createElement("LAYOUT");
+ paragraphElementOut.appendChild(layoutElement);
+
+ AbiPropsMap abiPropsMap;
+ styleDataMap.useOrCreateStyle("Normal"); // We might have to create the "Normal" style.
+ AddLayout("Normal", layoutElement, stackItem, mainDocument, abiPropsMap, 0, false);
+#else
+ stackItem->elementType=ElementTypeIgnore;
+#endif
+ return true;
+}
+
+// <cell>
+bool StructureParser::StartElementCell(StackItem* stackItem, StackItem* stackCurrent,
+ const QXmlAttributes& attributes)
+{
+#if 1
+ if (stackCurrent->elementType!=ElementTypeTable)
+ {
+ kdError(30506) << "Wrong element type!! Aborting! (in StructureParser::endElementCell)" << endl;
+ return false;
+ }
+
+ stackItem->elementType=ElementTypeCell;
+
+ const QString tableName(stackCurrent->strTemp1);
+ kdDebug(30506) << "Table name: " << tableName << endl;
+
+ if (tableName.isEmpty())
+ {
+ kdError(30506) << "Table name is empty! Aborting!" << endl;
+ return false;
+ }
+
+ AbiPropsMap abiPropsMap;
+ abiPropsMap.splitAndAddAbiProps(attributes.value("props")); // Do not check PROPS
+
+ // We abuse the attach number to know the row and col numbers.
+ const uint row=abiPropsMap["top-attach"].getValue().toUInt();
+ const uint col=abiPropsMap["left-attach"].getValue().toUInt();
+
+ if ( col >= stackItem->m_doubleArray.size() )
+ {
+ // We do not know the right position of this column, so improvise. (### TODO)
+ // We play on the fact that QByteArray uses shallow copies by default.
+ // (We do want that the change is known at <table> level)
+ stackItem->m_doubleArray.resize( stackItem->m_doubleArray.size() + 1, QGArray::SpeedOptim );
+ stackItem->m_doubleArray[col+1] = stackItem->m_doubleArray[col] + 72; // Try 1 inch
+ }
+
+ const QString frameName(i18n("Frameset name","Table %3, row %1, column %2")
+ .arg(row).arg(col).arg(stackCurrent->strTemp2)); // As the stack could be wrong, be careful and use the string as last!
+
+ // We need to create a frameset for the cell
+ QDomElement framesetElement(mainDocument.createElement("FRAMESET"));
+ framesetElement.setAttribute("frameType",1);
+ framesetElement.setAttribute("frameInfo",0);
+ framesetElement.setAttribute("visible",1);
+ framesetElement.setAttribute("name",frameName);
+ framesetElement.setAttribute("row",row);
+ framesetElement.setAttribute("col",col);
+ framesetElement.setAttribute("rows",1); // ### TODO: rowspan
+ framesetElement.setAttribute("cols",1); // ### TODO: colspan
+ framesetElement.setAttribute("grpMgr",tableName);
+ framesetsPluralElement.appendChild(framesetElement);
+
+ QDomElement frameElementOut(mainDocument.createElement("FRAME"));
+ frameElementOut.setAttribute( "left", stackItem->m_doubleArray[col] );
+ frameElementOut.setAttribute( "right", stackItem->m_doubleArray[col+1] );
+ frameElementOut.setAttribute("top",0);
+ frameElementOut.setAttribute("bottom",0);
+ frameElementOut.setAttribute("runaround",1);
+ frameElementOut.setAttribute("autoCreateNewFrame",0); // Very important for cell growing!
+ // ### TODO: a few attributes are missing
+ framesetElement.appendChild(frameElementOut);
+
+ stackItem->m_frameset=framesetElement;
+ QDomElement nullDummy;
+ stackItem->stackElementParagraph=nullDummy; // <PARAGRAPH>
+ stackItem->stackElementText=nullDummy; // <TEXT>
+ stackItem->stackElementFormatsPlural=nullDummy; // <FORMATS>
+
+#else
+ stackItem->elementType=ElementTypeIgnore;
+#endif
+ return true;
+}
+
+// Parser for SAX2
+
+bool StructureParser :: startElement( const QString&, const QString&, const QString& name, const QXmlAttributes& attributes)
+{
+ //Warning: be careful that some element names can be lower case or upper case (not very XML)
+ kdDebug(30506) << indent << " <" << name << ">" << endl; //DEBUG
+ indent += "*"; //DEBUG
+
+ if (structureStack.isEmpty())
+ {
+ kdError(30506) << "Stack is empty!! Aborting! (in StructureParser::startElement)" << endl;
+ return false;
+ }
+
+ // Create a new stack element copying the top of the stack.
+ StackItem *stackItem=new StackItem(*structureStack.current());
+
+ if (!stackItem)
+ {
+ kdError(30506) << "Could not create Stack Item! Aborting! (in StructureParser::startElement)" << endl;
+ return false;
+ }
+
+ stackItem->itemName=name;
+
+ bool success=false;
+
+ if ((name=="c")||(name=="C"))
+ {
+ success=StartElementC(stackItem,structureStack.current(),attributes);
+ }
+ else if ((name=="p")||(name=="P"))
+ {
+ success=StartElementP(stackItem,structureStack.current(),mainDocument,
+ styleDataMap,attributes);
+ }
+ else if ((name=="section")||(name=="SECTION"))
+ {
+ success=StartElementSection(stackItem,structureStack.current(),attributes);
+ }
+ else if (name=="a")
+ {
+ success=StartElementA(stackItem,structureStack.current(),attributes);
+ }
+ else if (name=="br") // NOTE: Not sure if it only exists in lower case!
+ {
+ // We have a forced line break
+ StackItem* stackCurrent=structureStack.current();
+ success=StartElementBR(stackItem,stackCurrent,mainDocument);
+ }
+ else if (name=="cbr") // NOTE: Not sure if it only exists in lower case!
+ {
+ // We have a forced column break (not supported by KWord)
+ stackItem->elementType=ElementTypeEmpty;
+ StackItem* stackCurrent=structureStack.current();
+ if (stackCurrent->elementType==ElementTypeContent)
+ {
+ kdWarning(30506) << "Forced column break found! Transforming to forced page break" << endl;
+ success=complexForcedPageBreak(stackItem);
+ }
+ else if (stackCurrent->elementType==ElementTypeParagraph)
+ {
+ kdWarning(30506) << "Forced column break found! Transforming to forced page break" << endl;
+ success=StartElementPBR(stackItem,stackCurrent,mainDocument);
+ }
+ else
+ {
+ kdError(30506) << "Forced column break found out of turn! Aborting! Parent: "
+ << stackCurrent->itemName <<endl;
+ success=false;
+ }
+ }
+ else if (name=="pbr") // NOTE: Not sure if it only exists in lower case!
+ {
+ // We have a forced page break
+ stackItem->elementType=ElementTypeEmpty;
+ StackItem* stackCurrent=structureStack.current();
+ if (stackCurrent->elementType==ElementTypeContent)
+ {
+ success=complexForcedPageBreak(stackItem);
+ }
+ else if (stackCurrent->elementType==ElementTypeParagraph)
+ {
+ success=StartElementPBR(stackItem,stackCurrent,mainDocument);
+ }
+ else
+ {
+ kdError(30506) << "Forced page break found out of turn! Aborting! Parent: "
+ << stackCurrent->itemName <<endl;
+ success=false;
+ }
+ }
+ else if (name=="pagesize")
+ // Does only exist as lower case tag!
+ {
+ stackItem->elementType=ElementTypeEmpty;
+ stackItem->stackElementText=structureStack.current()->stackElementText; // TODO: reason?
+ success=StartElementPageSize(m_paperElement,attributes);
+ }
+ else if ((name=="field") //TODO: upper-case?
+ || (name=="f")) // old deprecated name for <field>
+ {
+ success=StartElementField(stackItem,structureStack.current(),mainDocument,attributes);
+ }
+ else if (name=="s") // Seems only to exist as lower case
+ {
+ success=StartElementS(stackItem,structureStack.current(),attributes,styleDataMap);
+ }
+ else if ((name=="image") //TODO: upper-case?
+ || (name=="i")) // old deprecated name for <image>
+ {
+ success=StartElementImage(stackItem,structureStack.current(),attributes);
+ }
+ else if (name=="d") // TODO: upper-case?
+ {
+ success=StartElementD(stackItem,structureStack.current(),attributes);
+ }
+ else if (name=="iw") // No upper-case
+ {
+ stackItem->elementType=ElementTypeIgnoreWord;
+ success=true;
+ }
+ else if (name=="m") // No upper-case
+ {
+ success=StartElementM(stackItem,structureStack.current(),attributes);
+ }
+ else if (name=="foot") // No upper-case
+ {
+ success=StartElementFoot(stackItem,structureStack.current(),attributes);
+ }
+ else if (name=="table") // No upper-case
+ {
+ success=StartElementTable(stackItem,structureStack.current(), attributes);
+ }
+ else if (name=="cell") // No upper-case
+ {
+ success=StartElementCell(stackItem,structureStack.current(),attributes);
+ }
+ else
+ {
+ stackItem->elementType=ElementTypeUnknown;
+ stackItem->stackElementText=structureStack.current()->stackElementText; // TODO: reason?
+ success=true;
+ }
+ if (success)
+ {
+ structureStack.push(stackItem);
+ }
+ else
+ { // We have a problem so destroy our resources.
+ delete stackItem;
+ }
+ return success;
+}
+
+bool StructureParser :: endElement( const QString&, const QString& , const QString& name)
+{
+ indent.remove( 0, 1 ); // DEBUG
+ kdDebug(30506) << indent << " </" << name << ">" << endl;
+
+ if (structureStack.isEmpty())
+ {
+ kdError(30506) << "Stack is empty!! Aborting! (in StructureParser::endElement)" << endl;
+ return false;
+ }
+
+ bool success=false;
+
+ StackItem *stackItem=structureStack.pop();
+ if ((name=="c")||(name=="C"))
+ {
+ success=EndElementC(stackItem,structureStack.current());
+ }
+ else if ((name=="p")||(name=="P"))
+ {
+ success=EndElementP(stackItem);
+ }
+ else if (name=="a")
+ {
+ if (stackItem->elementType==ElementTypeContent)
+ {
+ // Anchor to a bookmark (not supported by KWord))
+ success=EndElementC(stackItem,structureStack.current());
+ }
+ else
+ {
+ // Normal anchor
+ success=EndElementA(stackItem,structureStack.current(), mainDocument);
+ }
+ }
+ else if (name=="d")
+ {
+ success=EndElementD(stackItem);
+ }
+ else if (name=="iw") // No upper-case
+ {
+ success=EndElementIW(stackItem,structureStack.current(), mainDocument, m_ignoreWordsElement);
+ }
+ else if (name=="m") // No upper-case
+ {
+ success=EndElementM(stackItem);
+ }
+ else
+ {
+ success=true; // No problem, so authorisation to continue parsing
+ }
+ if (!success)
+ {
+ // If we have no success, then it was surely a tag mismatch. Help debugging!
+ kdError(30506) << "Found tag name: " << name
+ << " expected: " << stackItem->itemName << endl;
+ }
+ delete stackItem;
+ return success;
+}
+
+bool StructureParser :: characters ( const QString & ch )
+{
+ // DEBUG start
+ if (ch=="\n")
+ {
+ kdDebug(30506) << indent << " (LINEFEED)" << endl;
+ }
+ else if (ch.length()> 40)
+ { // 40 characters are enough (especially for image data)
+ kdDebug(30506) << indent << " :" << ch.left(40) << "..." << endl;
+ }
+ else
+ {
+ kdDebug(30506) << indent << " :" << ch << ":" << endl;
+ }
+ // DEBUG end
+ if (structureStack.isEmpty())
+ {
+ kdError(30506) << "Stack is empty!! Aborting! (in StructureParser::characters)" << endl;
+ return false;
+ }
+
+ bool success=false;
+
+ StackItem *stackItem=structureStack.current();
+
+ if ((stackItem->elementType==ElementTypeContent)
+ || (stackItem->elementType==ElementTypeAnchorContent))
+ { // <c>
+ success=charactersElementC(stackItem,mainDocument,ch);
+ }
+ else if (stackItem->elementType==ElementTypeParagraph)
+ { // <p>
+ success=charactersElementP(stackItem,mainDocument,ch);
+ }
+ else if (stackItem->elementType==ElementTypeAnchor)
+ { // <a>
+ success=charactersElementA(stackItem,ch);
+ }
+ else if (stackItem->elementType==ElementTypeEmpty)
+ {
+ success=ch.stripWhiteSpace().isEmpty();
+ if (!success)
+ {
+ // We have a parsing error, so abort!
+ kdError(30506) << "Empty element "<< stackItem->itemName
+ <<" is not empty! Aborting! (in StructureParser::characters)" << endl;
+ }
+ }
+ else if (stackItem->elementType==ElementTypeRealData)
+ {
+ success=CharactersElementD(stackItem,mainDocument,ch);
+ }
+ else if (stackItem->elementType==ElementTypeIgnoreWord)
+ {
+ stackItem->strTemp2+=ch; // Just collect the data
+ success=true;
+ }
+ else if (stackItem->elementType==ElementTypeRealMetaData)
+ {
+ success=CharactersElementM(stackItem,ch);
+ }
+ else
+ {
+ success=true;
+ }
+
+ return success;
+}
+
+bool StructureParser::startDocument(void)
+{
+ indent = QString::null; //DEBUG
+ styleDataMap.defineDefaultStyles();
+ return true;
+}
+
+void StructureParser::createDocInfo(void)
+{
+ QDomImplementation implementation;
+ QDomDocument doc(implementation.createDocumentType("document-info",
+ "-//KDE//DTD document-info 1.2//EN", "http://www.koffice.org/DTD/document-info-1.2.dtd"));
+
+ m_info=doc;
+
+ m_info.appendChild(
+ mainDocument.createProcessingInstruction(
+ "xml","version=\"1.0\" encoding=\"UTF-8\""));
+
+ QDomElement elementDoc(mainDocument.createElement("document-info"));
+ elementDoc.setAttribute("xmlns","http://www.koffice.org/DTD/document-info");
+ m_info.appendChild(elementDoc);
+
+ QDomElement about(mainDocument.createElement("about"));
+ elementDoc.appendChild(about);
+
+ QDomElement abstract(mainDocument.createElement("abstract"));
+ about.appendChild(abstract);
+ abstract.appendChild(mainDocument.createTextNode(m_metadataMap["dc.description"]));
+
+ QDomElement title(mainDocument.createElement("title"));
+ about.appendChild(title);
+ title.appendChild(mainDocument.createTextNode(m_metadataMap["dc.title"]));
+
+ QDomElement keyword(mainDocument.createElement("keyword"));
+ about.appendChild(keyword);
+ keyword.appendChild(mainDocument.createTextNode(m_metadataMap["abiword.keywords"]));
+
+ QDomElement subject(mainDocument.createElement("subject"));
+ about.appendChild(subject);
+ subject.appendChild(mainDocument.createTextNode(m_metadataMap["dc.subject"]));
+}
+
+bool StructureParser::endDocument(void)
+{
+ QDomElement stylesPluralElement=mainDocument.createElement("STYLES");
+ // insert before <PICTURES>, as <PICTURES> must remain last.
+ mainDocument.documentElement().insertBefore(stylesPluralElement,m_picturesElement);
+
+ kdDebug(30506) << "###### Start Style List ######" << endl;
+ StyleDataMap::ConstIterator it;
+
+ // At first, we put the Normal style
+ it=styleDataMap.find("Normal");
+ if (it!=styleDataMap.end())
+ {
+ kdDebug(30506) << "\"" << it.key() << "\" => " << it.data().m_props << endl;
+ QDomElement styleElement=mainDocument.createElement("STYLE");
+ stylesPluralElement.appendChild(styleElement);
+ AddStyle(styleElement, it.key(),it.data(),mainDocument);
+ }
+ else
+ kdWarning(30506) << "No 'Normal' style" << endl;
+
+ for (it=styleDataMap.begin();it!=styleDataMap.end();++it)
+ {
+ if (it.key()=="Normal")
+ continue;
+
+ kdDebug(30506) << "\"" << it.key() << "\" => " << it.data().m_props << endl;
+
+ QDomElement styleElement=mainDocument.createElement("STYLE");
+ stylesPluralElement.appendChild(styleElement);
+
+ AddStyle(styleElement, it.key(),it.data(),mainDocument);
+ }
+ kdDebug(30506) << "###### End Style List ######" << endl;
+
+ createDocInfo();
+
+ return true;
+}
+
+bool StructureParser::warning(const QXmlParseException& exception)
+{
+ kdWarning(30506) << "XML parsing warning: line " << exception.lineNumber()
+ << " col " << exception.columnNumber() << " message: " << exception.message() << endl;
+ return true;
+}
+
+bool StructureParser::error(const QXmlParseException& exception)
+{
+ // A XML error is recoverable, so it is only a KDE warning
+ kdWarning(30506) << "XML parsing error: line " << exception.lineNumber()
+ << " col " << exception.columnNumber() << " message: " << exception.message() << endl;
+ return true;
+}
+
+bool StructureParser::fatalError (const QXmlParseException& exception)
+{
+ kdError(30506) << "XML parsing fatal error: line " << exception.lineNumber()
+ << " col " << exception.columnNumber() << " message: " << exception.message() << endl;
+ m_fatalerror=true;
+ KMessageBox::error(NULL, i18n("An error has occurred while parsing the AbiWord file.\nAt line: %1, column %2\nError message: %3")
+ .arg(exception.lineNumber()).arg(exception.columnNumber())
+ .arg( i18n( "QXml", exception.message().utf8() ) ),
+ i18n("AbiWord Import Filter"),0);
+ return false; // Stop parsing now, we do not need further errors.
+}
+
+void StructureParser :: createDocument(void)
+{
+ QDomImplementation implementation;
+ QDomDocument doc(implementation.createDocumentType("DOC",
+ "-//KDE//DTD kword 1.2//EN", "http://www.koffice.org/DTD/kword-1.2.dtd"));
+
+ mainDocument=doc;
+
+ mainDocument.appendChild(
+ mainDocument.createProcessingInstruction(
+ "xml","version=\"1.0\" encoding=\"UTF-8\""));
+
+ QDomElement elementDoc;
+ elementDoc=mainDocument.createElement("DOC");
+ elementDoc.setAttribute("xmlns","http://www.koffice.org/DTD/kword");
+ elementDoc.setAttribute("editor","AbiWord Import Filter");
+ elementDoc.setAttribute("mime","application/x-kword");
+ elementDoc.setAttribute( "syntaxVersion", 3 );
+ mainDocument.appendChild(elementDoc);
+
+ QDomElement element;
+ element=mainDocument.createElement("ATTRIBUTES");
+ element.setAttribute("processing",0);
+ element.setAttribute("standardpage",1);
+ element.setAttribute("hasHeader",0);
+ element.setAttribute("hasFooter",0);
+ //element.setAttribute("unit","mm"); // use KWord default instead
+ element.setAttribute("tabStopValue",36); // AbiWord has a default of 0.5 inch tab stops
+ elementDoc.appendChild(element);
+
+ // <PAPER> will be partialy changed by an AbiWord <pagesize> element.
+ // Default paper format of AbiWord is "Letter"
+ m_paperElement=mainDocument.createElement("PAPER");
+ m_paperElement.setAttribute("format",PG_US_LETTER);
+ m_paperElement.setAttribute("width",MillimetresToPoints(KoPageFormat::width (PG_US_LETTER,PG_PORTRAIT)));
+ m_paperElement.setAttribute("height",MillimetresToPoints(KoPageFormat::height(PG_US_LETTER,PG_PORTRAIT)));
+ m_paperElement.setAttribute("orientation",PG_PORTRAIT);
+ m_paperElement.setAttribute("columns",1);
+ m_paperElement.setAttribute("columnspacing",2);
+ m_paperElement.setAttribute("hType",0);
+ m_paperElement.setAttribute("fType",0);
+ m_paperElement.setAttribute("spHeadBody",9);
+ m_paperElement.setAttribute("spFootBody",9);
+ m_paperElement.setAttribute("zoom",100);
+ elementDoc.appendChild(m_paperElement);
+
+ m_paperBordersElement=mainDocument.createElement("PAPERBORDERS");
+ m_paperBordersElement.setAttribute("left",28);
+ m_paperBordersElement.setAttribute("top",42);
+ m_paperBordersElement.setAttribute("right",28);
+ m_paperBordersElement.setAttribute("bottom",42);
+ m_paperElement.appendChild(m_paperBordersElement);
+
+ framesetsPluralElement=mainDocument.createElement("FRAMESETS");
+ mainDocument.documentElement().appendChild(framesetsPluralElement);
+
+ mainFramesetElement=mainDocument.createElement("FRAMESET");
+ mainFramesetElement.setAttribute("frameType",1);
+ mainFramesetElement.setAttribute("frameInfo",0);
+ mainFramesetElement.setAttribute("visible",1);
+ mainFramesetElement.setAttribute("name",i18n("Frameset name","Main Text Frameset"));
+ framesetsPluralElement.appendChild(mainFramesetElement);
+
+ QDomElement frameElementOut=mainDocument.createElement("FRAME");
+ frameElementOut.setAttribute("left",28);
+ frameElementOut.setAttribute("top",42);
+ frameElementOut.setAttribute("bottom",566);
+ frameElementOut.setAttribute("right",798);
+ frameElementOut.setAttribute("runaround",1);
+ // TODO: a few attributes are missing
+ mainFramesetElement.appendChild(frameElementOut);
+
+ // As we are manipulating the document, create a few particular elements
+ m_ignoreWordsElement=mainDocument.createElement("SPELLCHECKIGNORELIST");
+ mainDocument.documentElement().appendChild(m_ignoreWordsElement);
+ m_picturesElement=mainDocument.createElement("PICTURES");
+ mainDocument.documentElement().appendChild(m_picturesElement);
+}
+
+bool StructureParser::clearStackUntilParagraph(StackItemStack& auxilaryStack)
+{
+ for (;;)
+ {
+ StackItem* item=structureStack.pop();
+ switch (item->elementType)
+ {
+ case ElementTypeContent:
+ {
+ // Push the item on the auxilary stack
+ auxilaryStack.push(item);
+ break;
+ }
+ case ElementTypeParagraph:
+ {
+ // Push back the item on this stack and then stop loop
+ structureStack.push(item);
+ return true;
+ }
+ default:
+ {
+ // Something has gone wrong!
+ kdError(30506) << "Cannot clear this element: "
+ << item->itemName << endl;
+ return false;
+ }
+ }
+ }
+}
+
+ABIWORDImport::ABIWORDImport(KoFilter */*parent*/, const char */*name*/, const QStringList &) :
+ KoFilter() {
+}
+
+KoFilter::ConversionStatus ABIWORDImport::convert( const QCString& from, const QCString& to )
+{
+ if ((to != "application/x-kword") || (from != "application/x-abiword"))
+ return KoFilter::NotImplemented;
+
+ kdDebug(30506)<<"AbiWord to KWord Import filter"<<endl;
+
+ StructureParser handler(m_chain);
+
+ //We arbitrarily decide that Qt can handle the encoding in which the file was written!!
+ QXmlSimpleReader reader;
+ reader.setContentHandler( &handler );
+ reader.setErrorHandler( &handler );
+
+ //Find the last extension
+ QString strExt;
+ QString fileIn = m_chain->inputFile();
+ const int result=fileIn.findRev('.');
+ if (result>=0)
+ {
+ strExt=fileIn.mid(result);
+ }
+
+ kdDebug(30506) << "File extension: -" << strExt << "-" << endl;
+
+ QString strMime; // Mime type of the compressor (default: unknown)
+
+ 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
+ strMime="application/x-gzip";
+ kdDebug(30506) << "Compression: gzip" << endl;
+ }
+ 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
+ strMime="application/x-bzip2";
+ kdDebug(30506) << "Compression: bzip2" << endl;
+ }
+
+ QIODevice* in = KFilterDev::deviceForFile(fileIn,strMime);
+
+ if ( !in )
+ {
+ kdError(30506) << "Cannot create device for uncompressing! Aborting!" << endl;
+ return KoFilter::FileNotFound; // ### TODO: better error?
+ }
+
+ if (!in->open(IO_ReadOnly))
+ {
+ kdError(30506) << "Cannot open file for uncompressing! Aborting!" << endl;
+ delete in;
+ return KoFilter::FileNotFound;
+ }
+
+ QXmlInputSource source(in); // Read the file
+
+ in->close();
+
+ if (!reader.parse( source ))
+ {
+ kdError(30506) << "Import: Parsing unsuccessful. Aborting!" << endl;
+ delete in;
+ if (!handler.wasFatalError())
+ {
+ // As the parsing was stopped for something else than a fatal error, we have not yet get an error message. (Can it really happen?)
+ KMessageBox::error(NULL, i18n("An error occurred during the load of the AbiWord file: %1").arg(from),
+ i18n("AbiWord Import Filter"),0);
+ }
+ return KoFilter::ParsingError;
+ }
+ delete in;
+
+ QCString strOut;
+ KoStoreDevice* out;
+
+ kdDebug(30506) << "Creating documentinfo.xml" << endl;
+ out=m_chain->storageFile( "documentinfo.xml", KoStore::Write );
+ if(!out)
+ {
+ kdError(30506) << "AbiWord Import unable to open output file! (Documentinfo)" << endl;
+ KMessageBox::error(NULL, i18n("Unable to save document information."),i18n("AbiWord Import Filter"),0);
+ return KoFilter::StorageCreationError;
+ }
+
+ //Write the document information!
+ strOut=handler.getDocInfo().toCString(); // UTF-8
+ // WARNING: we cannot use KoStore::write(const QByteArray&) because it writes an extra NULL character at the end.
+ out->writeBlock(strOut,strOut.length());
+
+ kdDebug(30506) << "Creating maindoc.xml" << endl;
+ out=m_chain->storageFile( "root", KoStore::Write );
+ if(!out)
+ {
+ kdError(30506) << "AbiWord Import unable to open output file! (Root)" << endl;
+ KMessageBox::error(NULL, i18n("Unable to save main document."),i18n("AbiWord Import Filter"),0);
+ return KoFilter::StorageCreationError;
+ }
+
+ //Write the document!
+ strOut=handler.getDocument().toCString(); // UTF-8
+ // WARNING: we cannot use KoStore::write(const QByteArray&) because it writes an extra NULL character at the end.
+ out->writeBlock(strOut,strOut.length());
+
+#if 0
+ kdDebug(30506) << documentOut.toString();
+#endif
+
+ kdDebug(30506) << "Now importing to KWord!" << endl;
+
+ return KoFilter::OK;
+}
+
+#include "abiwordimport.moc"
diff --git a/filters/kword/abiword/abiwordimport.h b/filters/kword/abiword/abiwordimport.h
new file mode 100644
index 000000000..3ead0283f
--- /dev/null
+++ b/filters/kword/abiword/abiwordimport.h
@@ -0,0 +1,54 @@
+/*
+ This file is part of the KDE project
+ Copyright (C) 2001 Nicolas GOUTTE <goutte@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+/*
+ This file is based on the old file:
+ koffice/filters/kword/ascii/asciiimport.h
+
+ The old file was copyrighted by
+ Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
+ Copyright (C) 2000 Michael Johnson <mikej@xnet.com>
+
+ The old file was licensed under the terms of the GNU Library General Public
+ License version 2.
+*/
+
+#ifndef ABIWORDIMPORT_H
+#define ABIWORDIMPORT_H
+
+#include <qstring.h>
+#include <qfile.h>
+#include <qobject.h>
+
+#include <KoFilter.h>
+#include <KoStore.h>
+
+class ABIWORDImport : public KoFilter {
+
+ Q_OBJECT
+
+public:
+ ABIWORDImport(KoFilter *parent, const char *name, const QStringList &);
+ ABIWORDImport();
+ virtual ~ABIWORDImport() {}
+
+ virtual KoFilter::ConversionStatus convert( const QCString& from, const QCString& to );
+};
+#endif // ABIWORDIMPORT_H
diff --git a/filters/kword/abiword/kword_abiword_export.desktop b/filters/kword/abiword/kword_abiword_export.desktop
new file mode 100644
index 000000000..0125bc1d1
--- /dev/null
+++ b/filters/kword/abiword/kword_abiword_export.desktop
@@ -0,0 +1,73 @@
+[Desktop Entry]
+Type=Service
+Name=KWord AbiWord Export Filter
+Name[af]=Kword Abiword Voer uit Filter
+Name[ar]=مِرْشَح تصدير AbiWord لدى KWord
+Name[az]=KWord AbiWord Alma Süzgəci
+Name[bg]=Филтър за експортиране от KWord в AbiWord
+Name[br]=Sil ezporzh AbiWord evit KWord
+Name[ca]=Filtre d'exportació AbiWord per a KWord
+Name[cs]=KWord AbiWord exportní filtr
+Name[cy]=Hidlen Allforio AbiWord KWord
+Name[da]=KWord AbiWord-eksportfilter
+Name[de]=KWord AbiWord-Exportfilter
+Name[el]=Φίλτρο εξαγωγής Abiword του KWord
+Name[eo]=KWord AbiWord-eksportfiltrilo
+Name[es]=Filtro de exportación AbiWord de KWord
+Name[et]=KWordi AbiWord'i ekspordifilter
+Name[eu]=KWord-en AbiWord esportaziorako iragazkia
+Name[fa]=پالایۀ صادرات KWord AbiWord
+Name[fi]=KWord AbiWord -vientisuodin
+Name[fo]=KOrð til AbiWord-umsetari
+Name[fr]=Filtre d'exportation AbiWord de KWord
+Name[fy]=KWord AbiWord Eksportfilter
+Name[ga]=Scagaire Easpórtála AbiWord KWord
+Name[gl]=Filtro de exportación para AbiWord de KWord
+Name[he]=מסנן ייצוא מ־KWord ל־AbiWord
+Name[hi]=के-वर्ड एबीवर्ड निर्यात छननी
+Name[hr]=KWord Abiword filtar izvoza
+Name[hu]=KWord AbiWord exportszűrő
+Name[id]=Filter Ekspor AbiWord KWord
+Name[is]=KWord AbiWord útflutningssía
+Name[it]=Filtro di esportazione AbiWord per KWord
+Name[ja]=KWord AbiWord エクスポートフィルタ
+Name[km]=តម្រង​នាំចេញ AbiWord សម្រាប់ KWord
+Name[lo]= ຕົວຕອງການສົ່ງອອກ AbiWord ຂອງເອກະສານຂໍ້ຄວາມ K
+Name[lt]=KWord AbiWord eksporto filtras
+Name[lv]=KWord AbiWord eksporta filtrs
+Name[ms]=Penapis Eksport KWord AbiWord
+Name[mt]=Filtru għall-esportazzjoni ta' AbiWord minn ġo KWord
+Name[nb]=AbiWord-eksportfilter for KWord
+Name[nds]=AbiWord-Exportfilter för KWord
+Name[ne]=केडीई शब्द एबीआई वर्ड निर्यात फिल्टर
+Name[nl]=KWord AbiWord-Exportfilter
+Name[nn]=AbiWord-eksportfilter for KWord
+Name[pl]=Filtr eksportu do formatu AbiWord z KWord
+Name[pt]=Filtro de exportação para AbiWord do KWord
+Name[pt_BR]=Filtro de exportação AbiWord para o KWord
+Name[ro]=Filtru exportare KWord pentru AbiWord
+Name[ru]=Фильтр экспорта документов KWord в AbiWord
+Name[se]=KWord:a AbiWord-olggosfievrridansilli
+Name[sk]=AbiWord filter pre export z KWord-u
+Name[sl]=Izvozni filter AbiWord za KWord
+Name[sr]=KWord-ов филтер за извоз у AbiWord
+Name[sr@Latn]=KWord-ov filter za izvoz u AbiWord
+Name[sv]=Kword-exportfilter för Abiword
+Name[ta]=KWord AbiWord ஏற்றுமதி வடிகட்டி
+Name[tg]=Филтри Содироти KWord AbiWord
+Name[th]=ตัวกรองการส่งออก AbiWord ของเอกสารข้อความ K
+Name[tr]=KWord için AbiWord Aktarma Filtresi
+Name[uk]=Фільтр експорту AbiWord для KWord
+Name[uz]=KWord AbiWord eksport filteri
+Name[uz@cyrillic]=KWord AbiWord экспорт филтери
+Name[ven]=Maipfi a K maipfi a Abi U bvisela nga nnda filithara
+Name[wa]=Passete AbiWord di rexhowe po KWord
+Name[xh]=Isihluzi Sokurhweba ngaphandle se KWord AbiWord
+Name[zh_CN]=KWord AbiWord 导出过滤器
+Name[zh_TW]=KWord AbiWord 匯出過濾程式
+Name[zu]=KWord AbiWord Icebo Export Filter
+X-KDE-Export=application/x-abiword
+X-KDE-Import=application/x-kword
+X-KDE-Weight=1
+X-KDE-Library=libabiwordexport
+ServiceTypes=KOfficeFilter
diff --git a/filters/kword/abiword/kword_abiword_import.desktop b/filters/kword/abiword/kword_abiword_import.desktop
new file mode 100644
index 000000000..e0b11cfb4
--- /dev/null
+++ b/filters/kword/abiword/kword_abiword_import.desktop
@@ -0,0 +1,73 @@
+[Desktop Entry]
+Type=Service
+Name=KWord AbiWord Import Filter
+Name[af]=Kword Abiword In voer Filter
+Name[ar]=مِرْشَح استيراد AbiWord لدى KWord
+Name[az]=KWord AbiWord Qeyd Süzgəci
+Name[bg]=Филтър за импортиране от AbiWord в KWord
+Name[br]=Sil enporzh AbiWord evit KWord
+Name[ca]=Filtre d'importació AbiWord per a KWord
+Name[cs]=KWord AbiWord importní filtr
+Name[cy]=Hidlen Fewnforio AbiWord KWord
+Name[da]=KWord Applixword-importfilter
+Name[de]=KWord AbiWord-Importfilter
+Name[el]=Φίλτρο εισαγωγής Abiword του KWord
+Name[eo]=KWord AbiWord-importfiltrilo
+Name[es]=Filtro de importación AbiWord de KWord
+Name[et]=KWordi AbiWord'i impordifilter
+Name[eu]=KWord-en AbiWord inportaziorako iragazkia
+Name[fa]=پالایۀ واردات KWord AbiWord
+Name[fi]=KWord AbiWord -tuontisuodin
+Name[fo]=AbiWord til KOrð-umsetari
+Name[fr]=Filtre d'importation AbiWord de KWord
+Name[fy]=KWord AbiWord Ymportfilter
+Name[ga]=Scagaire Iompórtála AbiWord KWord
+Name[gl]=Filtro de importación de AbiWord para KWord
+Name[he]=מסנן ייבוא מ־AbiWord ל־KWord
+Name[hi]=के-वर्ड एबीवर्ड आयात छननी
+Name[hr]=KWord Abiword filtar uvoza
+Name[hu]=KWord AbiWord importszűrő
+Name[id]=Filter Impor AbiWord KWord
+Name[is]=KWord AbiWord innflutningssía
+Name[it]=Filtro di importazione AbiWord per KWord
+Name[ja]=KWord AbiWord インポートフィルタ
+Name[km]=តម្រង​នាំចូល AbiWord សម្រាប់ KWord
+Name[lo]= ຕົວຕອງການນຳເຂົ້າ AbiWord ຂອງເອກະສານຂໍ້ຄວາມ K
+Name[lt]=KWord AbiWord importo filtras
+Name[lv]=KWord AbiWord importa filtrs
+Name[ms]=Penapis Import KWord AbiWord
+Name[mt]=Filtru għall-importazzjoni ta' AbiWord ġo KWord
+Name[nb]=AbiWord-importfilter for KWord
+Name[nds]=AbiWord-Importfilter för KWord
+Name[ne]=केडीई शब्द एबीआई वर्ड आयात फिल्टर
+Name[nl]=KWord AbiWord-importfilter
+Name[nn]=AbiWord-importfilter for KWord
+Name[pl]=Filtr importu formatu AbiWord do KWord
+Name[pt]=Filtro de importação do AbiWord para o KWord
+Name[pt_BR]=Filtro de importação AbiWord para o KWord
+Name[ro]=Filtru importare KWord pentru AbiWord
+Name[ru]=Фильтр импорта документов AbiWord в KWord
+Name[se]=KWord:a AbiWord-sisafievrridansilli
+Name[sk]=AbiWord filter pre import do KWord-u
+Name[sl]=Uvozni filter AbiWord za KWord
+Name[sr]=KWord-ов филтер за увоз из AbiWord-а
+Name[sr@Latn]=KWord-ov filter za uvoz iz AbiWord-a
+Name[sv]=Kword-importfilter för Abiword
+Name[ta]=KWord AbiWord இறக்குமதி வடிகட்டி
+Name[tg]=Филтри Воридоти KWord AbiWord
+Name[th]=ตัวกรองการนำเข้า AbiWord ของเอกสารข้อความ K
+Name[tr]=KWord için AbiWord Alma Filtresi
+Name[uk]=Фільтр імпорту AbiWord для KWord
+Name[uz]=KWord AbiWord import filteri
+Name[uz@cyrillic]=KWord AbiWord импорт филтери
+Name[ven]=Maipfi a K Maipfi a Abi u Dzhenisa nga ngomu filithara
+Name[wa]=Passete Abiword d' intrêye po KWord
+Name[xh]=Isihluzi Sokurhweba se KWord AbiWord
+Name[zh_CN]=KWord AbiWord 导入过滤器
+Name[zh_TW]=KWord AbiWord 匯入過濾程式
+Name[zu]=KWord AbiWord Icebo lokucoca ulwelo olurhwetyiweyo ngaphakathi
+X-KDE-Export=application/x-kword
+X-KDE-Import=application/x-abiword
+X-KDE-Weight=1
+X-KDE-Library=libabiwordimport
+ServiceTypes=KOfficeFilter
diff --git a/filters/kword/abiword/status.html b/filters/kword/abiword/status.html
new file mode 100644
index 000000000..de78dd484
--- /dev/null
+++ b/filters/kword/abiword/status.html
@@ -0,0 +1,219 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>KOffice filters status: AbiWord Filter</title>
+</head>
+<body text="#000000" bgcolor="#FFFFFF" link="#000099" vlink="#666666" alink="#666666">
+<a NAME="START">&nbsp;</a>
+
+<BR>
+<center>
+ <h1>
+ KOffice filters status: &nbsp;&nbsp;<i>AbiWord Filter</i>
+ </h1>
+</center>
+
+<hr NOSHADE SIZE=2 WIDTH="70%">
+
+<font size="-1"><b>
+ <a HREF="#import">Import</a> |
+ <a HREF="#export">Export</a>
+</b></font>
+
+<BR><BR><BR>
+<center><a NAME="import">&nbsp;</a></center>
+
+<a HREF="#START"><font size="-1"><b>Up</b></font></a>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+
+ <tr BGCOLOR="#DDFFDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ Import AbiWord for KWord<BR>
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>12 Jun 2005</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>
+ - Import text<br>
+ - Can import formatting<br>
+ - Can read gzip-compressed files (just use .abw.gz or .zabw as an extension of the filename!)<br>
+ - Can read bzip2-compressed files (just use .abw.bz2 or .bzabw as an extension of the filename!)<br>
+ - Styles<br>
+ - Result of character styles<br>
+ - Images (PNG)<br>
+ - Fields (as far as KWord supports them.)<br>
+ - Page size, including page margins<br>
+ - Import ignored word list (for spell checking)<br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>
+ - Multiple columns<br>
+ - Lists<br>
+ - Header/footer<br>
+ - Bookmarks<br>
+ - Tables<br>
+ - Footnotes<br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>
+ 19 Jan 2001: First half working import filter.<br>
+ 24 Jan 2001: Can read gzip compressed AbiWord files.<br>
+ 31 Jan 2001: Can import all formating at character level.<br>
+ 09 Jan 2002: Can import styles.<br>
+ 27 Feb 2002: Fields.<br>
+ 19 Mar 2002: More styles, inlcuding character ones.<br>
+ 07 Jun 2002: Ignored Word List<br>
+ 28 Jan 2003: new XML parsing error message box<br>
+ 12 Jun 2005: import keyword/subject in documentinfo<br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td><a href="mailto:goutte@kde.org">Nicolas GOUTTE</a></td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td>
+ <a href="http://www.abisource.com">AbiSource</a> (AbiWord's homepage)<br>
+ <a href="http://www.abisource.com/awml.dtd">AbiWord's DTD</a><br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Comment</font></b></td>
+ <td>
+ NOTE: this status describes the version of the filter for KOffice 1.3 (CVS HEAD)<br>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<a HREF="#START"><font size="-1"><b>Up</b></font></a>
+
+<br><br><br>
+
+<hr NOSHADE SIZE=1>
+<br><br><br>
+
+
+<center>
+ <a NAME="export">&nbsp;</a>
+</center>
+
+<a HREF="#START"><font size="-1"><b>Up</b></font></a>
+<center>
+<table BORDER=0 CELLSPACING=0 BGCOLOR="#000000" WIDTH="100%">
+ <tr>
+ <td>
+ <table BORDER=0 CELLPADDING=2 BGCOLOR="#FFFFFF" WIDTH="100%">
+ <tr BGCOLOR="#FFDDDD">
+ <td COLSPAN="2">
+ <center><b><i><font size="+1">
+ Export KWord to AbiWord
+ </font></i></b></center>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP WIDTH="1%" NOWRAP><b><font size="+1">Last update</font></b></td>
+ <td>25 Jan 2003</td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Features</font></b></td>
+ <td>
+ - Can export simple text<br>
+ - Can export formatting<br>
+ - Can write gzip-compressed files (just use .abw.gz or .zabw as an extension of the filename!)<br>
+ - Can handle forced page breaks<br>
+ - Can export inlined pictures (converted to PNG)<br>
+ - Can export styles<br>
+ - Can export variables into fields (no custom variables!)<br>
+ - Can export page size, including page margins<br>
+ - Can export the ignored word list (for spell checking)<br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Todo</font></b></td>
+ <td>
+ - Multiple columns.<br>
+ - Lists.<br>
+ - Inlined formula (MATHML)<br>
+ - Non-inlined pictures<br>
+ - Tables<br>
+ - KWord's DTP modus (How can you export that in AbiWord?)<br>
+ - Bookmarks<br>
+ - Footnotes<br>
+ - Many other things...<br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">History</font></b></td>
+ <td>
+ 17 Jan 2001: First filter version (can export simple texts and formats)<br>
+ 21 Jan 2001: Added colours and corrected bug in font size<br>
+ 31 Jan 2001: New form of comment header in the exported file<br>
+ 19 Mar 2001: Fix the bug due to the new KWord<br>
+ 16 Aug 2001: Fix forced page break handling<br>
+ 29 Nov 2001: Export of inlined images (PNG)<br>
+ 24 Feb 2002: Simplify the written file by avoiding redundant information<br>
+ 27 Feb 2002: Fields<br>
+ 19 Mar 2002: Page margins<br>
+ 09 Jun 2002: Ignored Word List<br>
+ 25 Jan 2003: Fix export of pictures<br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Authors</font></b></td>
+ <td><a href="mailto:goutte@kde.org">Nicolas GOUTTE</a></td>
+ </tr>
+
+ <tr BGCOLOR="#CCCCFF">
+ <td VALIGN=TOP><b><font size="+1">Links</font></b></td>
+ <td>
+ <a href="http://www.abisource.com">Abisource</a> (AbiWord's homepage)<br>
+ <a href="http://www.abisource.com/awml.dtd">AbiWord's DTD</a><br>
+ </td>
+ </tr>
+
+ <tr BGCOLOR="#EEEEFF">
+ <td VALIGN=TOP><b><font size="+1">Comment</font></b></td>
+ <td>
+ NOTE: this status describes the version of the filter for KOffice 1.3 (CVS HEAD)<br>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+</center>
+<a HREF="#START"><font size="-1"><b>Up</b></font></a>
+
+</body>
+</html>