kexi

formIO.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
00003    Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include <kdebug.h>
00022 
00023 #include <qmetaobject.h>
00024 #include <qdom.h>
00025 #include <qfile.h>
00026 #include <qtextstream.h>
00027 #include <qcursor.h>
00028 #include <qbuffer.h>
00029 #include <qimage.h>
00030 #include <qlayout.h>
00031 #include <qobjectlist.h>
00032 #include <qdatetime.h>
00033 #include <qlabel.h>
00034 #include <qpainter.h>
00035 
00036 #include <kfiledialog.h>
00037 #include <klocale.h>
00038 #include <kcommand.h>
00039 #include <kaccelmanager.h>
00040 
00041 #include "form.h"
00042 #include "container.h"
00043 #include "objecttree.h"
00044 #include "formmanager.h"
00045 #include "widgetlibrary.h"
00046 #include "spring.h"
00047 #include "pixmapcollection.h"
00048 #include "events.h"
00049 #include "utils.h"
00050 #include "kexiflowlayout.h"
00051 
00052 #include "formIO.h"
00053 
00055 CustomWidget::CustomWidget(const QCString &className, QWidget *parent, const char *name)
00056 : QWidget(parent, name), m_className(className)
00057 {
00058     setBackgroundMode(Qt::PaletteDark);
00059 }
00060 
00061 CustomWidget::~CustomWidget()
00062 {
00063 }
00064 
00065 void
00066 CustomWidget::paintEvent(QPaintEvent *)
00067 {
00068     QPainter p(this);
00069     p.setPen(palette().active().text());
00070     QRect r(rect());
00071     r.setX(r.x()+2);
00072     p.drawText(r, Qt::AlignTop, m_className);
00073 }
00074 
00075 using namespace KFormDesigner;
00076 
00077 QDict<QLabel> *FormIO::m_buddies = 0;
00078 ObjectTreeItem *FormIO::m_currentItem = 0;
00079 Form *FormIO::m_currentForm = 0;
00080 bool FormIO::m_savePixmapsInline = false;
00081 
00082 // FormIO itself
00083 
00084 KFORMEDITOR_EXPORT uint KFormDesigner::version()
00085 {
00086     return KFORMDESIGNER_VERSION;
00087 }
00088 
00092 
00093 FormIO::FormIO()
00094 {
00095 }
00096 
00097 FormIO::~FormIO()
00098 {
00099 }
00100 
00101 bool
00102 FormIO::saveFormToFile(Form *form, const QString &filename)
00103 {
00104     QString m_filename;
00105     if(!form->filename().isNull() && filename.isNull())
00106         m_filename = form->filename();
00107 
00108     if(filename.isNull())
00109     {
00110         m_filename = KFileDialog::getSaveFileName(QString::null, i18n("*.ui|Qt Designer UI Files"));
00111         if(m_filename.isNull())
00112             return false;
00113     }
00114     else
00115         m_filename = filename;
00116     form->setFilename(m_filename);
00117 
00118     QDomDocument domDoc;
00119     if (!saveFormToDom(form, domDoc))
00120         return false;
00121 
00122     QFile file(m_filename);
00123     if (!file.open(IO_WriteOnly))
00124         return false;
00125 
00126     QTextStream stream(&file);
00127     stream << domDoc.toString(3) << endl;
00128     file.close();
00129 
00130     return true;
00131 }
00132 
00133 bool
00134 FormIO::saveFormToByteArray(Form *form, QByteArray &dest)
00135 {
00136     QDomDocument domDoc;
00137     if (!saveFormToDom(form, domDoc))
00138         return false;
00139     dest = domDoc.toCString();
00140     return true;
00141 }
00142 
00143 bool
00144 FormIO::saveFormToString(Form *form, QString &dest, int indent)
00145 {
00146     QDomDocument domDoc;
00147     if (!saveFormToDom(form, domDoc))
00148         return false;
00149     dest = domDoc.toString(indent);
00150     return true;
00151 }
00152 
00153 bool
00154 FormIO::saveFormToDom(Form *form, QDomDocument &domDoc)
00155 {
00156     m_currentForm = form;
00157 
00158     domDoc = QDomDocument("UI");
00159     QDomElement uiElement = domDoc.createElement("UI");
00160     domDoc.appendChild(uiElement);
00161     uiElement.setAttribute("version", "3.1");
00162     uiElement.setAttribute("stdsetdef", 1);
00163 
00164     //update format version information
00165     form->headerProperties()->insert("version", QString::number(form->formatVersion()));
00166     //custom properties
00167     QDomElement headerPropertiesEl = domDoc.createElement("kfd:customHeader");
00168     for (QMapConstIterator<QCString,QString> it=form->headerProperties()->constBegin(); it!=form->headerProperties()->constEnd(); ++it) {
00169         headerPropertiesEl.setAttribute(it.key(), it.data());
00170     }
00171     uiElement.appendChild(headerPropertiesEl);
00172 
00174     QDomElement inlinePix = domDoc.createElement("pixmapinproject");
00175     uiElement.appendChild(inlinePix);
00176 
00177     // We create the top class element
00178     QDomElement baseClass = domDoc.createElement("class");
00179     uiElement.appendChild(baseClass);
00180     QDomText baseClassV = domDoc.createTextNode("QWidget");
00181     baseClass.appendChild(baseClassV);
00182 
00183     // Save the toplevel widgets, and so the whole Form
00184     saveWidget(form->objectTree(), uiElement, domDoc);
00185 
00186     // We then save the layoutdefaults element
00187     QDomElement layoutDefaults = domDoc.createElement("layoutDefaults");
00188     layoutDefaults.setAttribute("spacing", QString::number(form->defaultSpacing()));
00189     layoutDefaults.setAttribute("margin", QString::number(form->defaultMargin()));
00190     uiElement.appendChild(layoutDefaults);
00191 
00193     if(form->autoTabStops())
00194         form->autoAssignTabStops();
00195     QDomElement tabStops = domDoc.createElement("tabstops");
00196     uiElement.appendChild(tabStops);
00197     for(ObjectTreeListIterator it( form->tabStopsIterator() ); it.current(); ++it)
00198     {
00199         QDomElement tabstop = domDoc.createElement("tabstop");
00200         tabStops.appendChild(tabstop);
00201         QDomText tabStopText = domDoc.createTextNode(it.current()->name());
00202         tabstop.appendChild(tabStopText);
00203     }
00204 
00205     // Save the Form 's PixmapCollection
00206     form->pixmapCollection()->save(uiElement);
00207     // Save the Form connections
00208     form->connectionBuffer()->save(uiElement);
00209 
00210     form->commandHistory()->documentSaved();
00211 
00212     m_currentForm = 0;
00213     m_currentItem = 0;
00214     //m_currentWidget = 0;
00215 
00216     return true;
00217 }
00218 
00219 bool
00220 FormIO::loadFormFromByteArray(Form *form, QWidget *container, QByteArray &src, bool preview)
00221 {
00222     QString errMsg;
00223     int errLine;
00224     int errCol;
00225 
00226     QDomDocument inBuf;
00227     bool parsed = inBuf.setContent(src, false, &errMsg, &errLine, &errCol);
00228 
00229     if(!parsed)
00230     {
00231         kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
00232         kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
00233         return false;
00234     }
00235 
00236     if (!loadFormFromDom(form, container, inBuf))
00237         return false;
00238     if(preview)
00239         form->setDesignMode(false);
00240     return true;
00241 }
00242 
00243 bool
00244 FormIO::loadFormFromString(Form *form, QWidget *container, QString &src, bool preview)
00245 {
00246     QString errMsg;
00247     int errLine;
00248     int errCol;
00249 
00250 #ifdef KEXI_SHOW_DEBUG_ACTIONS
00251     form->m_recentlyLoadedUICode = src;
00252 #endif
00253 
00254     QDomDocument inBuf;
00255     bool parsed = inBuf.setContent(src, false, &errMsg, &errLine, &errCol);
00256 
00257     if(!parsed)
00258     {
00259         kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
00260         kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
00261         return false;
00262     }
00263 
00264     if (!loadFormFromDom(form, container, inBuf))
00265         return false;
00266     if(preview)
00267         form->setDesignMode(false);
00268     return true;
00269 }
00270 
00271 bool
00272 FormIO::loadFormFromFile(Form *form, QWidget *container, const QString &filename)
00273 {
00274     QString errMsg;
00275     int errLine;
00276     int errCol;
00277     QString m_filename;
00278 
00279     if(filename.isNull())
00280     {
00281         m_filename = KFileDialog::getOpenFileName(QString::null, i18n("*.ui|Qt Designer UI Files"));
00282         if(m_filename.isNull())
00283             return false;
00284     }
00285     else
00286         m_filename = filename;
00287 
00288     QFile file(m_filename);
00289     if(!file.open(IO_ReadOnly))
00290     {
00291         kdDebug() << "Cannot open the file " << filename << endl;
00292         return false;
00293     }
00294     QTextStream stream(&file);
00295     QString text = stream.read();
00296 
00297     QDomDocument inBuf;
00298     bool parsed = inBuf.setContent(text, false, &errMsg, &errLine, &errCol);
00299 
00300     if(!parsed)
00301     {
00302         kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
00303         kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
00304         return false;
00305     }
00306 
00307     return loadFormFromDom(form, container, inBuf);
00308 }
00309 
00310 bool
00311 FormIO::loadFormFromDom(Form *form, QWidget *container, QDomDocument &inBuf)
00312 {
00313     m_currentForm = form;
00314 
00315     QDomElement ui = inBuf.namedItem("UI").toElement();
00316 
00317     //custom properties
00318     form->headerProperties()->clear();
00319     QDomElement headerPropertiesEl = ui.namedItem("kfd:customHeader").toElement();
00320     QDomAttr attr = headerPropertiesEl.firstChild().toAttr();
00321     while (!attr.isNull() && attr.isAttr()) {
00322         form->headerProperties()->insert(attr.name().latin1(), attr.value());
00323         attr = attr.nextSibling().toAttr();
00324     }
00325     //update format version information
00326     uint ver = 1; //the default
00327     if (form->headerProperties()->contains("version")) {
00328         bool ok;
00329         uint v = (*form->headerProperties())["version"].toUInt(&ok);
00330         if (ok)
00331             ver = v;
00332     }
00333     kdDebug() << "FormIO::loadFormFromDom(): original format version: " << ver << endl;
00334     form->setOriginalFormatVersion( ver );
00335     if (ver < KFormDesigner::version()) {
00338         kdDebug() << "FormIO::loadFormFromDom(): original format is older than current: " << KFormDesigner::version() << endl;
00339         form->setFormatVersion( KFormDesigner::version() );
00340     }
00341     else
00342         form->setFormatVersion( ver );
00343 
00344     if (ver > KFormDesigner::version()) {
00346         kdDebug() << "FormIO::loadFormFromDom(): original format is newer than current: " << KFormDesigner::version() << endl;
00347     }
00348 
00349     // Load the pixmap collection
00350     m_savePixmapsInline = ( (ui.namedItem("pixmapinproject").isNull()) || (!ui.namedItem("images").isNull()) );
00351     form->pixmapCollection()->load(ui.namedItem("collection"));
00352 
00353     QDomElement element = ui.namedItem("widget").toElement();
00354     createToplevelWidget(form, container, element);
00355 
00356     // Loading the tabstops
00357     QDomElement tabStops = ui.namedItem("tabstops").toElement();
00358 //  if(tabStops.isNull())
00359 //      return 1;
00360     if(!tabStops.isNull()) {
00361         int i = 0;
00362         uint itemsNotFound = 0;
00363         for(QDomNode n = tabStops.firstChild(); !n.isNull(); n = n.nextSibling(), i++)
00364         {
00365             QString name = n.toElement().text();
00366             ObjectTreeItem *item = form->objectTree()->lookup(name);
00367             if(!item)
00368             {
00369                 kdDebug() << "FormIO::loadFormFromDom ERROR : no ObjectTreeItem " << endl;
00370                 continue;
00371             }
00372             const int index = form->tabStops()->findRef(item);
00373             /* Compute a real destination index: "a number of not found items so far". */
00374             const int realIndex = i - itemsNotFound;
00375             if((index != -1) && (index != realIndex)) // the widget is not in the same place, so we move it
00376             {
00377                 form->tabStops()->remove(item);
00378                 form->tabStops()->insert(realIndex, item);
00379             }
00380             if(index == -1) {
00381                 itemsNotFound++;
00382                 kdDebug() << "FormIO: item '" << name << "' not in list" << endl;
00383             }
00384         }
00385     }
00386 
00387     // Load the form connections
00388     form->connectionBuffer()->load(ui.namedItem("connections"));
00389 
00390     m_currentForm = 0;
00391     m_currentItem = 0;
00392 
00393     return true;
00394 }
00395 
00399 
00400 void
00401 FormIO::savePropertyValue(QDomElement &parentNode, QDomDocument &parent, const char *name, 
00402     const QVariant &value, QWidget *w, WidgetLibrary *lib)
00403 {
00404     // Widget specific properties and attributes ///////////////
00405     kdDebug() << "FormIO::savePropertyValue()  Saving the property: " << name << endl;
00406     const int propertyId = w->metaObject()->findProperty(name, true);
00407     if(propertyId == -1)
00408     {
00409         kdDebug() << "FormIO::savePropertyValue()  The object doesn't have this property. Let's try the WidgetLibrary." << endl;
00410         if(lib)
00411             lib->saveSpecialProperty(w->className(), name, value, w, parentNode, parent);
00412         return;
00413     }
00414 
00415     const QMetaProperty *meta = w->metaObject()->property(propertyId, true);
00416     if (!meta->stored( w )) //not storable
00417         return;
00418     QDomElement propertyE = parent.createElement("property");
00419     propertyE.setAttribute("name", name);
00420 
00421     if(meta && meta->isEnumType())
00422     {
00423         // this property is enum or set type
00424         QDomElement type;
00425         QDomText valueE;
00426 
00427         if(meta->isSetType())
00428         {
00429             QStringList list = QStringList::fromStrList(meta->valueToKeys(value.toInt()));
00430             type = parent.createElement("set");
00431             valueE = parent.createTextNode(list.join("|"));
00432             type.appendChild(valueE);
00433         }
00434         else
00435         {
00436             QString s = meta->valueToKey(value.toInt());
00437             type = parent.createElement("enum");
00438             valueE = parent.createTextNode(s);
00439             type.appendChild(valueE);
00440         }
00441         propertyE.appendChild(type);
00442         parentNode.appendChild(propertyE);
00443         return;
00444     }
00445 
00446     if(value.type() == QVariant::Pixmap) {
00447         QDomText valueE;
00448         QDomElement type = parent.createElement("pixmap");
00449         QCString property = propertyE.attribute("name").latin1();
00450 //todo      QCString pixmapName = m_currentItem->widget()->property("pixmapName").toCString();
00451         if(m_savePixmapsInline /* (js)too risky: || m_currentItem->pixmapName(property).isNull() */)
00452             valueE = parent.createTextNode(saveImage(parent, value.toPixmap()));
00453         else
00454             valueE = parent.createTextNode(m_currentItem->pixmapName(property));
00455         type.appendChild(valueE);
00456         propertyE.appendChild(type);
00457         parentNode.appendChild(propertyE);
00458         return;
00459     }
00460 
00461     // Saving a "normal" property
00462     writeVariant(parent, propertyE, value);
00463     parentNode.appendChild(propertyE);
00464 }
00465 
00466 void
00467 FormIO::writeVariant(QDomDocument &parent, QDomElement &parentNode, QVariant value)
00468 {
00469     QDomElement type;
00470     QDomText valueE;
00471 
00472     switch(value.type())
00473     {
00474         case QVariant::String:
00475         {
00476             type = parent.createElement("string");
00477             valueE = parent.createTextNode(value.toString());
00478             type.appendChild(valueE);
00479             break;
00480         }
00481         case QVariant::CString:
00482         {
00483             type = parent.createElement("cstring");
00484             valueE = parent.createTextNode(value.toString());
00485             type.appendChild(valueE);
00486             break;
00487         }
00488         case QVariant::Rect:
00489         {
00490             type = parent.createElement("rect");
00491             QDomElement x = parent.createElement("x");
00492             QDomElement y = parent.createElement("y");
00493             QDomElement w = parent.createElement("width");
00494             QDomElement h = parent.createElement("height");
00495             QDomText valueX = parent.createTextNode(QString::number(value.toRect().x()));
00496             QDomText valueY = parent.createTextNode(QString::number(value.toRect().y()));
00497             QDomText valueW = parent.createTextNode(QString::number(value.toRect().width()));
00498             QDomText valueH = parent.createTextNode(QString::number(value.toRect().height()));
00499 
00500             x.appendChild(valueX);
00501             y.appendChild(valueY);
00502             w.appendChild(valueW);
00503             h.appendChild(valueH);
00504 
00505             type.appendChild(x);
00506             type.appendChild(y);
00507             type.appendChild(w);
00508             type.appendChild(h);
00509             break;
00510         }
00511         case QVariant::Color:
00512         {
00513             type = parent.createElement("color");
00514             QDomElement r = parent.createElement("red");
00515             QDomElement g = parent.createElement("green");
00516             QDomElement b = parent.createElement("blue");
00517             QDomText valueR = parent.createTextNode(QString::number(value.toColor().red()));
00518             QDomText valueG = parent.createTextNode(QString::number(value.toColor().green()));
00519             QDomText valueB = parent.createTextNode(QString::number(value.toColor().blue()));
00520 
00521             r.appendChild(valueR);
00522             g.appendChild(valueG);
00523             b.appendChild(valueB);
00524 
00525             type.appendChild(r);
00526             type.appendChild(g);
00527             type.appendChild(b);
00528             break;
00529         }
00530         case QVariant::Bool:
00531         {
00532             type = parent.createElement("bool");
00533             //valueE = parent.createTextNode(QString::number(value.toBool()));
00534             valueE = parent.createTextNode(value.toBool() ? "true" : "false");
00535             type.appendChild(valueE);
00536             break;
00537         }
00538         case QVariant::Int:
00539         case QVariant::UInt:
00540         {
00541             type = parent.createElement("number");
00542             valueE = parent.createTextNode(QString::number(value.toInt()));
00543             type.appendChild(valueE);
00544             break;
00545         }
00546         case QVariant::Size:
00547         {
00548             type = parent.createElement("size");
00549             QDomElement w = parent.createElement("width");
00550             QDomElement h = parent.createElement("height");
00551             QDomText valueW = parent.createTextNode(QString::number(value.toSize().width()));
00552             QDomText valueH = parent.createTextNode(QString::number(value.toSize().height()));
00553 
00554             w.appendChild(valueW);
00555             h.appendChild(valueH);
00556 
00557             type.appendChild(w);
00558             type.appendChild(h);
00559             break;
00560         }
00561         case QVariant::Point:
00562         {
00563             type = parent.createElement("point");
00564             QDomElement x = parent.createElement("x");
00565             QDomElement y = parent.createElement("y");
00566             QDomText valueX = parent.createTextNode(QString::number(value.toPoint().x()));
00567             QDomText valueY = parent.createTextNode(QString::number(value.toPoint().y()));
00568 
00569             x.appendChild(valueX);
00570             y.appendChild(valueY);
00571 
00572             type.appendChild(x);
00573             type.appendChild(y);
00574             break;
00575         }
00576         case QVariant::Font:
00577         {
00578             type = parent.createElement("font");
00579             QDomElement f = parent.createElement("family");
00580             QDomElement p = parent.createElement("pointsize");
00581             QDomElement w = parent.createElement("weight");
00582             QDomElement b = parent.createElement("bold");
00583             QDomElement i = parent.createElement("italic");
00584             QDomElement u = parent.createElement("underline");
00585             QDomElement s = parent.createElement("strikeout");
00586             QDomText valueF = parent.createTextNode(value.toFont().family());
00587             QDomText valueP = parent.createTextNode(QString::number(value.toFont().pointSize()));
00588             QDomText valueW = parent.createTextNode(QString::number(value.toFont().weight()));
00589             QDomText valueB = parent.createTextNode(QString::number(value.toFont().bold()));
00590             QDomText valueI = parent.createTextNode(QString::number(value.toFont().italic()));
00591             QDomText valueU = parent.createTextNode(QString::number(value.toFont().underline()));
00592             QDomText valueS = parent.createTextNode(QString::number(value.toFont().strikeOut()));
00593 
00594             f.appendChild(valueF);
00595             p.appendChild(valueP);
00596             w.appendChild(valueW);
00597             b.appendChild(valueB);
00598             i.appendChild(valueI);
00599             u.appendChild(valueU);
00600             s.appendChild(valueS);
00601 
00602             type.appendChild(f);
00603             type.appendChild(p);
00604             type.appendChild(w);
00605             type.appendChild(b);
00606             type.appendChild(i);
00607             type.appendChild(u);
00608             type.appendChild(s);
00609             break;
00610         }
00611         case QVariant::Cursor:
00612         {
00613             type = parent.createElement("cursor");
00614             valueE = parent.createTextNode(QString::number(value.toCursor().shape()));
00615             type.appendChild(valueE);
00616             break;
00617         }
00618         case QVariant::SizePolicy:
00619         {
00620             type = parent.createElement("sizepolicy");
00621             QDomElement h = parent.createElement("hsizetype");
00622             QDomElement v = parent.createElement("vsizetype");
00623             QDomElement hs = parent.createElement("horstretch");
00624             QDomElement vs = parent.createElement("verstretch");
00625             QDomText valueH = parent.createTextNode(QString::number(value.toSizePolicy().horData()));
00626             QDomText valueV = parent.createTextNode(QString::number(value.toSizePolicy().verData()));
00627             QDomText valueHS = parent.createTextNode(QString::number(value.toSizePolicy().horStretch()));
00628             QDomText valueVS = parent.createTextNode(QString::number(value.toSizePolicy().verStretch()));
00629 
00630             h.appendChild(valueH);
00631             v.appendChild(valueV);
00632             hs.appendChild(valueHS);
00633             vs.appendChild(valueVS);
00634 
00635             type.appendChild(h);
00636             type.appendChild(v);
00637             type.appendChild(hs);
00638             type.appendChild(vs);
00639             break;
00640         }
00641         case QVariant::Time:
00642         {
00643             type = parent.createElement("time");
00644             QDomElement h = parent.createElement("hour");
00645             QDomElement m = parent.createElement("minute");
00646             QDomElement s = parent.createElement("second");
00647             QDomText valueH = parent.createTextNode(QString::number(value.toTime().hour()));
00648             QDomText valueM = parent.createTextNode(QString::number(value.toTime().minute()));
00649             QDomText valueS = parent.createTextNode(QString::number(value.toTime().second()));
00650 
00651             h.appendChild(valueH);
00652             m.appendChild(valueM);
00653             s.appendChild(valueS);
00654 
00655             type.appendChild(h);
00656             type.appendChild(m);
00657             type.appendChild(s);
00658             break;
00659         }
00660         case QVariant::Date:
00661         {
00662             type = parent.createElement("date");
00663             QDomElement y = parent.createElement("year");
00664             QDomElement m = parent.createElement("month");
00665             QDomElement d = parent.createElement("day");
00666             QDomText valueY = parent.createTextNode(QString::number(value.toDate().year()));
00667             QDomText valueM = parent.createTextNode(QString::number(value.toDate().month()));
00668             QDomText valueD = parent.createTextNode(QString::number(value.toDate().day()));
00669 
00670             y.appendChild(valueY);
00671             m.appendChild(valueM);
00672             d.appendChild(valueD);
00673 
00674             type.appendChild(y);
00675             type.appendChild(m);
00676             type.appendChild(d);
00677             break;
00678         }
00679         case QVariant::DateTime:
00680         {
00681             type = parent.createElement("datetime");
00682             QDomElement h = parent.createElement("hour");
00683             QDomElement m = parent.createElement("minute");
00684             QDomElement s = parent.createElement("second");
00685             QDomElement y = parent.createElement("year");
00686             QDomElement mo = parent.createElement("month");
00687             QDomElement d = parent.createElement("day");
00688             QDomText valueH = parent.createTextNode(QString::number(value.toDateTime().time().hour()));
00689             QDomText valueM = parent.createTextNode(QString::number(value.toDateTime().time().minute()));
00690             QDomText valueS = parent.createTextNode(QString::number(value.toDateTime().time().second()));
00691             QDomText valueY = parent.createTextNode(QString::number(value.toDateTime().date().year()));
00692             QDomText valueMo = parent.createTextNode(QString::number(value.toDateTime().date().month()));
00693             QDomText valueD = parent.createTextNode(QString::number(value.toDateTime().date().day()));
00694 
00695             h.appendChild(valueH);
00696             m.appendChild(valueM);
00697             s.appendChild(valueS);
00698             y.appendChild(valueY);
00699             mo.appendChild(valueMo);
00700             d.appendChild(valueD);
00701 
00702             type.appendChild(h);
00703             type.appendChild(m);
00704             type.appendChild(s);
00705             type.appendChild(y);
00706             type.appendChild(mo);
00707             type.appendChild(d);
00708             break;
00709         }
00710         default:
00711             break;
00712     }
00713 
00714     parentNode.appendChild(type);
00715 }
00716 
00717 void
00718 FormIO::savePropertyElement(QDomElement &parentNode, QDomDocument &domDoc, const QString &tagName, const QString &property, const QVariant &value)
00719 {
00720     QDomElement propertyE = domDoc.createElement(tagName);
00721     propertyE.setAttribute("name", property);
00722     writeVariant(domDoc, propertyE, value);
00723     parentNode.appendChild(propertyE);
00724 }
00725 
00726 QVariant
00727 FormIO::readPropertyValue(QDomNode node, QObject *obj, const QString &name)
00728 {
00729     QDomElement tag = node.toElement();
00730     QString text = tag.text();
00731     QString type = tag.tagName();
00732 
00733     if(type == "string" || type == "cstring")
00734         return text;
00735     else if(type == "rect")
00736     {
00737         QDomElement x = node.namedItem("x").toElement();
00738         QDomElement y = node.namedItem("y").toElement();
00739         QDomElement w = node.namedItem("width").toElement();
00740         QDomElement h = node.namedItem("height").toElement();
00741 
00742         int rx = x.text().toInt();
00743         int ry = y.text().toInt();
00744         int rw = w.text().toInt();
00745         int rh = h.text().toInt();
00746 
00747         return QRect(rx, ry, rw, rh);
00748     }
00749     else if(type == "color")
00750     {
00751         QDomElement r = node.namedItem("red").toElement();
00752         QDomElement g = node.namedItem("green").toElement();
00753         QDomElement b = node.namedItem("blue").toElement();
00754 
00755         int red = r.text().toInt();
00756         int green = g.text().toInt();
00757         int blue = b.text().toInt();
00758 
00759         return QColor(red, green, blue);
00760     }
00761     else if(type == "bool")
00762     {
00763         if(text == "true")
00764             return QVariant(true, 3);
00765         else if(text == "false")
00766             return QVariant(false, 3);
00767         return QVariant(text.toInt(), 3);
00768     }
00769     else if(type == "number")
00770     {
00771         return text.toInt();
00772     }
00773     else if(type == "size")
00774     {
00775         QDomElement w = node.namedItem("width").toElement();
00776         QDomElement h = node.namedItem("height").toElement();
00777 
00778         return QSize(w.text().toInt(), h.text().toInt());
00779     }
00780     else if(type == "point")
00781     {
00782         QDomElement x = node.namedItem("x").toElement();
00783         QDomElement y = node.namedItem("y").toElement();
00784 
00785         return QPoint(x.text().toInt(), y.text().toInt());
00786     }
00787     else if(type == "font")
00788     {
00789         QDomElement fa = node.namedItem("family").toElement();
00790         QDomElement p = node.namedItem("pointsize").toElement();
00791         QDomElement w = node.namedItem("weight").toElement();
00792         QDomElement b = node.namedItem("bold").toElement();
00793         QDomElement i = node.namedItem("italic").toElement();
00794         QDomElement u = node.namedItem("underline").toElement();
00795         QDomElement s = node.namedItem("strikeout").toElement();
00796 
00797         QFont f;
00798         f.setFamily(fa.text());
00799         f.setPointSize(p.text().toInt());
00800         f.setWeight(w.text().toInt());
00801         f.setBold(b.text().toInt());
00802         f.setItalic(i.text().toInt());
00803         f.setUnderline(u.text().toInt());
00804         f.setStrikeOut(s.text().toInt());
00805 
00806         return f;
00807     }
00808     else if(type == "cursor")
00809     {
00810         return QCursor(text.toInt());
00811     }
00812     else if(type == "time")
00813     {
00814         QDomElement h = node.namedItem("hour").toElement();
00815         QDomElement m = node.namedItem("minute").toElement();
00816         QDomElement s = node.namedItem("second").toElement();
00817 
00818         return QTime(h.text().toInt(), m.text().toInt(), s.text().toInt());
00819     }
00820     else if(type == "date")
00821     {
00822         QDomElement y = node.namedItem("year").toElement();
00823         QDomElement m = node.namedItem("month").toElement();
00824         QDomElement d = node.namedItem("day").toElement();
00825 
00826         return QDate(y.text().toInt(), m.text().toInt(), d.text().toInt());
00827     }
00828     else if(type == "datetime")
00829     {
00830         QDomElement h = node.namedItem("hour").toElement();
00831         QDomElement m = node.namedItem("minute").toElement();
00832         QDomElement s = node.namedItem("second").toElement();
00833         QDomElement y = node.namedItem("year").toElement();
00834         QDomElement mo = node.namedItem("month").toElement();
00835         QDomElement d = node.namedItem("day").toElement();
00836 
00837         QTime t(h.text().toInt(), m.text().toInt(), s.text().toInt());
00838         QDate da(y.text().toInt(), mo.text().toInt(), d.text().toInt());
00839 
00840         return QDateTime(da, t);
00841     }
00842     else if(type == "sizepolicy")
00843     {
00844         QDomElement h = node.namedItem("hsizetype").toElement();
00845         QDomElement v = node.namedItem("vsizetype").toElement();
00846         QDomElement hs = node.namedItem("horstretch").toElement();
00847         QDomElement vs = node.namedItem("verstretch").toElement();
00848 
00849         QSizePolicy s;
00850         s.setHorData((QSizePolicy::SizeType)h.text().toInt());
00851         s.setVerData((QSizePolicy::SizeType)v.text().toInt());
00852         s.setHorStretch(hs.text().toInt());
00853         s.setVerStretch(vs.text().toInt());
00854         return s;
00855     }
00856     else if(type == "pixmap")
00857     {
00858         if(m_savePixmapsInline || !m_currentForm || !m_currentItem || !m_currentForm->pixmapCollection()->contains(text))
00859             return loadImage(tag.ownerDocument(), text);
00860         else
00861         {
00862             m_currentItem->setPixmapName(name.latin1(), text);
00863             return m_currentForm->pixmapCollection()->getPixmap(text);
00864         }
00865         return QVariant(QPixmap());
00866     }
00867     else if(type == "enum")
00868         return text;
00869     else if(type == "set")
00870     {
00871         int count = obj->metaObject()->findProperty(name.latin1(), true);
00872         const QMetaProperty *meta = count!=-1 ? obj->metaObject()->property(count, true) : 0;
00873 
00874         if(meta && meta->isSetType())
00875         {
00876             QStrList keys;
00877             QStringList list = QStringList::split("|", text);
00878             for(QStringList::iterator it = list.begin(); it != list.end(); ++it)
00879                 keys.append((*it).latin1());
00880 
00881             return QVariant(meta->keysToValue(keys));
00882         }
00883     }
00884     return QVariant();
00885 }
00886 
00890 
00891 void
00892 FormIO::saveWidget(ObjectTreeItem *item, QDomElement &parent, QDomDocument &domDoc, bool insideGridLayout)
00893 {
00894     if (!item)
00895         return;
00896     bool savedAlignment = false;
00897     // we let Spring class handle saving itself
00898     if(item->className() == "Spring")
00899     {
00900         Spring::saveSpring(item, parent, domDoc, insideGridLayout);
00901         return;
00902     }
00903 
00904     bool resetCurrentForm = false;
00905     m_currentItem = item;
00906     if(!m_currentForm) // copying widget
00907     {
00908         resetCurrentForm = true;
00909         m_currentForm = item->container() ? item->container()->form() : item->parent()->container()->form();
00910     }
00911 
00912 
00913     WidgetLibrary *lib = m_currentForm->library();
00914 //  if(item->container())
00915 //      lib = item->container()->form()->manager()->lib();
00916 //  else
00917 //      lib = item->parent()->container()->form()->manager()->lib();
00918 
00919     // We create the "widget" element
00920     QDomElement tclass = domDoc.createElement("widget");
00921     parent.appendChild(tclass);
00922 
00923     if(insideGridLayout)
00924     {
00925         tclass.setAttribute("row", item->gridRow());
00926         tclass.setAttribute("column", item->gridCol());
00927         if(item->spanMultipleCells())
00928         {
00929             tclass.setAttribute("rowspan", item->gridRowSpan());
00930             tclass.setAttribute("colspan", item->gridColSpan());
00931         }
00932     }
00933 
00934     if(!item->parent()) // Toplevel widget
00935         tclass.setAttribute("class", "QWidget");
00936     // For compatibility, HBox, VBox and Grid are saved as "QLayoutWidget"
00937     else if(item->widget()->isA("HBox") || item->widget()->isA("VBox") || item->widget()->isA("Grid")
00938             || item->widget()->isA("HFlow") || item->widget()->isA("VFlow"))
00939         tclass.setAttribute("class", "QLayoutWidget");
00940     else if(item->widget()->isA("CustomWidget"))
00941         tclass.setAttribute("class", item->className());
00942     else // Normal widgets
00943         tclass.setAttribute("class", lib->savingName(item->widget()->className()) );
00944 
00945     savePropertyValue(tclass, domDoc, "name", item->widget()->property("name"), item->widget());
00946 
00947     // We don't want to save the geometry if the widget is inside a layout (so parent.tagName() == "grid" for example)
00948     if(item && !item->parent()) {
00949         // save form widget size, but not its position
00950         savePropertyValue(tclass, domDoc, "geometry",
00951             QRect( QPoint(0,0), item->widget()->size()),
00952             item->widget());
00953     }
00954     // normal widget (if == "UI', it means we're copying widget)
00955     else if(parent.tagName() == "widget" || parent.tagName() == "UI")
00956         savePropertyValue(tclass, domDoc, "geometry", item->widget()->property("geometry"), item->widget());
00957 
00958     // Save the buddy widget for a label
00959     if(item->widget()->inherits("QLabel") && ((QLabel*)item->widget())->buddy())
00960         savePropertyElement(tclass, domDoc, "property", "buddy", ((QLabel*)item->widget())->buddy()->name());
00961 
00962 
00963     // We save every property in the modifProp list of the ObjectTreeItem
00964     QVariantMap *map = new QVariantMap( *(item->modifiedProperties()) );
00965     QMap<QString,QVariant>::ConstIterator endIt = map->constEnd();
00966     for(QMap<QString,QVariant>::ConstIterator it = map->constBegin(); it != endIt; ++it)
00967     {
00968         QString name = it.key();
00969         if((name == QString::fromLatin1("hAlign")) || (name == QString::fromLatin1("vAlign")) || (name == QString::fromLatin1("wordbreak")))
00970         {
00971             if(!savedAlignment) // not tosave it twice
00972             {
00973                 savePropertyValue(tclass, domDoc, "alignment", item->widget()->property("alignment"), item->widget());
00974                 savedAlignment = true;
00975             }
00976         }
00977 
00978         else if(name == "name" || name == "geometry" || name == "layout") {
00979             // these have already been saved
00980         }
00981         else {
00982             savePropertyValue(tclass, domDoc, it.key().latin1(), item->widget()->property(it.key().latin1()), 
00983                 item->widget(), lib);
00984         }
00985     }
00986     delete map;
00987 
00988     if(item->widget()->isA("CustomWidget")) {
00989         QDomDocument doc("TEMP");
00990         doc.setContent(item->m_unknownProps);
00991         for(QDomNode n = doc.firstChild(); !n.isNull(); n = n.nextSibling()) {
00992             tclass.appendChild(n.cloneNode());
00993         }
00994 
00995     }
00996     // Saving container 's layout if there is one
00997     QDomElement layout;
00998     if(item->container() && item->container()->layoutType() != Container::NoLayout)
00999     {
01000         if(item->container()->layout()) // there is a layout
01001         {
01002             layout = domDoc.createElement("temp");
01003             savePropertyValue(layout, domDoc, "name", "unnamed", item->widget());
01004             if(item->modifiedProperties()->contains("layoutMargin"))
01005                 savePropertyElement(layout, domDoc, "property", "margin", item->container()->layoutMargin());
01006             if(item->modifiedProperties()->contains("layoutSpacing"))
01007                 savePropertyElement(layout, domDoc, "property", "spacing", item->container()->layoutSpacing());
01008             tclass.appendChild(layout);
01009         }
01010     }
01011 
01012     int layoutType = item->container() ? item->container()->layoutType() : Container::NoLayout;
01013     switch(layoutType) {
01014         case Container::Grid: // grid layout
01015         {
01016             layout.setTagName("grid");
01017             for(ObjectTreeItem *objIt = item->children()->first(); objIt; objIt = item->children()->next())
01018                 saveWidget(objIt, layout, domDoc, true);
01019             break;
01020         }
01021         case Container::HBox: case Container::VBox:
01022         {
01023             // as we don't save geometry, we need to sort widgets in the right order, not creation order
01024             WidgetList *list;
01025             if(layout.tagName() == "hbox") {
01026                 list = new HorWidgetList();
01027                 layout.setTagName("hbox");
01028             }
01029             else {
01030                 list = new VerWidgetList();
01031                 layout.setTagName("vbox");
01032             }
01033 
01034             for(ObjectTreeItem *objTree = item->children()->first(); objTree; objTree = item->children()->next())
01035                 list->append(objTree->widget());
01036             list->sort();
01037 
01038             for(QWidget *obj = list->first(); obj; obj = list->next()) {
01039                 ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup(obj->name());
01040                 if(item)
01041                     saveWidget(titem, layout, domDoc);
01042             }
01043             delete list;
01044             break;
01045         }
01046         case Container::HFlow: case Container::VFlow:
01047         {
01048             layout.setTagName("grid");
01049             KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
01050             if(!flow)  break;
01051             WidgetList *list = (WidgetList*)flow->widgetList();
01052 
01053             // save some special properties
01054             savePropertyElement(layout, domDoc, "property", "customLayout", Container::layoutTypeToString(item->container()->layoutType()) );
01055             savePropertyElement(layout, domDoc, "property", "justify", QVariant(static_cast<KexiFlowLayout*>(item->container()->layout())->isJustified(), 3) );
01056 
01057             // fill the widget's grid info, ie just simulate grid layout
01058             item->container()->createGridLayout(true);
01059             for(QWidget *obj = list->first(); obj; obj = list->next()) {
01060                 ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup(obj->name());
01061                 if(item)
01062                     saveWidget(titem, layout, domDoc, true); // save grid info for compatibility with QtDesigner
01063             }
01064             delete list;
01065             break;
01066         }
01067         default:
01068         {
01069             for(ObjectTreeItem *objIt = item->children()->first(); objIt; objIt = item->children()->next())
01070                 saveWidget(objIt, tclass, domDoc);
01071         }
01072     }
01073 
01074     addIncludeFileName(lib->includeFileName(item->widget()->className()), domDoc);
01075 
01076     if(resetCurrentForm)
01077         m_currentForm = 0;
01078     m_currentItem = 0;
01079 }
01080 
01081 void
01082 FormIO::cleanClipboard(QDomElement &uiElement)
01083 {
01084     // remove includehints element not needed
01085     if(!uiElement.namedItem("includehints").isNull())
01086         uiElement.removeChild(uiElement.namedItem("includehints"));
01087     // and ensure images and connection are at the end
01088     if(!uiElement.namedItem("connections").isNull())
01089         uiElement.insertAfter(uiElement.namedItem("connections"), QDomNode());
01090     if(!uiElement.namedItem("images").isNull())
01091         uiElement.insertAfter(uiElement.namedItem("images"), QDomNode());
01092 }
01093 
01094 void
01095 FormIO::loadWidget(Container *container, const QDomElement &el, QWidget *parent)
01096 {
01097     bool resetCurrentForm = false;
01098     if(!m_currentForm) // pasting widget
01099     {
01100         resetCurrentForm = true;
01101         m_currentForm = container->form();
01102     }
01103 
01104     // We first look for the widget's name
01105     QString wname;
01106     for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
01107     {
01108         if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
01109         {
01110             wname = n.toElement().text();
01111             break;
01112         }
01113     }
01114 
01115     QWidget *w;
01116     QCString classname, alternate;
01117     // We translate some name (for compatibility)
01118     if(el.tagName() == "spacer")
01119         classname = "Spring";
01120     else if(el.attribute("class") == "QLayoutWidget")
01121     {
01122         for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
01123         {
01124             QString tagName = n.toElement().tagName();
01125             if(tagName == "property")
01126                 continue;
01127             if(tagName == "hbox")
01128                 classname = "HBox";
01129             else if(tagName == "vbox")
01130                 classname = "VBox";
01131             else if(tagName == "grid") {
01132                 // first, see if it is flow layout
01133                 for(QDomNode child = n.firstChild(); !child.isNull(); child = child.nextSibling())  {
01134                     if((child.toElement().tagName() == "property") 
01135                         && (child.toElement().attribute("name") == "customLayout"))
01136                     {
01137                         classname = child.toElement().text().latin1();
01138                         break;
01139                     }
01140                 }
01141 
01142                 if(classname.isEmpty()) // normal grid
01143                     classname = "Grid";
01144             }
01145         }
01146     }
01147     else
01148     // We check if this classname is an alternate one, and replace it if necessary
01149     {
01150         classname = el.attribute("class").local8Bit();
01151         alternate = container->form()->library()->classNameForAlternate(classname);
01152     }
01153 
01154     if(alternate == "CustomWidget")
01155         w = new CustomWidget(classname, container->widget(), wname.latin1());
01156     else
01157     {
01158         if(!alternate.isNull())
01159             classname = alternate;
01160 
01161         int widgetOptions = WidgetFactory::DefaultOptions;
01162         if (!container->form()->designMode()) {
01163             widgetOptions ^= WidgetFactory::DesignViewMode;
01164         }
01165 
01166         if(!parent)
01167             w = container->form()->library()->createWidget(classname, container->widget(), 
01168                 wname.latin1(), container, widgetOptions);
01169         else
01170             w = container->form()->library()->createWidget(classname, parent, wname.latin1(), 
01171                 container, widgetOptions);
01172     }
01173 
01174     if(!w)
01175         return;
01176 #if KDE_VERSION >= KDE_MAKE_VERSION(3,4,0) 
01178     if (m_currentForm->designMode()) {
01179         //don't generate accelerators for widgets in design mode
01180         KAcceleratorManager::setNoAccel(w);
01181     }
01182 #endif
01183     w->setStyle(&(container->widget()->style()));
01184     w->show();
01185 
01186     // We create and insert the ObjectTreeItem at the good place in the ObjectTree
01187     ObjectTreeItem *item = container->form()->objectTree()->lookup(wname);
01188     if (!item)  {
01189         // not yet created
01190         item =  new ObjectTreeItem(container->form()->library()->displayName(classname), 
01191             wname, w, container);
01192         if(parent)  {
01193             ObjectTreeItem *titem = container->form()->objectTree()->lookup(parent->name());
01194             if(titem)
01195                 container->form()->objectTree()->addItem(titem, item);
01196             else
01197                 kdDebug() << "FORMIO :: ERROR no parent widget "  << endl;
01198         }
01199         else
01200             container->form()->objectTree()->addItem(container->objectTree(), item);
01201     }
01202     //assign item for its widget if it supports DesignTimeDynamicChildWidgetHandler interface
01203     //(e.g. KexiDBAutoField)
01204     if (container->form()->designMode() && dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)) {
01205         dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)->assignItem(item);
01206     }
01207 
01208     m_currentItem = item;
01209     // if we are inside a Grid, we need to insert the widget in the good cell
01210     if(container->layoutType() == Container::Grid)  {
01211         QGridLayout *layout = (QGridLayout*)container->layout();
01212         if(el.hasAttribute("rowspan")) { // widget spans multiple cells
01213             if(layout)
01214                 layout->addMultiCellWidget(w, el.attribute("row").toInt(), el.attribute("row").toInt() + el.attribute("rowspan").toInt()-1,
01215                      el.attribute("column").toInt(),  el.attribute("column").toInt() + el.attribute("colspan").toInt()-1);
01216              item->setGridPos(el.attribute("row").toInt(),  el.attribute("column").toInt(), el.attribute("rowspan").toInt(),
01217                el.attribute("colspan").toInt());
01218         }
01219         else  {
01220             if(layout)
01221                 layout->addWidget(w, el.attribute("row").toInt(), el.attribute("column").toInt());
01222             item->setGridPos(el.attribute("row").toInt(),  el.attribute("column").toInt(), 0, 0);
01223         }
01224     }
01225     else if(container->layout())
01226         container->layout()->add(w);
01227 
01228     readChildNodes(item, container, el, w);
01229 
01230     if(item->container() && item->container()->layout())
01231         item->container()->layout()->activate();
01232 
01233     // We add the autoSaveProperties in the modifProp list of the ObjectTreeItem, so that they are saved later
01234     QValueList<QCString> list(container->form()->library()->autoSaveProperties(w->className()));
01235     QValueList<QCString>::ConstIterator endIt = list.constEnd();
01236     for(QValueList<QCString>::ConstIterator it = list.constBegin(); it != endIt; ++it) {
01237         if(w->metaObject()->findProperty(*it, true) != -1)
01238             item->addModifiedProperty(*it, w->property(*it));
01239     }
01240 
01241     if(resetCurrentForm)
01242         m_currentForm = 0;
01243     m_currentItem = 0;
01244 }
01245 
01246 void
01247 FormIO::createToplevelWidget(Form *form, QWidget *container, QDomElement &el)
01248 {
01249     // We first look for the widget's name
01250     QString wname;
01251     for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
01252     {
01253         if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
01254         {
01255             wname = n.toElement().text();
01256             break;
01257         }
01258 
01259     }
01260     // And rename the widget and its ObjectTreeItem
01261     container->setName(wname.latin1());
01262     if(form->objectTree())
01263         form->objectTree()->rename(form->objectTree()->name(), wname);
01264     form->setInteractiveMode(false);
01265 
01266     QDict<QLabel>  *oldBuddies = 0;
01267     if(m_buddies)  // save old buddies (for subforms)
01268         oldBuddies = m_buddies;
01269     m_buddies = new QDict<QLabel>();
01270     m_currentItem = form->objectTree();
01271 
01272     readChildNodes(form->objectTree(), form->toplevelContainer(), el, container);
01273 
01274     // Now the Form is fully loaded, we can assign the buddies
01275     QDictIterator<QLabel> it(*m_buddies);
01276     for(; it.current(); ++it)
01277     {
01278         ObjectTreeItem *item = form->objectTree()->lookup(it.currentKey());
01279         if(!item || !item->widget())
01280         {
01281             kdDebug() << "Cannot assign buddy for widget " << it.current()->name() << " to " << it.currentKey() << endl;
01282             continue;
01283         }
01284         it.current()->setBuddy(item->widget());
01285     }
01286     delete m_buddies;
01287     m_buddies = oldBuddies; // and restore it
01288 
01289     m_currentItem = 0;
01290 
01291     form->setInteractiveMode(true);
01292 }
01293 
01294 void
01295 FormIO::readChildNodes(ObjectTreeItem *item, Container *container, const QDomElement &el, QWidget *w)
01296 {
01297     QString eltag = el.tagName();
01298 
01299     for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
01300     {
01301         QString tag = n.toElement().tagName();
01302         QDomElement node = n.toElement();
01303 
01304         if((tag == "property") || (tag == "attribute"))
01305         {
01306             QString name = node.attribute("name");
01307             //if(name == "geometry")
01308             //  hasGeometryProp = true;
01309             if( ((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
01310                   (name == "name")) // we don't care about layout names
01311                 continue;
01312 
01313             // We cannot assign the buddy now as the buddy widget may not be created yet
01314             if(name == "buddy")
01315                 m_buddies->insert(readPropertyValue(node.firstChild(), w, name).toString(), (QLabel*)w);
01316             else if(((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
01317               item->container() && item->container()->layout()) {
01318                 // We load the margin of a Layout
01319                  if(name == "margin")  {
01320                     int margin = readPropertyValue(node.firstChild(), w, name).toInt();
01321                     item->container()->setLayoutMargin(margin);
01322                     item->container()->layout()->setMargin(margin);
01323                 }
01324                 // We load the spacing of a Layout
01325                 else if(name == "spacing")  {
01326                     int spacing = readPropertyValue(node.firstChild(), w, name).toInt();
01327                     item->container()->setLayoutSpacing(spacing);
01328                     item->container()->layout()->setSpacing(spacing);
01329                 }
01330                 else if((name == "justify")){
01331                     bool justify = readPropertyValue(node.firstChild(), w, name).toBool();
01332                     KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
01333                     if(flow)
01334                         flow->setJustified(justify);
01335                 }
01336             }
01337             // If the object doesn't have this property, we let the Factory handle it (maybe a special property)
01338             else if(w->metaObject()->findProperty(name.latin1(), true) == -1)
01339             {
01340                 if(w->className() == QString::fromLatin1("CustomWidget"))
01341                     item->storeUnknownProperty(node);
01342                 else {
01343                     bool read = container->form()->library()->readSpecialProperty(
01344                         w->className(), node, w, item);
01345                     if(!read) // the factory doesn't support this property neither
01346                         item->storeUnknownProperty(node);
01347                 }
01348             }
01349             else // we have a normal property, let's load it
01350             {
01351                 QVariant val( readPropertyValue(node.firstChild(), w, name) );
01352                 if(name == "geometry" && dynamic_cast<FormWidget*>(w)) {
01353                     //fix geometry if needed - this is top level form widget
01354                     QRect r( val.toRect() );
01355                     if (r.left()<0) //negative X!
01356                         r.moveLeft(0);
01357                     if (r.top()<0) //negative Y!
01358                         r.moveTop(0);
01359                     val = r;
01360                 }
01361                 w->setProperty(name.latin1(), val);
01362 //              int count = w->metaObject()->findProperty(name, true);
01363 //              const QMetaProperty *meta = w->metaObject()->property(count, true);
01364 //              if(meta && meta->isEnumType()) {
01365 //                  val = w->property(name.latin1()); //update: we want a numeric value of enum
01366 //              }
01367                 item->addModifiedProperty(name.latin1(), val);
01368             }
01369         }
01370         else if(tag == "widget") // a child widget
01371         {
01372             if(item->container()) // we are a Container
01373                 loadWidget(item->container(), node);
01374             else
01375                 loadWidget(container, node, w);
01376         }
01377         else if(tag == "spacer")  {
01378             loadWidget(container, node, w);
01379         }
01380         else if(tag == "grid") {
01381             // first, see if it is flow layout
01382             QString layoutName;
01383             for(QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling())  {
01384                 if((child.toElement().tagName() == "property") && (child.toElement().attribute("name") == "customLayout"))  {
01385                     layoutName = child.toElement().text();
01386                     break;
01387                 }
01388             }
01389 
01390              if(layoutName == "HFlow") {
01391                 item->container()->m_layType = Container::HFlow;
01392                 KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
01393                 layout->setOrientation(Horizontal);
01394                 item->container()->m_layout = (QLayout*)layout;
01395             }
01396             else if(layoutName == "VFlow") {
01397                 item->container()->m_layType = Container::VFlow;
01398                 KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
01399                 layout->setOrientation(Vertical);
01400                 item->container()->m_layout = (QLayout*)layout;
01401             }
01402             else { // grid layout
01403                 item->container()->m_layType = Container::Grid;
01404                 QGridLayout *layout = new QGridLayout(item->widget(), 1, 1);
01405                 item->container()->m_layout = (QLayout*)layout;
01406             }
01407             readChildNodes(item, container, node, w);
01408         }
01409         else if(tag == "vbox")  {
01410             item->container()->m_layType = Container::VBox;
01411             QVBoxLayout *layout = new QVBoxLayout(item->widget());
01412             item->container()->m_layout = (QLayout*)layout;
01413             readChildNodes(item, container, node, w);
01414         }
01415         else if(tag == "hbox") {
01416             item->container()->m_layType = Container::HBox;
01417             QHBoxLayout *layout = new QHBoxLayout(item->widget());
01418             item->container()->m_layout = (QLayout*)layout;
01419             readChildNodes(item, container, node, w);
01420         }
01421         else {// unknown tag, we let the Factory handle it
01422             if(w->className() == QString::fromLatin1("CustomWidget"))
01423                 item->storeUnknownProperty(node);
01424             else {
01425                 bool read = container->form()->library()->readSpecialProperty(
01426                     w->className(), node, w, item);
01427                 if(!read) // the factory doesn't suport this property neither
01428                     item->storeUnknownProperty(node);
01429             }
01430         }
01431     }
01432 }
01433 
01437 
01438 void
01439 FormIO::addIncludeFileName(const QString &include, QDomDocument &domDoc)
01440 {
01441     if(include.isEmpty())
01442         return;
01443 
01444     QDomElement includes;
01445     QDomElement uiEl = domDoc.namedItem("UI").toElement();
01446     if(uiEl.namedItem("includehints").isNull())
01447     {
01448         includes = domDoc.createElement("includehints");
01449         uiEl.appendChild(includes);
01450     }
01451     else
01452         includes = uiEl.namedItem("includehints").toElement();
01453 
01454     // Check if this include has already been saved, and return if it is the case
01455     for(QDomNode n = includes.firstChild(); !n.isNull(); n = n.nextSibling())
01456     {
01457         if(n.toElement().text() == include)
01458             return;
01459     }
01460 
01461     QDomElement includeHint = domDoc.createElement("includehint");
01462     includes.appendChild(includeHint);
01463     QDomText includeText = domDoc.createTextNode(include);
01464     includeHint.appendChild(includeText);
01465 }
01466 
01468 
01469 QString
01470 FormIO::saveImage(QDomDocument &domDoc, const QPixmap &pixmap)
01471 {
01472     QDomNode node = domDoc.namedItem("images");
01473     QDomElement images;
01474     if(node.isNull())
01475     {
01476         images = domDoc.createElement("images");
01477         QDomElement ui = domDoc.namedItem("UI").toElement();
01478         ui.appendChild(images);
01479     }
01480     else
01481         images = node.toElement();
01482 
01483     int count = images.childNodes().count();
01484     QDomElement image = domDoc.createElement("image");
01485     QString name = "image" + QString::number(count);
01486     image.setAttribute("name", name);
01487 
01488     QImage img = pixmap.convertToImage();
01489     QByteArray ba;
01490     QBuffer buf(ba);
01491     buf.open( IO_WriteOnly | IO_Translate );
01492     QString format = img.depth() > 1 ? "XPM" : "XBM";
01493     QImageIO iio( &buf, format.latin1() );
01494     iio.setImage( img );
01495     iio.write();
01496     buf.close();
01497     QByteArray bazip = qCompress( ba );
01498     ulong len = bazip.size();
01499 
01500     QDomElement data = domDoc.createElement("data");
01501     data.setAttribute("format", format + ".GZ");
01502     data.setAttribute("length", ba.size());
01503 
01504     static const char hexchars[] = "0123456789abcdef";
01505     QString content;
01506     for(int i = 4; i < (int)len; ++i)
01507     {
01508     uchar s = (uchar) bazip[i];
01509     content += hexchars[s >> 4];
01510     content += hexchars[s & 0x0f];
01511     }
01512 
01513     QDomText text = domDoc.createTextNode(content);
01514     data.appendChild(text);
01515     image.appendChild(data);
01516     images.appendChild(image);
01517 
01518     return name;
01519 }
01520 
01521 QPixmap
01522 FormIO::loadImage(QDomDocument domDoc, const QString& name)
01523 {
01524     QDomElement images = domDoc.namedItem("UI").namedItem("images").toElement();
01525     if(images.isNull())
01526         return 0;
01527 
01528     QDomElement image;
01529     for(QDomNode n = images.firstChild(); !n.isNull(); n = n.nextSibling())
01530     {
01531         if((n.toElement().tagName() == "image") && (n.toElement().attribute("name") == name))
01532         {
01533             image = n.toElement();
01534             break;
01535         }
01536     }
01537 
01538     QPixmap pix;
01539     QString data = image.namedItem("data").toElement().text();
01540     const int lengthOffset = 4;
01541     int baSize = data.length() / 2 + lengthOffset;
01542     uchar *ba = new uchar[baSize];
01543     for(int i = lengthOffset; i < baSize; ++i)
01544     {
01545         char h = data[2 * (i-lengthOffset)].latin1();
01546         char l = data[2 * (i-lengthOffset) + 1].latin1();
01547         uchar r = 0;
01548         if(h <= '9')
01549             r += h - '0';
01550         else
01551             r += h - 'a' + 10;
01552         r = r << 4;
01553         if(l <= '9')
01554             r += l - '0';
01555         else
01556             r += l - 'a' + 10;
01557         ba[i] = r;
01558     }
01559 
01560     QString format = image.namedItem("data").toElement().attribute("format", "PNG");
01561     if((format == "XPM.GZ") || (format == "XBM.GZ"))
01562     {
01563         ulong len = image.attribute("length").toULong();
01564         if(len < data.length() * 5)
01565             len = data.length() * 5;
01566         // qUncompress() expects the first 4 bytes to be the expected length of
01567         // the uncompressed data
01568         ba[0] = ( len & 0xff000000 ) >> 24;
01569         ba[1] = ( len & 0x00ff0000 ) >> 16;
01570         ba[2] = ( len & 0x0000ff00 ) >> 8;
01571         ba[3] = ( len & 0x000000ff );
01572         QByteArray baunzip = qUncompress(ba, baSize);
01573         pix.loadFromData( (const uchar*)baunzip.data(), baunzip.size(), format.left(format.find('.')).latin1() );
01574     }
01575     else
01576         pix.loadFromData( (const uchar*)ba+lengthOffset, baSize-lengthOffset, format.latin1() );
01577 
01578     delete[] ba;
01579 
01580     return pix;
01581 }
01582 
01584 
01585 #include "formIO.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys