You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/filters/kword/html/import/kwdwriter.cpp

588 lines
19 KiB

/***************************************************************************
kwdwriter.cpp - description
-------------------
begin : Wed Sep 5 2001
copyright : (C) 2001 by Frank Dekervel
email : Frank.Dekervel@student.kuleuven.ac.be
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License *
* as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "kwdwriter.h"
#include <stdlib.h>
#include "tqrect.h"
#include <KoTextZoomHandler.h>
#include <tqpaintdevice.h>
KWDWriter::KWDWriter(KoStore *store){
_zoomhandler = new KoTextZoomHandler();
_store=store;
_doc= new TQDomDocument("DOC");
_docinfo = new TQDomDocument("document-info");
_doc->appendChild( _doc->createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
_docinfo->appendChild( _docinfo->createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
TQDomElement infodoc = _docinfo->createElement( "document-info" );
_docinfoMain=infodoc;
_docinfo->appendChild(infodoc);
tableNo=1;
insidetable = false;
TQDomElement kwdoc = _doc->createElement( "DOC" );
kwdoc.setAttribute( "editor", "HTML Import Filter" );
kwdoc.setAttribute( "mime", "application/x-kword" );
_doc->appendChild( kwdoc );
TQDomElement paper = _doc->createElement( "PAPER" );
kwdoc.appendChild( paper );
paper.setAttribute( "format", 1 );
paper.setAttribute( "width", 595 );
paper.setAttribute( "height", 841 );
paper.setAttribute( "orientation", 0 );
paper.setAttribute( "columns", 1 );
paper.setAttribute( "columnspacing", 3 );
paper.setAttribute( "hType", 0 );
paper.setAttribute( "fType", 0 );
TQDomElement borders = _doc->createElement( "PAPERBORDERS" );
paper.appendChild( borders );
borders.setAttribute( "left", 20 );
borders.setAttribute( "top", 10 );
borders.setAttribute( "right", 10 );
borders.setAttribute( "bottom", 10 );
TQDomElement docattrs = _doc->createElement( "ATTRIBUTES" );
kwdoc.appendChild( docattrs );
docattrs.setAttribute( "processing", 0 );
docattrs.setAttribute( "standardpage", 1 );
docattrs.setAttribute( "hasHeader", 0 );
docattrs.setAttribute( "hasFooter", 0 );
//docattrs.setAttribute( "unit", "mm" ); // use KWord default instead
TQDomElement framesets = _doc->createElement("FRAMESETS");
kwdoc.appendChild(framesets);
TQDomElement rootframeset = addFrameSet(framesets);
_mainFrameset=rootframeset;
TQDomElement mainframe= addFrame(rootframeset,TQRect(28,28,539,757));
TQDomElement styles=_doc->createElement("STYLES");
kwdoc.appendChild(styles);
TQDomElement standard=_doc->createElement("STYLE");
styles.appendChild(standard);
TQDomElement tmp;
tmp=_doc->createElement("NAME");
tmp.setAttribute("value","Standard");
standard.appendChild(tmp);
tmp=_doc->createElement("FOLLOWING");
tmp.setAttribute("name","Standard");
standard.appendChild(tmp);
TQDomElement fmt;
fmt=_doc->createElement("FORMAT");
fmt.setAttribute("id","1");
standard.appendChild(fmt);
tmp=_doc->createElement("SIZE");
tmp.setAttribute("value","12"); // HACK !
fmt.appendChild(tmp);
#define HEADINGSTYLE(a,b) standard=_doc->createElement("STYLE");\
styles.appendChild(standard);\
tmp=_doc->createElement("NAME");\
tmp.setAttribute("value",#a);\
standard.appendChild(tmp);\
tmp=_doc->createElement("FOLLOWING");\
tmp.setAttribute("name","Standard");\
standard.appendChild(tmp);\
fmt=_doc->createElement("FORMAT");\
fmt.setAttribute("id","1");\
standard.appendChild(fmt);\
tmp=_doc->createElement("SIZE");\
tmp.setAttribute("value",#b);\
fmt.appendChild(tmp);
HEADINGSTYLE(h1,20);
HEADINGSTYLE(h2,18);
HEADINGSTYLE(h3,16);
HEADINGSTYLE(h4,14);
HEADINGSTYLE(h5,10);
HEADINGSTYLE(h6,8);
}
bool KWDWriter::isInTable() const {
return insidetable;
}
int KWDWriter::createTable() {
insidetable = true;
return tableNo++;
}
void KWDWriter::createDocInfo(TQString author, TQString title) {
TQDomElement authorTag=_docinfo->createElement("author");
TQDomElement aboutTag=_docinfo->createElement("about");
TQDomElement fullNameTag=_docinfo->createElement("full-name");
TQDomText titleText=_docinfo->createTextNode(title);
TQDomText authorText=_docinfo->createTextNode(author);
fullNameTag.appendChild(authorText);
authorTag.appendChild(fullNameTag);
TQDomElement titleTag=_docinfo->createElement("title");
titleTag.appendChild(titleText);
aboutTag.appendChild(titleTag);
_docinfoMain.appendChild(authorTag);
_docinfoMain.appendChild(aboutTag);
}
void KWDWriter::createInline(TQDomElement paragraph, TQDomElement toInline) {
if (toInline.tagName() == "FRAMESET") {
formatAttribute(paragraph,"ANCHOR","type","frameset");
// fixme: support other kinds of inlines.
}
if (!toInline.attribute("grpMgr").isEmpty()) {
formatAttribute(paragraph,"ANCHOR","instance",toInline.attribute("grpMgr"));
}
addText(paragraph,"#",6); // the anchor.
}
TQDomElement KWDWriter::currentLayout(TQDomElement paragraph) {
return paragraph.elementsByTagName("LAYOUT").item(0).toElement();
}
TQDomElement KWDWriter::createTableCell(int tableno, int nrow,
int ncol, int colspan, TQRect rect) {
TQDomElement parent=docroot().elementsByTagName("FRAMESETS").item(0).toElement();
TQDomElement fs=addFrameSet(parent,1,0,
TQString("Table %1 - %2,%3").arg(tableno).arg(nrow).arg(ncol),
1);
fs.setAttribute("grpMgr",TQString("Table %1").arg(tableno));
fs.setAttribute("row",nrow);
fs.setAttribute("col",ncol);
fs.setAttribute("cols",colspan); // FIXME do colspan in finishTable
// so we don't have to give it as an argument
fs.setAttribute("rows",1); // FIXME support rowspan ?
addFrame(fs,rect);
return fs;
}
TQDomElement KWDWriter::fetchTableCell(int tableno, int rowno, int colno) {
TQDomNodeList e=docroot().elementsByTagName("FRAMESET");
for (unsigned int i=0;i<e.count();i++) {
TQDomElement k=e.item(i).toElement();
if (k.attribute("grpMgr") == TQString("Table %1").arg(tableno))
if (k.attribute("row") == TQString("%1").arg(rowno))
if (k.attribute("col") == TQString("%1").arg(colno))
return k;
}
TQDomElement dummy;
return dummy;
}
#define MAX(x,y) ((x > y) ? x : y)
#define MIN(x,y) ((x < y) ? x : y)
void KWDWriter::finishTable(int tableno) {
finishTable(tableno,TQRect(-1,-1,-1,-1));
}
void KWDWriter::createHR(TQDomElement paragraph, int width) {
layoutAttribute(paragraph,"BOTTOMBORDER","width",TQString("%1").arg(width));
}
void KWDWriter::finishTable(int tableno,TQRect rect) {
int ncols=0;
int nrows=0;
insidetable = false;
int x=rect.x();
int y=rect.y();
int w=rect.width();
int h=rect.height();
TQDomNodeList nl=docroot().elementsByTagName("FRAMESET");
//FIXME calculate nrows and stuff.
//and add empty cells for missing ones.
// first, see how big the table is (cols & rows)
for (unsigned i=0;i<nl.count();i++) {
TQDomElement k=nl.item(i).toElement();
if (k.attribute("grpMgr") == TQString("Table %1").arg(tableno)) {
ncols=MAX(ncols,k.attribute("col").toInt()+1);
nrows=MAX(nrows,k.attribute("row").toInt()+1);
}
}
int curcol=0;
int currow=0;
int currow_inc=0;
if (ncols == 0) ncols=1; // FIXME (floating point division by zero)
if (nrows == 0) nrows=1;
int step_x=(w-x)/ncols;
int step_y=(h-y)/nrows;
// then, let's create the missing cells and resize them if needed.
bool must_resize=false;
if (x>0) must_resize=true;
while (currow < nrows) {
curcol=0;
while (curcol < ncols) {
TQDomElement e=fetchTableCell(tableno,currow,curcol);
if (e.isNull()) {
// a missing cell !
kdDebug(30503) << TQString("creating %1 %2").arg(currow).arg(curcol).latin1() << endl;
createTableCell(tableno,currow,curcol,1,
TQRect(x+step_x*curcol,y+step_y*currow,step_x,step_y)
);
// fixme: what to do if we don't have to resize ?
}
// resize this one FIXME optimize this routine
if (must_resize == true) {
TQDomElement ee=e.firstChild().toElement(); // the frame in the frameset
int cs=e.attribute("cols").toInt();
int rs=e.attribute("rows").toInt();
kdDebug(30503) << "resizing" << endl;
addRect(ee,TQRect(x+step_x*curcol,0,step_x*cs,step_y*rs));
}
if (curcol==0) currow_inc=e.attribute("rows").toInt();
curcol +=e.attribute("cols").toInt();
}
currow+=currow_inc;
}
}
TQDomElement KWDWriter::addFrameSet(TQDomElement parent, int frametype,
int frameinfo, TQString name, int visible) {
TQDomElement frameset=_doc->createElement("FRAMESET");
parent.appendChild(frameset);
frameset.setAttribute("frameType",frametype);
frameset.setAttribute("frameInfo",frameinfo);
if (!name.isNull())
frameset.setAttribute("name",name);
else
frameset.setAttribute("name","Text-frameset 1");
frameset.setAttribute("visible",visible);
return frameset;
}
TQDomElement KWDWriter::addParagraph(TQDomElement parent) {
TQDomElement k;
return addParagraph(parent,k);
}
void KWDWriter::appendKWordVariable(TQDomDocument& doc, TQDomElement& format,
const TQString& text, const TQString& key, int type, TQDomElement& child) {
TQDomElement variableElement ( doc.createElement("VARIABLE") );
TQDomElement typeElement ( doc.createElement("TYPE") );
typeElement.setAttribute("key",key);
typeElement.setAttribute("type",type);
typeElement.setAttribute("text",text);
variableElement.appendChild(typeElement); //Append to <VARIABLE>
variableElement.appendChild(child); //Append to <VARIABLE>
format.appendChild(variableElement);
}
TQDomElement KWDWriter::createLink(TQDomElement paragraph, TQString linkName, TQString hrefName) {
TQDomElement linkElement = _doc->createElement("LINK");
linkElement.setAttribute( "linkName", linkName );
linkElement.setAttribute( "hrefName", hrefName );
TQDomElement format = currentFormat(paragraph,true);
format.setAttribute("id", 4); // change Variable
appendKWordVariable(*_doc, format, linkName, "STRING", 9, linkElement);
return linkElement;
}
TQDomElement KWDWriter::setLayout(TQDomElement paragraph, TQDomElement layout) {
TQDomElement theLayout;
if (layout.isNull())
theLayout=_doc->createElement("LAYOUT");
else
theLayout=layout.cloneNode().toElement();
TQDomElement oldLayout=currentLayout(paragraph);
paragraph.removeChild(oldLayout);
paragraph.appendChild(theLayout);
return theLayout;
}
TQRect getRect(TQDomElement frameset) {
// returns the rect of the first frame.
TQDomElement frame=frameset.elementsByTagName("FRAME").item(0).toElement();
return TQRect(frame.attribute("left").toInt(),
frame.attribute("top").toInt(),
frame.attribute("right").toInt()-frame.attribute("left").toInt(),
frame.attribute("bottom").toInt()-frame.attribute("top").toInt()
);
}
TQDomElement KWDWriter::addParagraph(TQDomElement parent, TQDomElement layoutToClone) {
TQDomElement paragraph=_doc->createElement("PARAGRAPH");
TQDomElement formats=_doc->createElement("FORMATS");
TQDomElement layout;
if (layoutToClone.isNull()) {
layout=_doc->createElement("LAYOUT");
}
else {
layout=layoutToClone.cloneNode().toElement();
}
TQDomElement text=_doc->createElement("TEXT");
TQDomText t=_doc->createTextNode(TQString(""));
text.appendChild(t);
paragraph.appendChild(formats);
paragraph.appendChild(text);
parent.appendChild(paragraph);
paragraph.appendChild(layout);
layoutAttribute(paragraph,"NAME","value","Standard");
return paragraph;
}
TQDomElement KWDWriter::formatAttribute(TQDomElement paragraph, TQString name, TQString attrName, TQString attr) {
kdDebug() << "Entering KWDWriter::formatAttribute" << endl;
TQDomElement lastformat=currentFormat(paragraph,true);
TQDomNodeList qdnl= lastformat.elementsByTagName(name);
if (qdnl.length()) {
TQDomElement el;
el=qdnl.item(0).toElement();
el.setAttribute(attrName,attr);
return el;
} else {
TQDomElement al=_doc->createElement(name);
lastformat.appendChild(al);
al.setAttribute(attrName,attr);
return al;
}
}
TQString KWDWriter::getLayoutAttribute(TQDomElement paragraph, TQString name, TQString attrName) {
TQDomElement currentLayout=paragraph.elementsByTagName("LAYOUT").item(0).toElement();
TQDomNodeList qdnl= currentLayout.elementsByTagName(name);
if (qdnl.length()) {
TQDomElement el=qdnl.item(0).toElement();
return el.attribute(attrName);
}
return TQString();
}
TQDomElement KWDWriter::layoutAttribute(TQDomElement paragraph, TQString name, TQString attrName, TQString attr)
{
kdDebug() << "Entering KWDWriter::layoutAttribute name=" << name << " attrName=" << attrName << " attr=" << attr << endl;
TQDomElement currentLayout=paragraph.elementsByTagName("LAYOUT").item(0).toElement();
TQDomNodeList qdnl= currentLayout.elementsByTagName(name);
if (qdnl.length())
{
TQDomElement el;
el=qdnl.item(0).toElement();
el.setAttribute(attrName,attr);
return el;
}
else
{
TQDomElement al=_doc->createElement(name);
currentLayout.appendChild(al);
al.setAttribute(attrName,attr);
return al;
}
}
void KWDWriter::addText(TQDomElement paragraph, TQString text, int format_id, bool keep_formatting) {
TQDomNode temp=paragraph.elementsByTagName("TEXT").item(0).firstChild();
TQDomText currentText=temp.toText();
if (temp.isNull()) { kdDebug(30503) << "no text" << endl; return; }
TQString oldtext=currentText.data();
int oldLength=oldtext.length();
if (keep_formatting)
{
if (oldLength)
{
++oldLength;
oldtext.append('\n');
}
}
else
{
if (oldLength)
++oldLength; // add new trailing space char
text=text.simplifyWhiteSpace(); // drop all unprintable chars
}
TQString newtext;
if (keep_formatting)
newtext=oldtext + text;
else
{
newtext=oldtext + " " + text;
// strip possible newline at beginning.
while (newtext.left(1)=="\n" || newtext.left(1)==" ") newtext=newtext.right(newtext.length()-1);
}
currentText.setData(newtext);
int newLength=text.length();
TQDomElement lastformat=currentFormat(paragraph,true);
if (lastformat.attribute("id").isEmpty()) // keep old id value, e.g. for LINK URL
lastformat.setAttribute("id",format_id);
lastformat.setAttribute("pos",TQString("%1").arg(oldLength));
lastformat.setAttribute("len",TQString("%1").arg(newLength));
}
TQString KWDWriter::getText(TQDomElement paragraph) {
TQDomNode temp=paragraph.elementsByTagName("TEXT").item(0).firstChild();
TQDomText currentText=temp.toText();
if (temp.isNull()) { kdWarning(30503) << "no text" << endl; }
return currentText.data();
}
TQDomElement KWDWriter::startFormat(TQDomElement paragraph) {
if (paragraph.isNull()) { kdWarning(30503) << "startFormat on empty paragraph" << endl; }
TQDomElement format=_doc->createElement("FORMAT");
paragraph.elementsByTagName("FORMATS").item(0).appendChild(format);
return format;
}
TQDomElement KWDWriter::startFormat(TQDomElement paragraph, TQDomElement formatToClone) {
TQDomElement format=formatToClone.cloneNode().toElement();
if (format.isNull()) { kdWarning(30503) << "startFormat: null format cloned" << endl; }
if (paragraph.isNull()) { kdWarning(30503) << "startFormat on empty paragraph" << endl; }
format.removeAttribute("len");
format.removeAttribute("pos");
format.removeAttribute("id");
for (TQDomElement a=format.firstChild().toElement();!a.isNull();a=a.nextSibling().toElement()) {
if (a.tagName() == "ANCHOR") {
format.removeChild(a);
}
}
paragraph.elementsByTagName("FORMATS").item(0).appendChild(format);
return format;
}
TQDomElement KWDWriter::currentFormat(TQDomElement paragraph, bool start_new_one) {
TQDomElement e=paragraph.elementsByTagName("FORMATS").item(0).lastChild().toElement();
if (e.isNull()) {
// no current format, start a new one
if (start_new_one) return startFormat(paragraph);
else { kdWarning(30503) << "warning: returning null format" << endl; }
}
if (!e.attribute("len").isNull()) {
// current format already has length, clone it.
if (start_new_one) return startFormat(paragraph,e);
}
return e;
}
void KWDWriter::cleanUpParagraph(TQDomElement paragraph) {
TQDomElement e=paragraph.elementsByTagName("FORMATS").item(0).toElement();
if (e.isNull()) { kdWarning(30503) << "cleanup : no valid paragraph" << endl; return; }
for (TQDomElement k=e.firstChild().toElement();!k.isNull();k=k.nextSibling().toElement()) {
if (k.attribute("len",TQString()).isNull()) {
e.removeChild(k);
cleanUpParagraph(paragraph);
return;
}
}
}
TQDomElement KWDWriter::addFrame(TQDomElement frameset, TQRect rect, int runaround, int copy,
int newFrameBehaviour, int runaroundGap
) {
TQDomElement frame = _doc->createElement("FRAME");
frameset.appendChild(frame);
frame.setAttribute("runaround",runaround);
frame.setAttribute("copy",copy);
frame.setAttribute("newFrameBehaviour",newFrameBehaviour);
frame.setAttribute("runaroundGap",runaroundGap);
addRect(frame,rect);
return frame;
}
TQDomElement KWDWriter::docroot() {
return _doc->elementsByTagName("DOC").item(0).toElement();
}
bool KWDWriter::writeDoc() {
TQCString str=_doc->toCString();
kdWarning(30503) << str << endl;
if (!_store->open("root")) {
return false;
} else {
_store->write((const char *)str, str.length());
_store->close();
}
if (!_store->open("documentinfo.xml")) {
kdWarning(30503) << "WARNING: unable to write out doc info. continuing anyway" << endl;
} else {
str=_docinfo->toCString();
_store->write((const char *)str, str.length());
_store->close();
}
return true;
}
TQDomElement KWDWriter::mainFrameset() {
return _mainFrameset;
}
void KWDWriter::addRect(TQDomElement e,TQRect rect) {
e.setAttribute("top",_zoomhandler->pixelYToPt( rect.top()));
e.setAttribute("left",_zoomhandler->pixelXToPt(rect.left()));
e.setAttribute("bottom",_zoomhandler->pixelYToPt(rect.bottom()));
e.setAttribute("right",_zoomhandler->pixelXToPt(rect.right()));
}
KWDWriter::~KWDWriter(){
delete(_zoomhandler);
}