filters

kwdwriter.cpp

00001 /***************************************************************************
00002                           kwdwriter.cpp  -  description
00003                              -------------------
00004     begin                : Wed Sep 5 2001
00005     copyright            : (C) 2001 by Frank Dekervel
00006     email                : Frank.Dekervel@student.kuleuven.ac.be
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU Lesser General Public License           *
00013  *   as published by                                                       *
00014  *   the Free Software Foundation; either version 2 of the License, or     *
00015  *   (at your option) any later version.                                   *
00016  *                                                                         *
00017  ***************************************************************************/
00018 
00019 #include "kwdwriter.h"
00020 #include <stdlib.h>
00021 #include "qrect.h"
00022 #include <KoTextZoomHandler.h>
00023 #include <qpaintdevice.h>
00024 
00025 KWDWriter::KWDWriter(KoStore *store){
00026     _zoomhandler = new KoTextZoomHandler();
00027 
00028     _store=store;
00029     _doc= new QDomDocument("DOC");
00030     _docinfo = new QDomDocument("document-info");
00031 
00032     _doc->appendChild( _doc->createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
00033     _docinfo->appendChild( _docinfo->createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
00034 
00035     QDomElement infodoc = _docinfo->createElement( "document-info" );
00036     _docinfoMain=infodoc;
00037     _docinfo->appendChild(infodoc);
00038 
00039     tableNo=1;
00040     insidetable = false;
00041     QDomElement kwdoc = _doc->createElement( "DOC" );
00042     kwdoc.setAttribute( "editor", "HTML Import Filter" );
00043     kwdoc.setAttribute( "mime", "application/x-kword" );
00044     _doc->appendChild( kwdoc );
00045 
00046     QDomElement paper = _doc->createElement( "PAPER" );
00047     kwdoc.appendChild( paper );
00048     paper.setAttribute( "format", 1 );
00049     paper.setAttribute( "width", 595 );
00050     paper.setAttribute( "height", 841 );
00051     paper.setAttribute( "orientation", 0 );
00052     paper.setAttribute( "columns", 1 );
00053     paper.setAttribute( "columnspacing", 3 );
00054     paper.setAttribute( "hType", 0 );
00055     paper.setAttribute( "fType", 0 );
00056 
00057     QDomElement borders = _doc->createElement( "PAPERBORDERS" );
00058     paper.appendChild( borders );
00059     borders.setAttribute( "left", 20 );
00060     borders.setAttribute( "top", 10 );
00061     borders.setAttribute( "right", 10 );
00062     borders.setAttribute( "bottom", 10 );
00063 
00064     QDomElement docattrs = _doc->createElement( "ATTRIBUTES" );
00065     kwdoc.appendChild( docattrs );
00066     docattrs.setAttribute( "processing", 0 );
00067     docattrs.setAttribute( "standardpage", 1 );
00068     docattrs.setAttribute( "hasHeader", 0 );
00069     docattrs.setAttribute( "hasFooter", 0 );
00070     //docattrs.setAttribute( "unit", "mm" ); // use KWord default instead
00071 
00072     QDomElement framesets = _doc->createElement("FRAMESETS");
00073     kwdoc.appendChild(framesets);
00074     QDomElement rootframeset = addFrameSet(framesets);
00075     _mainFrameset=rootframeset;
00076     QDomElement mainframe= addFrame(rootframeset,QRect(28,28,539,757));
00077 
00078     QDomElement styles=_doc->createElement("STYLES");
00079     kwdoc.appendChild(styles);
00080 
00081     QDomElement standard=_doc->createElement("STYLE");
00082     styles.appendChild(standard);
00083 
00084     QDomElement  tmp;
00085         tmp=_doc->createElement("NAME");
00086         tmp.setAttribute("value","Standard");
00087         standard.appendChild(tmp);
00088 
00089         tmp=_doc->createElement("FOLLOWING");
00090         tmp.setAttribute("name","Standard");
00091         standard.appendChild(tmp);
00092         QDomElement fmt;
00093 
00094         fmt=_doc->createElement("FORMAT");
00095         fmt.setAttribute("id","1");
00096         standard.appendChild(fmt);
00097 
00098         tmp=_doc->createElement("SIZE");
00099         tmp.setAttribute("value","12"); // HACK !
00100         fmt.appendChild(tmp);
00101 
00102 
00103 #define HEADINGSTYLE(a,b)     standard=_doc->createElement("STYLE");\
00104     styles.appendChild(standard);\
00105         tmp=_doc->createElement("NAME");\
00106         tmp.setAttribute("value",#a);\
00107         standard.appendChild(tmp);\
00108         tmp=_doc->createElement("FOLLOWING");\
00109         tmp.setAttribute("name","Standard");\
00110         standard.appendChild(tmp);\
00111         fmt=_doc->createElement("FORMAT");\
00112         fmt.setAttribute("id","1");\
00113         standard.appendChild(fmt);\
00114         tmp=_doc->createElement("SIZE");\
00115         tmp.setAttribute("value",#b);\
00116         fmt.appendChild(tmp);
00117 
00118 HEADINGSTYLE(h1,20);
00119 HEADINGSTYLE(h2,18);
00120 HEADINGSTYLE(h3,16);
00121 HEADINGSTYLE(h4,14);
00122 HEADINGSTYLE(h5,10);
00123 HEADINGSTYLE(h6,8);
00124 
00125 
00126 }
00127 
00128 bool KWDWriter::isInTable() const {
00129     return insidetable;
00130 }
00131 
00132 int KWDWriter::createTable() {
00133  insidetable = true;
00134  return tableNo++;
00135 }
00136 
00137 void KWDWriter::createDocInfo(QString author, QString title) {
00138     QDomElement authorTag=_docinfo->createElement("author");
00139     QDomElement aboutTag=_docinfo->createElement("about");
00140     QDomElement fullNameTag=_docinfo->createElement("full-name");
00141     QDomText titleText=_docinfo->createTextNode(title);
00142     QDomText authorText=_docinfo->createTextNode(author);
00143     fullNameTag.appendChild(authorText);
00144     authorTag.appendChild(fullNameTag);
00145     QDomElement titleTag=_docinfo->createElement("title");
00146     titleTag.appendChild(titleText);
00147     aboutTag.appendChild(titleTag);
00148     _docinfoMain.appendChild(authorTag);
00149     _docinfoMain.appendChild(aboutTag);
00150 }
00151 
00152 
00153 void KWDWriter::createInline(QDomElement paragraph, QDomElement toInline) {
00154  if (toInline.tagName() == "FRAMESET") {
00155      formatAttribute(paragraph,"ANCHOR","type","frameset");
00156      // fixme: support other kinds of inlines.
00157  }
00158  if (!toInline.attribute("grpMgr").isEmpty()) {
00159      formatAttribute(paragraph,"ANCHOR","instance",toInline.attribute("grpMgr"));
00160  }
00161  addText(paragraph,"#",6); // the anchor.
00162 }
00163 
00164 
00165 QDomElement KWDWriter::currentLayout(QDomElement paragraph) {
00166     return paragraph.elementsByTagName("LAYOUT").item(0).toElement();
00167 }
00168 
00169 
00170 
00171 QDomElement KWDWriter::createTableCell(int tableno, int nrow,
00172                 int ncol, int colspan, QRect rect) {
00173     QDomElement parent=docroot().elementsByTagName("FRAMESETS").item(0).toElement();
00174 
00175     QDomElement fs=addFrameSet(parent,1,0,
00176             QString("Table %1 - %2,%3").arg(tableno).arg(nrow).arg(ncol),
00177             1);
00178     fs.setAttribute("grpMgr",QString("Table %1").arg(tableno));
00179     fs.setAttribute("row",nrow);
00180     fs.setAttribute("col",ncol);
00181     fs.setAttribute("cols",colspan); // FIXME do colspan in finishTable
00182                      // so we don't have to give it as an argument
00183     fs.setAttribute("rows",1);  // FIXME support rowspan ?
00184     addFrame(fs,rect);
00185     return fs;
00186 }
00187 
00188 QDomElement KWDWriter::fetchTableCell(int tableno, int rowno, int colno) {
00189     QDomNodeList e=docroot().elementsByTagName("FRAMESET");
00190     for (unsigned int i=0;i<e.count();i++) {
00191          QDomElement k=e.item(i).toElement();
00192          if (k.attribute("grpMgr") == QString("Table %1").arg(tableno))
00193              if (k.attribute("row") == QString("%1").arg(rowno))
00194                 if (k.attribute("col") == QString("%1").arg(colno))
00195                     return k;
00196     }
00197     QDomElement dummy;
00198     return dummy;
00199 }
00200 
00201 #define MAX(x,y) ((x > y) ? x : y)
00202 #define MIN(x,y) ((x < y) ? x : y)
00203 
00204 void KWDWriter::finishTable(int tableno) {
00205     finishTable(tableno,QRect(-1,-1,-1,-1));
00206 }
00207 
00208 
00209 void KWDWriter::createHR(QDomElement paragraph, int width) {
00210     layoutAttribute(paragraph,"BOTTOMBORDER","width",QString("%1").arg(width));
00211 }
00212 
00213 void KWDWriter::finishTable(int tableno,QRect rect) {
00214     int ncols=0;
00215     int nrows=0;
00216     insidetable = false;
00217 
00218     int x=rect.x();
00219     int y=rect.y();
00220     int w=rect.width();
00221     int h=rect.height();
00222 
00223     QDomNodeList nl=docroot().elementsByTagName("FRAMESET");
00224        //FIXME calculate nrows and stuff.
00225        //and add empty cells for missing ones.
00226 
00227     // first, see how big the table is (cols & rows)
00228     for (unsigned i=0;i<nl.count();i++) {
00229         QDomElement k=nl.item(i).toElement();
00230             if (k.attribute("grpMgr") == QString("Table %1").arg(tableno)) {
00231               ncols=MAX(ncols,k.attribute("col").toInt()+1);
00232               nrows=MAX(nrows,k.attribute("row").toInt()+1);            
00233             }
00234     }
00235     int curcol=0;
00236     int currow=0;
00237     int currow_inc=0;
00238     if (ncols == 0) ncols=1; // FIXME (floating point division by zero)
00239     if (nrows == 0) nrows=1;
00240     
00241     int step_x=(w-x)/ncols;
00242     int step_y=(h-y)/nrows;
00243     
00244 
00245     // then, let's create the missing cells and resize them if needed.
00246     bool must_resize=false;
00247     if (x>0) must_resize=true;
00248     while (currow < nrows) {
00249        curcol=0;
00250        while (curcol < ncols) {
00251           QDomElement e=fetchTableCell(tableno,currow,curcol);
00252           if (e.isNull()) {
00253                   // a missing cell !
00254                   kdDebug(30503) << QString("creating %1 %2").arg(currow).arg(curcol).latin1() << endl;
00255                   createTableCell(tableno,currow,curcol,1,
00256                         QRect(x+step_x*curcol,y+step_y*currow,step_x,step_y)
00257                 );
00258                   // fixme: what to do if we don't have to resize ?
00259           }
00260 
00261           // resize this one FIXME optimize this routine
00262           if (must_resize == true) {
00263           QDomElement ee=e.firstChild().toElement(); // the frame in the frameset
00264               int cs=e.attribute("cols").toInt();
00265               int rs=e.attribute("rows").toInt();
00266               kdDebug(30503) << "resizing" << endl;
00267               addRect(ee,QRect(x+step_x*curcol,0,step_x*cs,step_y*rs));
00268           }
00269           if (curcol==0) currow_inc=e.attribute("rows").toInt();
00270           curcol +=e.attribute("cols").toInt();
00271 
00272             
00273        }
00274        currow+=currow_inc;
00275     }
00276     
00277     
00278 }
00279 
00280 
00281 QDomElement KWDWriter::addFrameSet(QDomElement parent, int frametype,
00282                    int frameinfo, QString name, int visible) {
00283 
00284     QDomElement frameset=_doc->createElement("FRAMESET");
00285     parent.appendChild(frameset);
00286     frameset.setAttribute("frameType",frametype);
00287     frameset.setAttribute("frameInfo",frameinfo);
00288 
00289     if (!name.isNull())
00290         frameset.setAttribute("name",name);
00291     else
00292         frameset.setAttribute("name","Text-frameset 1");
00293 
00294     frameset.setAttribute("visible",visible);
00295     return frameset;
00296 }
00297 
00298 QDomElement KWDWriter::addParagraph(QDomElement parent) {
00299     QDomElement k;
00300     return addParagraph(parent,k);
00301 }
00302 
00303 void KWDWriter::appendKWordVariable(QDomDocument& doc, QDomElement& format, 
00304     const QString& text, const QString& key, int type, QDomElement& child) {
00305 
00306     QDomElement variableElement ( doc.createElement("VARIABLE") );
00307 
00308     QDomElement typeElement ( doc.createElement("TYPE") );
00309     typeElement.setAttribute("key",key);
00310     typeElement.setAttribute("type",type);
00311     typeElement.setAttribute("text",text);
00312     variableElement.appendChild(typeElement); //Append to <VARIABLE>
00313 
00314     variableElement.appendChild(child); //Append to <VARIABLE>
00315 
00316     format.appendChild(variableElement);
00317 }
00318 
00319 QDomElement KWDWriter::createLink(QDomElement paragraph, QString linkName, QString hrefName) {
00320     QDomElement linkElement = _doc->createElement("LINK");
00321     linkElement.setAttribute( "linkName", linkName );
00322     linkElement.setAttribute( "hrefName", hrefName );
00323     QDomElement format = currentFormat(paragraph,true);
00324     format.setAttribute("id", 4); // change Variable
00325         appendKWordVariable(*_doc, format, linkName, "STRING", 9, linkElement);
00326 
00327     return linkElement;
00328 }
00329 
00330 
00331 QDomElement KWDWriter::setLayout(QDomElement paragraph, QDomElement layout) {
00332     QDomElement theLayout;
00333     if (layout.isNull())
00334         theLayout=_doc->createElement("LAYOUT");
00335     else
00336         theLayout=layout.cloneNode().toElement();
00337     QDomElement oldLayout=currentLayout(paragraph);
00338     paragraph.removeChild(oldLayout);
00339     paragraph.appendChild(theLayout);
00340     return theLayout;
00341 }
00342 
00343 
00344 QRect getRect(QDomElement frameset) {
00345     // returns the rect of the first frame.
00346     QDomElement frame=frameset.elementsByTagName("FRAME").item(0).toElement();
00347     return QRect(frame.attribute("left").toInt(),
00348              frame.attribute("top").toInt(),
00349              frame.attribute("right").toInt()-frame.attribute("left").toInt(),
00350              frame.attribute("bottom").toInt()-frame.attribute("top").toInt()
00351              );
00352 
00353 }
00354 
00355 
00356 QDomElement KWDWriter::addParagraph(QDomElement parent, QDomElement layoutToClone) {
00357 
00358     QDomElement paragraph=_doc->createElement("PARAGRAPH");
00359     QDomElement formats=_doc->createElement("FORMATS");
00360     QDomElement layout;
00361     if (layoutToClone.isNull()) {
00362         layout=_doc->createElement("LAYOUT");
00363     }
00364     else {
00365         layout=layoutToClone.cloneNode().toElement();
00366     }
00367     QDomElement text=_doc->createElement("TEXT");
00368     QDomText t=_doc->createTextNode(QString(""));
00369     text.appendChild(t);
00370     paragraph.appendChild(formats);
00371     paragraph.appendChild(text);
00372     parent.appendChild(paragraph);
00373     paragraph.appendChild(layout);
00374     layoutAttribute(paragraph,"NAME","value","Standard");
00375     return paragraph;
00376 }
00377 
00378 QDomElement KWDWriter::formatAttribute(QDomElement paragraph, QString name, QString attrName, QString attr) {
00379     QDomElement lastformat=currentFormat(paragraph,true);
00380     QDomNodeList qdnl= lastformat.elementsByTagName(name);
00381     if (qdnl.length()) {
00382       QDomElement el;
00383       el=qdnl.item(0).toElement();
00384       el.setAttribute(attrName,attr);
00385       return el;
00386     } else {
00387       QDomElement al=_doc->createElement(name);
00388       lastformat.appendChild(al);
00389       al.setAttribute(attrName,attr);
00390       return al;
00391     }
00392 
00393 }
00394 
00395 QString KWDWriter::getLayoutAttribute(QDomElement paragraph, QString name, QString attrName) {
00396     QDomElement currentLayout=paragraph.elementsByTagName("LAYOUT").item(0).toElement();
00397     QDomNodeList qdnl= currentLayout.elementsByTagName(name);
00398     if (qdnl.length()) {
00399       QDomElement el=qdnl.item(0).toElement();
00400       return el.attribute(attrName);
00401     }
00402     return QString::null;
00403 }
00404 
00405 QDomElement KWDWriter::layoutAttribute(QDomElement paragraph, QString name, QString attrName, QString attr) {
00406     QDomElement currentLayout=paragraph.elementsByTagName("LAYOUT").item(0).toElement();
00407     QDomNodeList qdnl= currentLayout.elementsByTagName(name);
00408 
00409     if (qdnl.length()) {
00410       QDomElement el;
00411       el=qdnl.item(0).toElement();
00412       el.setAttribute(attrName,attr);
00413       return el;
00414     } else {
00415       QDomElement al=_doc->createElement(name);
00416       currentLayout.appendChild(al);
00417       al.setAttribute(attrName,attr);
00418       return al;
00419     }
00420 }
00421 
00422 void KWDWriter::addText(QDomElement paragraph, QString text, int format_id, bool keep_formatting) {
00423     QDomNode temp=paragraph.elementsByTagName("TEXT").item(0).firstChild();
00424     QDomText currentText=temp.toText();
00425     if (temp.isNull()) { kdDebug(30503) << "no text" << endl; return; }
00426     QString oldtext=currentText.data();
00427     int oldLength=oldtext.length();
00428     if (keep_formatting) {
00429         if (oldLength) {
00430             ++oldLength;
00431             oldtext.append('\n');
00432         }
00433     } else {
00434         if (oldLength)
00435             ++oldLength; // add new trailing space char
00436         text=text.simplifyWhiteSpace(); // drop all unprintable chars
00437     }
00438     QString newtext;
00439     if (keep_formatting)
00440         newtext=oldtext + text;
00441     else {
00442         newtext=oldtext + " " + text;
00443         newtext=newtext.simplifyWhiteSpace(); // strip possible new space at beginning.
00444     }
00445     currentText.setData(newtext);
00446     int newLength=text.length();
00447     QDomElement lastformat=currentFormat(paragraph,true);
00448     if (lastformat.attribute("id").isEmpty()) // keep old id value, e.g. for LINK URL
00449         lastformat.setAttribute("id",format_id);
00450     lastformat.setAttribute("pos",QString("%1").arg(oldLength));
00451     lastformat.setAttribute("len",QString("%1").arg(newLength));
00452 }
00453 
00454 QString KWDWriter::getText(QDomElement paragraph) {
00455     QDomNode temp=paragraph.elementsByTagName("TEXT").item(0).firstChild();
00456     QDomText currentText=temp.toText();
00457     if (temp.isNull()) { kdWarning(30503) << "no text" << endl; }
00458     return currentText.data();
00459 }
00460 
00461 
00462 QDomElement KWDWriter::startFormat(QDomElement paragraph) {
00463         if (paragraph.isNull()) { kdWarning(30503) << "startFormat on empty paragraph" << endl; }
00464     QDomElement format=_doc->createElement("FORMAT");
00465     paragraph.elementsByTagName("FORMATS").item(0).appendChild(format);
00466     return format;
00467 }
00468 
00469 
00470 QDomElement KWDWriter::startFormat(QDomElement paragraph, QDomElement formatToClone) {
00471     QDomElement format=formatToClone.cloneNode().toElement();
00472     if (format.isNull()) { kdWarning(30503) << "startFormat: null format cloned" << endl; }
00473         if (paragraph.isNull()) { kdWarning(30503) << "startFormat on empty paragraph" << endl; }
00474 
00475     format.removeAttribute("len");
00476     format.removeAttribute("pos");
00477     format.removeAttribute("id");
00478     for (QDomElement a=format.firstChild().toElement();!a.isNull();a=a.nextSibling().toElement()) {
00479         if (a.tagName() == "ANCHOR") {
00480               format.removeChild(a);
00481         }
00482     }
00483     paragraph.elementsByTagName("FORMATS").item(0).appendChild(format);
00484     return format;
00485 }
00486 
00487 QDomElement KWDWriter::currentFormat(QDomElement paragraph, bool start_new_one) {
00488 
00489     QDomElement e=paragraph.elementsByTagName("FORMATS").item(0).lastChild().toElement();
00490     if (e.isNull()) {
00491        // no current format, start a new one
00492        if (start_new_one) return startFormat(paragraph);
00493        else { kdWarning(30503) << "warning: returning null format" << endl; }
00494     }
00495     if (!e.attribute("len").isNull()) {
00496        // current format already has length, clone it.
00497        if (start_new_one) return startFormat(paragraph,e);
00498     }
00499     return e;
00500 }
00501 
00502 
00503 void KWDWriter::cleanUpParagraph(QDomElement paragraph) {
00504     QDomElement e=paragraph.elementsByTagName("FORMATS").item(0).toElement();
00505     if (e.isNull()) { kdWarning(30503) << "cleanup : no valid paragraph" << endl; return; }
00506     for (QDomElement k=e.firstChild().toElement();!k.isNull();k=k.nextSibling().toElement()) {
00507          if (k.attribute("len",QString::null).isNull()) {
00508              e.removeChild(k);
00509              cleanUpParagraph(paragraph);
00510              return;
00511          }
00512     }
00513 }
00514 
00515 
00516 QDomElement KWDWriter::addFrame(QDomElement frameset, QRect rect, int runaround, int copy,
00517                                 int newFrameBehaviour, int runaroundGap
00518                  ) {
00519     QDomElement frame = _doc->createElement("FRAME");
00520     frameset.appendChild(frame);
00521     frame.setAttribute("runaround",runaround);
00522     frame.setAttribute("copy",copy);
00523     frame.setAttribute("newFrameBehaviour",newFrameBehaviour);
00524     frame.setAttribute("runaroundGap",runaroundGap);
00525     addRect(frame,rect);
00526     return frame;
00527 }
00528 
00529 QDomElement KWDWriter::docroot() {
00530     return _doc->elementsByTagName("DOC").item(0).toElement();
00531 }
00532 
00533 bool KWDWriter::writeDoc() {
00534     QCString str=_doc->toCString();
00535     kdWarning(30503) << str << endl;
00536 
00537     if (!_store->open("root")) {
00538         return false;
00539     } else {
00540         _store->write((const char *)str, str.length());
00541         _store->close();
00542     }
00543 
00544     if (!_store->open("documentinfo.xml")) {
00545         kdWarning(30503) << "WARNING: unable to write out doc info. continuing anyway" << endl;
00546     } else {
00547         str=_docinfo->toCString();
00548         _store->write((const char *)str, str.length());
00549         _store->close();
00550     }
00551 
00552     return true;
00553 }
00554 
00555 
00556 QDomElement KWDWriter::mainFrameset() {
00557     return _mainFrameset;
00558 }
00559 
00560 
00561 void KWDWriter::addRect(QDomElement e,QRect rect) {
00562      e.setAttribute("top",_zoomhandler->pixelYToPt( rect.top()));
00563      e.setAttribute("left",_zoomhandler->pixelXToPt(rect.left()));
00564      e.setAttribute("bottom",_zoomhandler->pixelYToPt(rect.bottom()));
00565      e.setAttribute("right",_zoomhandler->pixelXToPt(rect.right()));
00566 }
00567 
00568 
00569 
00570 
00571 
00572 KWDWriter::~KWDWriter(){
00573     delete(_zoomhandler);
00574 }
KDE Home | KDE Accessibility Home | Description of Access Keys