filters

kwdwriter.cpp
1/***************************************************************************
2 kwdwriter.cpp - description
3 -------------------
4 begin : Wed Sep 5 2001
5 copyright : (C) 2001 by Frank Dekervel
6 email : Frank.Dekervel@student.kuleuven.ac.be
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU Lesser General Public License *
13 * as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
16 * *
17 ***************************************************************************/
18
19#include "kwdwriter.h"
20#include <stdlib.h>
21#include "tqrect.h"
22#include <KoTextZoomHandler.h>
23#include <tqpaintdevice.h>
24
25KWDWriter::KWDWriter(KoStore *store){
26 _zoomhandler = new KoTextZoomHandler();
27
28 _store=store;
29 _doc= new TQDomDocument("DOC");
30 _docinfo = new TQDomDocument("document-info");
31
32 _doc->appendChild( _doc->createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
33 _docinfo->appendChild( _docinfo->createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
34
35 TQDomElement infodoc = _docinfo->createElement( "document-info" );
36 _docinfoMain=infodoc;
37 _docinfo->appendChild(infodoc);
38
39 tableNo=1;
40 insidetable = false;
41 TQDomElement kwdoc = _doc->createElement( "DOC" );
42 kwdoc.setAttribute( "editor", "HTML Import Filter" );
43 kwdoc.setAttribute( "mime", "application/x-kword" );
44 _doc->appendChild( kwdoc );
45
46 TQDomElement paper = _doc->createElement( "PAPER" );
47 kwdoc.appendChild( paper );
48 paper.setAttribute( "format", 1 );
49 paper.setAttribute( "width", 595 );
50 paper.setAttribute( "height", 841 );
51 paper.setAttribute( "orientation", 0 );
52 paper.setAttribute( "columns", 1 );
53 paper.setAttribute( "columnspacing", 3 );
54 paper.setAttribute( "hType", 0 );
55 paper.setAttribute( "fType", 0 );
56
57 TQDomElement borders = _doc->createElement( "PAPERBORDERS" );
58 paper.appendChild( borders );
59 borders.setAttribute( "left", 20 );
60 borders.setAttribute( "top", 10 );
61 borders.setAttribute( "right", 10 );
62 borders.setAttribute( "bottom", 10 );
63
64 TQDomElement docattrs = _doc->createElement( "ATTRIBUTES" );
65 kwdoc.appendChild( docattrs );
66 docattrs.setAttribute( "processing", 0 );
67 docattrs.setAttribute( "standardpage", 1 );
68 docattrs.setAttribute( "hasHeader", 0 );
69 docattrs.setAttribute( "hasFooter", 0 );
70 //docattrs.setAttribute( "unit", "mm" ); // use KWord default instead
71
72 TQDomElement framesets = _doc->createElement("FRAMESETS");
73 kwdoc.appendChild(framesets);
74 TQDomElement rootframeset = addFrameSet(framesets);
75 _mainFrameset=rootframeset;
76 TQDomElement mainframe= addFrame(rootframeset,TQRect(28,28,539,757));
77
78 TQDomElement styles=_doc->createElement("STYLES");
79 kwdoc.appendChild(styles);
80
81 TQDomElement standard=_doc->createElement("STYLE");
82 styles.appendChild(standard);
83
84 TQDomElement tmp;
85 tmp=_doc->createElement("NAME");
86 tmp.setAttribute("value","Standard");
87 standard.appendChild(tmp);
88
89 tmp=_doc->createElement("FOLLOWING");
90 tmp.setAttribute("name","Standard");
91 standard.appendChild(tmp);
92 TQDomElement fmt;
93
94 fmt=_doc->createElement("FORMAT");
95 fmt.setAttribute("id","1");
96 standard.appendChild(fmt);
97
98 tmp=_doc->createElement("SIZE");
99 tmp.setAttribute("value","12"); // HACK !
100 fmt.appendChild(tmp);
101
102
103#define HEADINGSTYLE(a,b) standard=_doc->createElement("STYLE");\
104 styles.appendChild(standard);\
105 tmp=_doc->createElement("NAME");\
106 tmp.setAttribute("value",#a);\
107 standard.appendChild(tmp);\
108 tmp=_doc->createElement("FOLLOWING");\
109 tmp.setAttribute("name","Standard");\
110 standard.appendChild(tmp);\
111 fmt=_doc->createElement("FORMAT");\
112 fmt.setAttribute("id","1");\
113 standard.appendChild(fmt);\
114 tmp=_doc->createElement("SIZE");\
115 tmp.setAttribute("value",#b);\
116 fmt.appendChild(tmp);
117
118HEADINGSTYLE(h1,20);
119HEADINGSTYLE(h2,18);
120HEADINGSTYLE(h3,16);
121HEADINGSTYLE(h4,14);
122HEADINGSTYLE(h5,10);
123HEADINGSTYLE(h6,8);
124
125
126}
127
128bool KWDWriter::isInTable() const {
129 return insidetable;
130}
131
132int KWDWriter::createTable() {
133 insidetable = true;
134 return tableNo++;
135}
136
137void KWDWriter::createDocInfo(TQString author, TQString title) {
138 TQDomElement authorTag=_docinfo->createElement("author");
139 TQDomElement aboutTag=_docinfo->createElement("about");
140 TQDomElement fullNameTag=_docinfo->createElement("full-name");
141 TQDomText titleText=_docinfo->createTextNode(title);
142 TQDomText authorText=_docinfo->createTextNode(author);
143 fullNameTag.appendChild(authorText);
144 authorTag.appendChild(fullNameTag);
145 TQDomElement titleTag=_docinfo->createElement("title");
146 titleTag.appendChild(titleText);
147 aboutTag.appendChild(titleTag);
148 _docinfoMain.appendChild(authorTag);
149 _docinfoMain.appendChild(aboutTag);
150}
151
152
153void KWDWriter::createInline(TQDomElement paragraph, TQDomElement toInline) {
154 if (toInline.tagName() == "FRAMESET") {
155 formatAttribute(paragraph,"ANCHOR","type","frameset");
156 // fixme: support other kinds of inlines.
157 }
158 if (!toInline.attribute("grpMgr").isEmpty()) {
159 formatAttribute(paragraph,"ANCHOR","instance",toInline.attribute("grpMgr"));
160 }
161 addText(paragraph,"#",6); // the anchor.
162}
163
164
165TQDomElement KWDWriter::currentLayout(TQDomElement paragraph) {
166 return paragraph.elementsByTagName("LAYOUT").item(0).toElement();
167}
168
169
170
171TQDomElement KWDWriter::createTableCell(int tableno, int nrow,
172 int ncol, int colspan, TQRect rect) {
173 TQDomElement parent=docroot().elementsByTagName("FRAMESETS").item(0).toElement();
174
175 TQDomElement fs=addFrameSet(parent,1,0,
176 TQString("Table %1 - %2,%3").arg(tableno).arg(nrow).arg(ncol),
177 1);
178 fs.setAttribute("grpMgr",TQString("Table %1").arg(tableno));
179 fs.setAttribute("row",nrow);
180 fs.setAttribute("col",ncol);
181 fs.setAttribute("cols",colspan); // FIXME do colspan in finishTable
182 // so we don't have to give it as an argument
183 fs.setAttribute("rows",1); // FIXME support rowspan ?
184 addFrame(fs,rect);
185 return fs;
186}
187
188TQDomElement KWDWriter::fetchTableCell(int tableno, int rowno, int colno) {
189 TQDomNodeList e=docroot().elementsByTagName("FRAMESET");
190 for (unsigned int i=0;i<e.count();i++) {
191 TQDomElement k=e.item(i).toElement();
192 if (k.attribute("grpMgr") == TQString("Table %1").arg(tableno))
193 if (k.attribute("row") == TQString("%1").arg(rowno))
194 if (k.attribute("col") == TQString("%1").arg(colno))
195 return k;
196 }
197 TQDomElement dummy;
198 return dummy;
199}
200
201#define MAX(x,y) ((x > y) ? x : y)
202#define MIN(x,y) ((x < y) ? x : y)
203
204void KWDWriter::finishTable(int tableno) {
205 finishTable(tableno,TQRect(-1,-1,-1,-1));
206}
207
208
209void KWDWriter::createHR(TQDomElement paragraph, int width) {
210 layoutAttribute(paragraph,"BOTTOMBORDER","width",TQString("%1").arg(width));
211}
212
213void KWDWriter::finishTable(int tableno,TQRect rect) {
214 int ncols=0;
215 int nrows=0;
216 insidetable = false;
217
218 int x=rect.x();
219 int y=rect.y();
220 int w=rect.width();
221 int h=rect.height();
222
223 TQDomNodeList nl=docroot().elementsByTagName("FRAMESET");
224 //FIXME calculate nrows and stuff.
225 //and add empty cells for missing ones.
226
227 // first, see how big the table is (cols & rows)
228 for (unsigned i=0;i<nl.count();i++) {
229 TQDomElement k=nl.item(i).toElement();
230 if (k.attribute("grpMgr") == TQString("Table %1").arg(tableno)) {
231 ncols=MAX(ncols,k.attribute("col").toInt()+1);
232 nrows=MAX(nrows,k.attribute("row").toInt()+1);
233 }
234 }
235 int curcol=0;
236 int currow=0;
237 int currow_inc=0;
238 if (ncols == 0) ncols=1; // FIXME (floating point division by zero)
239 if (nrows == 0) nrows=1;
240
241 int step_x=(w-x)/ncols;
242 int step_y=(h-y)/nrows;
243
244
245 // then, let's create the missing cells and resize them if needed.
246 bool must_resize=false;
247 if (x>0) must_resize=true;
248 while (currow < nrows) {
249 curcol=0;
250 while (curcol < ncols) {
251 TQDomElement e=fetchTableCell(tableno,currow,curcol);
252 if (e.isNull()) {
253 // a missing cell !
254 kdDebug(30503) << TQString("creating %1 %2").arg(currow).arg(curcol).latin1() << endl;
255 createTableCell(tableno,currow,curcol,1,
256 TQRect(x+step_x*curcol,y+step_y*currow,step_x,step_y)
257 );
258 // fixme: what to do if we don't have to resize ?
259 }
260
261 // resize this one FIXME optimize this routine
262 if (must_resize == true) {
263 TQDomElement ee=e.firstChild().toElement(); // the frame in the frameset
264 int cs=e.attribute("cols").toInt();
265 int rs=e.attribute("rows").toInt();
266 kdDebug(30503) << "resizing" << endl;
267 addRect(ee,TQRect(x+step_x*curcol,0,step_x*cs,step_y*rs));
268 }
269 if (curcol==0) currow_inc=e.attribute("rows").toInt();
270 curcol +=e.attribute("cols").toInt();
271
272
273 }
274 currow+=currow_inc;
275 }
276
277
278}
279
280
281TQDomElement KWDWriter::addFrameSet(TQDomElement parent, int frametype,
282 int frameinfo, TQString name, int visible) {
283
284 TQDomElement frameset=_doc->createElement("FRAMESET");
285 parent.appendChild(frameset);
286 frameset.setAttribute("frameType",frametype);
287 frameset.setAttribute("frameInfo",frameinfo);
288
289 if (!name.isNull())
290 frameset.setAttribute("name",name);
291 else
292 frameset.setAttribute("name","Text-frameset 1");
293
294 frameset.setAttribute("visible",visible);
295 return frameset;
296}
297
298TQDomElement KWDWriter::addParagraph(TQDomElement parent) {
299 TQDomElement k;
300 return addParagraph(parent,k);
301}
302
303void KWDWriter::appendKWordVariable(TQDomDocument& doc, TQDomElement& format,
304 const TQString& text, const TQString& key, int type, TQDomElement& child) {
305
306 TQDomElement variableElement ( doc.createElement("VARIABLE") );
307
308 TQDomElement typeElement ( doc.createElement("TYPE") );
309 typeElement.setAttribute("key",key);
310 typeElement.setAttribute("type",type);
311 typeElement.setAttribute("text",text);
312 variableElement.appendChild(typeElement); //Append to <VARIABLE>
313
314 variableElement.appendChild(child); //Append to <VARIABLE>
315
316 format.appendChild(variableElement);
317}
318
319TQDomElement KWDWriter::createLink(TQDomElement paragraph, TQString linkName, TQString hrefName) {
320 TQDomElement linkElement = _doc->createElement("LINK");
321 linkElement.setAttribute( "linkName", linkName );
322 linkElement.setAttribute( "hrefName", hrefName );
323 TQDomElement format = currentFormat(paragraph,true);
324 format.setAttribute("id", 4); // change Variable
325 appendKWordVariable(*_doc, format, linkName, "STRING", 9, linkElement);
326
327 return linkElement;
328}
329
330
331TQDomElement KWDWriter::setLayout(TQDomElement paragraph, TQDomElement layout) {
332 TQDomElement theLayout;
333 if (layout.isNull())
334 theLayout=_doc->createElement("LAYOUT");
335 else
336 theLayout=layout.cloneNode().toElement();
337 TQDomElement oldLayout=currentLayout(paragraph);
338 paragraph.removeChild(oldLayout);
339 paragraph.appendChild(theLayout);
340 return theLayout;
341}
342
343
344TQRect getRect(TQDomElement frameset) {
345 // returns the rect of the first frame.
346 TQDomElement frame=frameset.elementsByTagName("FRAME").item(0).toElement();
347 return TQRect(frame.attribute("left").toInt(),
348 frame.attribute("top").toInt(),
349 frame.attribute("right").toInt()-frame.attribute("left").toInt(),
350 frame.attribute("bottom").toInt()-frame.attribute("top").toInt()
351 );
352
353}
354
355
356TQDomElement KWDWriter::addParagraph(TQDomElement parent, TQDomElement layoutToClone) {
357
358 TQDomElement paragraph=_doc->createElement("PARAGRAPH");
359 TQDomElement formats=_doc->createElement("FORMATS");
360 TQDomElement layout;
361 if (layoutToClone.isNull()) {
362 layout=_doc->createElement("LAYOUT");
363 }
364 else {
365 layout=layoutToClone.cloneNode().toElement();
366 }
367 TQDomElement text=_doc->createElement("TEXT");
368 TQDomText t=_doc->createTextNode(TQString(""));
369 text.appendChild(t);
370 paragraph.appendChild(formats);
371 paragraph.appendChild(text);
372 parent.appendChild(paragraph);
373 paragraph.appendChild(layout);
374 layoutAttribute(paragraph,"NAME","value","Standard");
375 return paragraph;
376}
377
378TQDomElement KWDWriter::formatAttribute(TQDomElement paragraph, TQString name, TQString attrName, TQString attr) {
379 kdDebug() << "Entering KWDWriter::formatAttribute" << endl;
380 TQDomElement lastformat=currentFormat(paragraph,true);
381 TQDomNodeList qdnl= lastformat.elementsByTagName(name);
382 if (qdnl.length()) {
383 TQDomElement el;
384 el=qdnl.item(0).toElement();
385 el.setAttribute(attrName,attr);
386 return el;
387 } else {
388 TQDomElement al=_doc->createElement(name);
389 lastformat.appendChild(al);
390 al.setAttribute(attrName,attr);
391 return al;
392 }
393
394}
395
396TQString KWDWriter::getLayoutAttribute(TQDomElement paragraph, TQString name, TQString attrName) {
397 TQDomElement currentLayout=paragraph.elementsByTagName("LAYOUT").item(0).toElement();
398 TQDomNodeList qdnl= currentLayout.elementsByTagName(name);
399 if (qdnl.length()) {
400 TQDomElement el=qdnl.item(0).toElement();
401 return el.attribute(attrName);
402 }
403 return TQString();
404}
405
406TQDomElement KWDWriter::layoutAttribute(TQDomElement paragraph, TQString name, TQString attrName, TQString attr)
407{
408 kdDebug() << "Entering KWDWriter::layoutAttribute name=" << name << " attrName=" << attrName << " attr=" << attr << endl;
409 TQDomElement currentLayout=paragraph.elementsByTagName("LAYOUT").item(0).toElement();
410 TQDomNodeList qdnl= currentLayout.elementsByTagName(name);
411
412 if (qdnl.length())
413 {
414 TQDomElement el;
415 el=qdnl.item(0).toElement();
416 el.setAttribute(attrName,attr);
417 return el;
418 }
419 else
420 {
421 TQDomElement al=_doc->createElement(name);
422 currentLayout.appendChild(al);
423 al.setAttribute(attrName,attr);
424 return al;
425 }
426}
427
428void KWDWriter::addText(TQDomElement paragraph, TQString text, int format_id, bool keep_formatting) {
429 TQDomNode temp=paragraph.elementsByTagName("TEXT").item(0).firstChild();
430 TQDomText currentText=temp.toText();
431 if (temp.isNull()) { kdDebug(30503) << "no text" << endl; return; }
432 TQString oldtext=currentText.data();
433 int oldLength=oldtext.length();
434 if (keep_formatting)
435 {
436 if (oldLength)
437 {
438 ++oldLength;
439 oldtext.append('\n');
440 }
441 }
442 else
443 {
444 if (oldLength)
445 ++oldLength; // add new trailing space char
446 text=text.simplifyWhiteSpace(); // drop all unprintable chars
447 }
448 TQString newtext;
449 if (keep_formatting)
450 newtext=oldtext + text;
451 else
452 {
453 newtext=oldtext + " " + text;
454 // strip possible newline at beginning.
455 while (newtext.left(1)=="\n" || newtext.left(1)==" ") newtext=newtext.right(newtext.length()-1);
456
457 }
458 currentText.setData(newtext);
459 int newLength=text.length();
460 TQDomElement lastformat=currentFormat(paragraph,true);
461 if (lastformat.attribute("id").isEmpty()) // keep old id value, e.g. for LINK URL
462 lastformat.setAttribute("id",format_id);
463 lastformat.setAttribute("pos",TQString("%1").arg(oldLength));
464 lastformat.setAttribute("len",TQString("%1").arg(newLength));
465}
466
467TQString KWDWriter::getText(TQDomElement paragraph) {
468 TQDomNode temp=paragraph.elementsByTagName("TEXT").item(0).firstChild();
469 TQDomText currentText=temp.toText();
470 if (temp.isNull()) { kdWarning(30503) << "no text" << endl; }
471 return currentText.data();
472}
473
474
475TQDomElement KWDWriter::startFormat(TQDomElement paragraph) {
476 if (paragraph.isNull()) { kdWarning(30503) << "startFormat on empty paragraph" << endl; }
477 TQDomElement format=_doc->createElement("FORMAT");
478 paragraph.elementsByTagName("FORMATS").item(0).appendChild(format);
479 return format;
480}
481
482
483TQDomElement KWDWriter::startFormat(TQDomElement paragraph, TQDomElement formatToClone) {
484 TQDomElement format=formatToClone.cloneNode().toElement();
485 if (format.isNull()) { kdWarning(30503) << "startFormat: null format cloned" << endl; }
486 if (paragraph.isNull()) { kdWarning(30503) << "startFormat on empty paragraph" << endl; }
487
488 format.removeAttribute("len");
489 format.removeAttribute("pos");
490 format.removeAttribute("id");
491 for (TQDomElement a=format.firstChild().toElement();!a.isNull();a=a.nextSibling().toElement()) {
492 if (a.tagName() == "ANCHOR") {
493 format.removeChild(a);
494 }
495 }
496 paragraph.elementsByTagName("FORMATS").item(0).appendChild(format);
497 return format;
498}
499
500TQDomElement KWDWriter::currentFormat(TQDomElement paragraph, bool start_new_one) {
501
502 TQDomElement e=paragraph.elementsByTagName("FORMATS").item(0).lastChild().toElement();
503 if (e.isNull()) {
504 // no current format, start a new one
505 if (start_new_one) return startFormat(paragraph);
506 else { kdWarning(30503) << "warning: returning null format" << endl; }
507 }
508 if (!e.attribute("len").isNull()) {
509 // current format already has length, clone it.
510 if (start_new_one) return startFormat(paragraph,e);
511 }
512 return e;
513}
514
515
516void KWDWriter::cleanUpParagraph(TQDomElement paragraph) {
517 TQDomElement e=paragraph.elementsByTagName("FORMATS").item(0).toElement();
518 if (e.isNull()) { kdWarning(30503) << "cleanup : no valid paragraph" << endl; return; }
519 for (TQDomElement k=e.firstChild().toElement();!k.isNull();k=k.nextSibling().toElement()) {
520 if (k.attribute("len",TQString()).isNull()) {
521 e.removeChild(k);
522 cleanUpParagraph(paragraph);
523 return;
524 }
525 }
526}
527
528
529TQDomElement KWDWriter::addFrame(TQDomElement frameset, TQRect rect, int runaround, int copy,
530 int newFrameBehaviour, int runaroundGap
531 ) {
532 TQDomElement frame = _doc->createElement("FRAME");
533 frameset.appendChild(frame);
534 frame.setAttribute("runaround",runaround);
535 frame.setAttribute("copy",copy);
536 frame.setAttribute("newFrameBehaviour",newFrameBehaviour);
537 frame.setAttribute("runaroundGap",runaroundGap);
538 addRect(frame,rect);
539 return frame;
540}
541
542TQDomElement KWDWriter::docroot() {
543 return _doc->elementsByTagName("DOC").item(0).toElement();
544}
545
546bool KWDWriter::writeDoc() {
547 TQCString str=_doc->toCString();
548 kdWarning(30503) << str << endl;
549
550 if (!_store->open("root")) {
551 return false;
552 } else {
553 _store->write((const char *)str, str.length());
554 _store->close();
555 }
556
557 if (!_store->open("documentinfo.xml")) {
558 kdWarning(30503) << "WARNING: unable to write out doc info. continuing anyway" << endl;
559 } else {
560 str=_docinfo->toCString();
561 _store->write((const char *)str, str.length());
562 _store->close();
563 }
564
565 return true;
566}
567
568
569TQDomElement KWDWriter::mainFrameset() {
570 return _mainFrameset;
571}
572
573
574void KWDWriter::addRect(TQDomElement e,TQRect rect) {
575 e.setAttribute("top",_zoomhandler->pixelYToPt( rect.top()));
576 e.setAttribute("left",_zoomhandler->pixelXToPt(rect.left()));
577 e.setAttribute("bottom",_zoomhandler->pixelYToPt(rect.bottom()));
578 e.setAttribute("right",_zoomhandler->pixelXToPt(rect.right()));
579}
580
581
582
583
584
585KWDWriter::~KWDWriter(){
586 delete(_zoomhandler);
587}