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-2007 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 #include "widgetwithsubpropertiesinterface.h"
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_DEBUG_GUI
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     WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(w);
00407     QWidget *subwidget = w;
00408     bool addSubwidgetFlag = false;
00409     int propertyId = w->metaObject()->findProperty(name, true);
00410     if (propertyId == -1 && subpropIface && subpropIface->subwidget()) { // try property from subwidget
00411         subwidget = subpropIface->subwidget();
00412         propertyId = subpropIface->subwidget()->metaObject()->findProperty(name, true);
00413         addSubwidgetFlag = true;
00414     }
00415     if(propertyId == -1)
00416     {
00417         kdDebug() << "FormIO::savePropertyValue()  The object doesn't have this property. Let's try the WidgetLibrary." << endl;
00418         if(lib)
00419             lib->saveSpecialProperty(w->className(), name, value, w, parentNode, parent);
00420         return;
00421     }
00422 
00423     const QMetaProperty *meta = subwidget->metaObject()->property(propertyId, true);
00424     if (!meta->stored( subwidget )) //not storable
00425         return;
00426     QDomElement propertyE = parent.createElement("property");
00427     propertyE.setAttribute("name", name);
00428     if (addSubwidgetFlag)
00429         propertyE.setAttribute("subwidget", "true");
00430 
00431     if(meta && meta->isEnumType())
00432     {
00433         // this property is enum or set type
00434         QDomElement type;
00435         QDomText valueE;
00436 
00437         if(meta->isSetType())
00438         {
00439             QStringList list = QStringList::fromStrList(meta->valueToKeys(value.toInt()));
00440             type = parent.createElement("set");
00441             valueE = parent.createTextNode(list.join("|"));
00442             type.appendChild(valueE);
00443         }
00444         else
00445         {
00446             QString s = meta->valueToKey(value.toInt());
00447             type = parent.createElement("enum");
00448             valueE = parent.createTextNode(s);
00449             type.appendChild(valueE);
00450         }
00451         propertyE.appendChild(type);
00452         parentNode.appendChild(propertyE);
00453         return;
00454     }
00455 
00456     if(value.type() == QVariant::Pixmap) {
00457         QDomText valueE;
00458         QDomElement type = parent.createElement("pixmap");
00459         QCString property = propertyE.attribute("name").latin1();
00460 //todo      QCString pixmapName = m_currentItem->widget()->property("pixmapName").toCString();
00461         if(m_savePixmapsInline /* (js)too risky: || m_currentItem->pixmapName(property).isNull() */)
00462             valueE = parent.createTextNode(saveImage(parent, value.toPixmap()));
00463         else
00464             valueE = parent.createTextNode(m_currentItem->pixmapName(property));
00465         type.appendChild(valueE);
00466         propertyE.appendChild(type);
00467         parentNode.appendChild(propertyE);
00468         return;
00469     }
00470 
00471     // Saving a "normal" property
00472     writeVariant(parent, propertyE, value);
00473     parentNode.appendChild(propertyE);
00474 }
00475 
00476 void
00477 FormIO::writeVariant(QDomDocument &parent, QDomElement &parentNode, QVariant value)
00478 {
00479     QDomElement type;
00480     QDomText valueE;
00481 
00482     switch(value.type())
00483     {
00484         case QVariant::String:
00485         {
00486             type = parent.createElement("string");
00487             valueE = parent.createTextNode(value.toString());
00488             type.appendChild(valueE);
00489             break;
00490         }
00491         case QVariant::CString:
00492         {
00493             type = parent.createElement("cstring");
00494             valueE = parent.createTextNode(value.toString());
00495             type.appendChild(valueE);
00496             break;
00497         }
00498         case QVariant::Rect:
00499         {
00500             type = parent.createElement("rect");
00501             QDomElement x = parent.createElement("x");
00502             QDomElement y = parent.createElement("y");
00503             QDomElement w = parent.createElement("width");
00504             QDomElement h = parent.createElement("height");
00505             QDomText valueX = parent.createTextNode(QString::number(value.toRect().x()));
00506             QDomText valueY = parent.createTextNode(QString::number(value.toRect().y()));
00507             QDomText valueW = parent.createTextNode(QString::number(value.toRect().width()));
00508             QDomText valueH = parent.createTextNode(QString::number(value.toRect().height()));
00509 
00510             x.appendChild(valueX);
00511             y.appendChild(valueY);
00512             w.appendChild(valueW);
00513             h.appendChild(valueH);
00514 
00515             type.appendChild(x);
00516             type.appendChild(y);
00517             type.appendChild(w);
00518             type.appendChild(h);
00519             break;
00520         }
00521         case QVariant::Color:
00522         {
00523             type = parent.createElement("color");
00524             QDomElement r = parent.createElement("red");
00525             QDomElement g = parent.createElement("green");
00526             QDomElement b = parent.createElement("blue");
00527             QDomText valueR = parent.createTextNode(QString::number(value.toColor().red()));
00528             QDomText valueG = parent.createTextNode(QString::number(value.toColor().green()));
00529             QDomText valueB = parent.createTextNode(QString::number(value.toColor().blue()));
00530 
00531             r.appendChild(valueR);
00532             g.appendChild(valueG);
00533             b.appendChild(valueB);
00534 
00535             type.appendChild(r);
00536             type.appendChild(g);
00537             type.appendChild(b);
00538             break;
00539         }
00540         case QVariant::Bool:
00541         {
00542             type = parent.createElement("bool");
00543             //valueE = parent.createTextNode(QString::number(value.toBool()));
00544             valueE = parent.createTextNode(value.toBool() ? "true" : "false");
00545             type.appendChild(valueE);
00546             break;
00547         }
00548         case QVariant::Int:
00549         case QVariant::UInt:
00550         {
00551             type = parent.createElement("number");
00552             valueE = parent.createTextNode(QString::number(value.toInt()));
00553             type.appendChild(valueE);
00554             break;
00555         }
00556         case QVariant::Size:
00557         {
00558             type = parent.createElement("size");
00559             QDomElement w = parent.createElement("width");
00560             QDomElement h = parent.createElement("height");
00561             QDomText valueW = parent.createTextNode(QString::number(value.toSize().width()));
00562             QDomText valueH = parent.createTextNode(QString::number(value.toSize().height()));
00563 
00564             w.appendChild(valueW);
00565             h.appendChild(valueH);
00566 
00567             type.appendChild(w);
00568             type.appendChild(h);
00569             break;
00570         }
00571         case QVariant::Point:
00572         {
00573             type = parent.createElement("point");
00574             QDomElement x = parent.createElement("x");
00575             QDomElement y = parent.createElement("y");
00576             QDomText valueX = parent.createTextNode(QString::number(value.toPoint().x()));
00577             QDomText valueY = parent.createTextNode(QString::number(value.toPoint().y()));
00578 
00579             x.appendChild(valueX);
00580             y.appendChild(valueY);
00581 
00582             type.appendChild(x);
00583             type.appendChild(y);
00584             break;
00585         }
00586         case QVariant::Font:
00587         {
00588             type = parent.createElement("font");
00589             QDomElement f = parent.createElement("family");
00590             QDomElement p = parent.createElement("pointsize");
00591             QDomElement w = parent.createElement("weight");
00592             QDomElement b = parent.createElement("bold");
00593             QDomElement i = parent.createElement("italic");
00594             QDomElement u = parent.createElement("underline");
00595             QDomElement s = parent.createElement("strikeout");
00596             QDomText valueF = parent.createTextNode(value.toFont().family());
00597             QDomText valueP = parent.createTextNode(QString::number(value.toFont().pointSize()));
00598             QDomText valueW = parent.createTextNode(QString::number(value.toFont().weight()));
00599             QDomText valueB = parent.createTextNode(QString::number(value.toFont().bold()));
00600             QDomText valueI = parent.createTextNode(QString::number(value.toFont().italic()));
00601             QDomText valueU = parent.createTextNode(QString::number(value.toFont().underline()));
00602             QDomText valueS = parent.createTextNode(QString::number(value.toFont().strikeOut()));
00603 
00604             f.appendChild(valueF);
00605             p.appendChild(valueP);
00606             w.appendChild(valueW);
00607             b.appendChild(valueB);
00608             i.appendChild(valueI);
00609             u.appendChild(valueU);
00610             s.appendChild(valueS);
00611 
00612             type.appendChild(f);
00613             type.appendChild(p);
00614             type.appendChild(w);
00615             type.appendChild(b);
00616             type.appendChild(i);
00617             type.appendChild(u);
00618             type.appendChild(s);
00619             break;
00620         }
00621         case QVariant::Cursor:
00622         {
00623             type = parent.createElement("cursor");
00624             valueE = parent.createTextNode(QString::number(value.toCursor().shape()));
00625             type.appendChild(valueE);
00626             break;
00627         }
00628         case QVariant::SizePolicy:
00629         {
00630             type = parent.createElement("sizepolicy");
00631             QDomElement h = parent.createElement("hsizetype");
00632             QDomElement v = parent.createElement("vsizetype");
00633             QDomElement hs = parent.createElement("horstretch");
00634             QDomElement vs = parent.createElement("verstretch");
00635             QDomText valueH = parent.createTextNode(QString::number(value.toSizePolicy().horData()));
00636             QDomText valueV = parent.createTextNode(QString::number(value.toSizePolicy().verData()));
00637             QDomText valueHS = parent.createTextNode(QString::number(value.toSizePolicy().horStretch()));
00638             QDomText valueVS = parent.createTextNode(QString::number(value.toSizePolicy().verStretch()));
00639 
00640             h.appendChild(valueH);
00641             v.appendChild(valueV);
00642             hs.appendChild(valueHS);
00643             vs.appendChild(valueVS);
00644 
00645             type.appendChild(h);
00646             type.appendChild(v);
00647             type.appendChild(hs);
00648             type.appendChild(vs);
00649             break;
00650         }
00651         case QVariant::Time:
00652         {
00653             type = parent.createElement("time");
00654             QDomElement h = parent.createElement("hour");
00655             QDomElement m = parent.createElement("minute");
00656             QDomElement s = parent.createElement("second");
00657             QDomText valueH = parent.createTextNode(QString::number(value.toTime().hour()));
00658             QDomText valueM = parent.createTextNode(QString::number(value.toTime().minute()));
00659             QDomText valueS = parent.createTextNode(QString::number(value.toTime().second()));
00660 
00661             h.appendChild(valueH);
00662             m.appendChild(valueM);
00663             s.appendChild(valueS);
00664 
00665             type.appendChild(h);
00666             type.appendChild(m);
00667             type.appendChild(s);
00668             break;
00669         }
00670         case QVariant::Date:
00671         {
00672             type = parent.createElement("date");
00673             QDomElement y = parent.createElement("year");
00674             QDomElement m = parent.createElement("month");
00675             QDomElement d = parent.createElement("day");
00676             QDomText valueY = parent.createTextNode(QString::number(value.toDate().year()));
00677             QDomText valueM = parent.createTextNode(QString::number(value.toDate().month()));
00678             QDomText valueD = parent.createTextNode(QString::number(value.toDate().day()));
00679 
00680             y.appendChild(valueY);
00681             m.appendChild(valueM);
00682             d.appendChild(valueD);
00683 
00684             type.appendChild(y);
00685             type.appendChild(m);
00686             type.appendChild(d);
00687             break;
00688         }
00689         case QVariant::DateTime:
00690         {
00691             type = parent.createElement("datetime");
00692             QDomElement h = parent.createElement("hour");
00693             QDomElement m = parent.createElement("minute");
00694             QDomElement s = parent.createElement("second");
00695             QDomElement y = parent.createElement("year");
00696             QDomElement mo = parent.createElement("month");
00697             QDomElement d = parent.createElement("day");
00698             QDomText valueH = parent.createTextNode(QString::number(value.toDateTime().time().hour()));
00699             QDomText valueM = parent.createTextNode(QString::number(value.toDateTime().time().minute()));
00700             QDomText valueS = parent.createTextNode(QString::number(value.toDateTime().time().second()));
00701             QDomText valueY = parent.createTextNode(QString::number(value.toDateTime().date().year()));
00702             QDomText valueMo = parent.createTextNode(QString::number(value.toDateTime().date().month()));
00703             QDomText valueD = parent.createTextNode(QString::number(value.toDateTime().date().day()));
00704 
00705             h.appendChild(valueH);
00706             m.appendChild(valueM);
00707             s.appendChild(valueS);
00708             y.appendChild(valueY);
00709             mo.appendChild(valueMo);
00710             d.appendChild(valueD);
00711 
00712             type.appendChild(h);
00713             type.appendChild(m);
00714             type.appendChild(s);
00715             type.appendChild(y);
00716             type.appendChild(mo);
00717             type.appendChild(d);
00718             break;
00719         }
00720         default:
00721             break;
00722     }
00723 
00724     parentNode.appendChild(type);
00725 }
00726 
00727 void
00728 FormIO::savePropertyElement(QDomElement &parentNode, QDomDocument &domDoc, const QString &tagName, const QString &property, const QVariant &value)
00729 {
00730     QDomElement propertyE = domDoc.createElement(tagName);
00731     propertyE.setAttribute("name", property);
00732     writeVariant(domDoc, propertyE, value);
00733     parentNode.appendChild(propertyE);
00734 }
00735 
00736 QVariant
00737 FormIO::readPropertyValue(QDomNode node, QObject *obj, const QString &name)
00738 {
00739     QDomElement tag = node.toElement();
00740     QString text = tag.text();
00741     QString type = tag.tagName();
00742 
00743     if(type == "string" || type == "cstring")
00744         return text;
00745     else if(type == "rect")
00746     {
00747         QDomElement x = node.namedItem("x").toElement();
00748         QDomElement y = node.namedItem("y").toElement();
00749         QDomElement w = node.namedItem("width").toElement();
00750         QDomElement h = node.namedItem("height").toElement();
00751 
00752         int rx = x.text().toInt();
00753         int ry = y.text().toInt();
00754         int rw = w.text().toInt();
00755         int rh = h.text().toInt();
00756 
00757         return QRect(rx, ry, rw, rh);
00758     }
00759     else if(type == "color")
00760     {
00761         QDomElement r = node.namedItem("red").toElement();
00762         QDomElement g = node.namedItem("green").toElement();
00763         QDomElement b = node.namedItem("blue").toElement();
00764 
00765         int red = r.text().toInt();
00766         int green = g.text().toInt();
00767         int blue = b.text().toInt();
00768 
00769         return QColor(red, green, blue);
00770     }
00771     else if(type == "bool")
00772     {
00773         if(text == "true")
00774             return QVariant(true, 3);
00775         else if(text == "false")
00776             return QVariant(false, 3);
00777         return QVariant(text.toInt(), 3);
00778     }
00779     else if(type == "number")
00780     {
00781         return text.toInt();
00782     }
00783     else if(type == "size")
00784     {
00785         QDomElement w = node.namedItem("width").toElement();
00786         QDomElement h = node.namedItem("height").toElement();
00787 
00788         return QSize(w.text().toInt(), h.text().toInt());
00789     }
00790     else if(type == "point")
00791     {
00792         QDomElement x = node.namedItem("x").toElement();
00793         QDomElement y = node.namedItem("y").toElement();
00794 
00795         return QPoint(x.text().toInt(), y.text().toInt());
00796     }
00797     else if(type == "font")
00798     {
00799         QDomElement fa = node.namedItem("family").toElement();
00800         QDomElement p = node.namedItem("pointsize").toElement();
00801         QDomElement w = node.namedItem("weight").toElement();
00802         QDomElement b = node.namedItem("bold").toElement();
00803         QDomElement i = node.namedItem("italic").toElement();
00804         QDomElement u = node.namedItem("underline").toElement();
00805         QDomElement s = node.namedItem("strikeout").toElement();
00806 
00807         QFont f;
00808         f.setFamily(fa.text());
00809         f.setPointSize(p.text().toInt());
00810         f.setWeight(w.text().toInt());
00811         f.setBold(b.text().toInt());
00812         f.setItalic(i.text().toInt());
00813         f.setUnderline(u.text().toInt());
00814         f.setStrikeOut(s.text().toInt());
00815 
00816         return f;
00817     }
00818     else if(type == "cursor")
00819     {
00820         return QCursor(text.toInt());
00821     }
00822     else if(type == "time")
00823     {
00824         QDomElement h = node.namedItem("hour").toElement();
00825         QDomElement m = node.namedItem("minute").toElement();
00826         QDomElement s = node.namedItem("second").toElement();
00827 
00828         return QTime(h.text().toInt(), m.text().toInt(), s.text().toInt());
00829     }
00830     else if(type == "date")
00831     {
00832         QDomElement y = node.namedItem("year").toElement();
00833         QDomElement m = node.namedItem("month").toElement();
00834         QDomElement d = node.namedItem("day").toElement();
00835 
00836         return QDate(y.text().toInt(), m.text().toInt(), d.text().toInt());
00837     }
00838     else if(type == "datetime")
00839     {
00840         QDomElement h = node.namedItem("hour").toElement();
00841         QDomElement m = node.namedItem("minute").toElement();
00842         QDomElement s = node.namedItem("second").toElement();
00843         QDomElement y = node.namedItem("year").toElement();
00844         QDomElement mo = node.namedItem("month").toElement();
00845         QDomElement d = node.namedItem("day").toElement();
00846 
00847         QTime t(h.text().toInt(), m.text().toInt(), s.text().toInt());
00848         QDate da(y.text().toInt(), mo.text().toInt(), d.text().toInt());
00849 
00850         return QDateTime(da, t);
00851     }
00852     else if(type == "sizepolicy")
00853     {
00854         QDomElement h = node.namedItem("hsizetype").toElement();
00855         QDomElement v = node.namedItem("vsizetype").toElement();
00856         QDomElement hs = node.namedItem("horstretch").toElement();
00857         QDomElement vs = node.namedItem("verstretch").toElement();
00858 
00859         QSizePolicy s;
00860         s.setHorData((QSizePolicy::SizeType)h.text().toInt());
00861         s.setVerData((QSizePolicy::SizeType)v.text().toInt());
00862         s.setHorStretch(hs.text().toInt());
00863         s.setVerStretch(vs.text().toInt());
00864         return s;
00865     }
00866     else if(type == "pixmap")
00867     {
00868         if(m_savePixmapsInline || !m_currentForm || !m_currentItem || !m_currentForm->pixmapCollection()->contains(text))
00869             return loadImage(tag.ownerDocument(), text);
00870         else
00871         {
00872             m_currentItem->setPixmapName(name.latin1(), text);
00873             return m_currentForm->pixmapCollection()->getPixmap(text);
00874         }
00875         return QVariant(QPixmap());
00876     }
00877     else if(type == "enum")
00878         return text;
00879     else if(type == "set")
00880     {
00881         WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(obj);
00882         QObject *subobject = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : obj;
00883         const int count = subobject->metaObject()->findProperty(name.latin1(), true);
00884         const QMetaProperty *meta = count!=-1 ? subobject->metaObject()->property(count, true) : 0;
00885 
00886         if (meta) {
00887             if (meta->isSetType()) {
00888                 QStrList keys;
00889                 const QStringList list( QStringList::split("|", text) );
00890                 for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
00891                     keys.append((*it).latin1());
00892 
00893                 return meta->keysToValue(keys);
00894             }
00895         }
00896         else {
00897             // Metaproperty not found, probably because subwidget is not created.
00898             // We will return a string list here with hope that names will 
00899             // be resolved and translated into an integer value later when subwidget is created,
00900             // e.g. near KexiFormView::updateValuesForSubproperties()
00901             return QStringList::split("|", text);
00902         }
00903     }
00904     return QVariant();
00905 }
00906 
00910 
00911 void
00912 FormIO::saveWidget(ObjectTreeItem *item, QDomElement &parent, QDomDocument &domDoc, bool insideGridLayout)
00913 {
00914     if (!item)
00915         return;
00916     bool savedAlignment = false;
00917     // we let Spring class handle saving itself
00918     if(item->className() == "Spring")
00919     {
00920         Spring::saveSpring(item, parent, domDoc, insideGridLayout);
00921         return;
00922     }
00923 
00924     bool resetCurrentForm = false;
00925     m_currentItem = item;
00926     if(!m_currentForm) // copying widget
00927     {
00928         resetCurrentForm = true;
00929         m_currentForm = item->container() ? item->container()->form() : item->parent()->container()->form();
00930     }
00931 
00932 
00933     WidgetLibrary *lib = m_currentForm->library();
00934 //  if(item->container())
00935 //      lib = item->container()->form()->manager()->lib();
00936 //  else
00937 //      lib = item->parent()->container()->form()->manager()->lib();
00938 
00939     // We create the "widget" element
00940     QDomElement tclass = domDoc.createElement("widget");
00941     parent.appendChild(tclass);
00942 
00943     if(insideGridLayout)
00944     {
00945         tclass.setAttribute("row", item->gridRow());
00946         tclass.setAttribute("column", item->gridCol());
00947         if(item->spanMultipleCells())
00948         {
00949             tclass.setAttribute("rowspan", item->gridRowSpan());
00950             tclass.setAttribute("colspan", item->gridColSpan());
00951         }
00952     }
00953 
00954     if(!item->parent()) // Toplevel widget
00955         tclass.setAttribute("class", "QWidget");
00956     // For compatibility, HBox, VBox and Grid are saved as "QLayoutWidget"
00957     else if(item->widget()->isA("HBox") || item->widget()->isA("VBox") || item->widget()->isA("Grid")
00958             || item->widget()->isA("HFlow") || item->widget()->isA("VFlow"))
00959         tclass.setAttribute("class", "QLayoutWidget");
00960     else if(item->widget()->isA("CustomWidget"))
00961         tclass.setAttribute("class", item->className());
00962     else // Normal widgets
00963         tclass.setAttribute("class", lib->savingName(item->widget()->className()) );
00964 
00965     savePropertyValue(tclass, domDoc, "name", item->widget()->property("name"), item->widget());
00966 
00967     // Important: save dataSource property FIRST before properties like "alignment"
00968     // - needed when subproperties are defined after subwidget creation, and subwidget is created after setting "dataSource"
00969     //   (this is the case for KexiDBAutoField)
00971 //  if (-1 != item->widget()->metaObject()->findProperty("dataSource"))
00972     //  savePropertyValue(tclass, domDoc, "dataSource", item->widget()->property("dataSource"), item->widget());
00973 
00974     // We don't want to save the geometry if the widget is inside a layout (so parent.tagName() == "grid" for example)
00975     if(item && !item->parent()) {
00976         // save form widget size, but not its position
00977         savePropertyValue(tclass, domDoc, "geometry",
00978             QRect( QPoint(0,0), item->widget()->size()),
00979             item->widget());
00980     }
00981     // normal widget (if == "UI', it means we're copying widget)
00982     else if(parent.tagName() == "widget" || parent.tagName() == "UI")
00983         savePropertyValue(tclass, domDoc, "geometry", item->widget()->property("geometry"), item->widget());
00984 
00985     // Save the buddy widget for a label
00986     if(item->widget()->inherits("QLabel") && ((QLabel*)item->widget())->buddy())
00987         savePropertyElement(tclass, domDoc, "property", "buddy", ((QLabel*)item->widget())->buddy()->name());
00988 
00989     // We save every property in the modifProp list of the ObjectTreeItem
00990     QVariantMap *map = new QVariantMap( *(item->modifiedProperties()) );
00991     QMap<QString,QVariant>::ConstIterator endIt = map->constEnd();
00992     for(QMap<QString,QVariant>::ConstIterator it = map->constBegin(); it != endIt; ++it)
00993     {
00994         const QCString name( it.key().latin1() );
00995         if(name == "hAlign" || name == "vAlign" || name == "wordbreak" || name == "alignment") {
00996             if(!savedAlignment) // not to save it twice
00997             {
00998                 savePropertyValue(tclass, domDoc, "alignment", item->widget()->property("alignment"), item->widget());
00999                 savedAlignment = true;
01000             }
01001         }
01002         else if(name == "name" || name == "geometry" || name == "layout") {
01003             // these have already been saved
01004         }
01005         else {
01006             savePropertyValue(tclass, domDoc, it.key().latin1(), item->widget()->property(it.key().latin1()), 
01007                 item->widget(), lib);
01008         }
01009     }
01010     delete map;
01011 
01012     if(item->widget()->isA("CustomWidget")) {
01013         QDomDocument doc("TEMP");
01014         doc.setContent(item->m_unknownProps);
01015         for(QDomNode n = doc.firstChild(); !n.isNull(); n = n.nextSibling()) {
01016             tclass.appendChild(n.cloneNode());
01017         }
01018 
01019     }
01020     // Saving container 's layout if there is one
01021     QDomElement layout;
01022     if(item->container() && item->container()->layoutType() != Container::NoLayout)
01023     {
01024         if(item->container()->layout()) // there is a layout
01025         {
01026             layout = domDoc.createElement("temp");
01027             savePropertyValue(layout, domDoc, "name", "unnamed", item->widget());
01028             if(item->modifiedProperties()->contains("layoutMargin"))
01029                 savePropertyElement(layout, domDoc, "property", "margin", item->container()->layoutMargin());
01030             if(item->modifiedProperties()->contains("layoutSpacing"))
01031                 savePropertyElement(layout, domDoc, "property", "spacing", item->container()->layoutSpacing());
01032             tclass.appendChild(layout);
01033         }
01034     }
01035 
01036     int layoutType = item->container() ? item->container()->layoutType() : Container::NoLayout;
01037     switch(layoutType) {
01038         case Container::Grid: // grid layout
01039         {
01040             layout.setTagName("grid");
01041             for(ObjectTreeItem *objIt = item->children()->first(); objIt; objIt = item->children()->next())
01042                 saveWidget(objIt, layout, domDoc, true);
01043             break;
01044         }
01045         case Container::HBox: case Container::VBox:
01046         {
01047             // as we don't save geometry, we need to sort widgets in the right order, not creation order
01048             WidgetList *list;
01049             if(layout.tagName() == "hbox") {
01050                 list = new HorWidgetList(item->container()->form()->toplevelContainer()->widget());
01051                 layout.setTagName("hbox");
01052             }
01053             else {
01054                 list = new VerWidgetList(item->container()->form()->toplevelContainer()->widget());
01055                 layout.setTagName("vbox");
01056             }
01057 
01058             for(ObjectTreeItem *objTree = item->children()->first(); objTree; objTree = item->children()->next())
01059                 list->append(objTree->widget());
01060             list->sort();
01061 
01062             for(QWidget *obj = list->first(); obj; obj = list->next()) {
01063                 ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup(obj->name());
01064                 if(item)
01065                     saveWidget(titem, layout, domDoc);
01066             }
01067             delete list;
01068             break;
01069         }
01070         case Container::HFlow: case Container::VFlow:
01071         {
01072             layout.setTagName("grid");
01073             KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
01074             if(!flow)  break;
01075             WidgetList *list = (WidgetList*)flow->widgetList();
01076 
01077             // save some special properties
01078             savePropertyElement(layout, domDoc, "property", "customLayout", Container::layoutTypeToString(item->container()->layoutType()) );
01079             savePropertyElement(layout, domDoc, "property", "justify", QVariant(static_cast<KexiFlowLayout*>(item->container()->layout())->isJustified(), 3) );
01080 
01081             // fill the widget's grid info, ie just simulate grid layout
01082             item->container()->createGridLayout(true);
01083             for(QWidget *obj = list->first(); obj; obj = list->next()) {
01084                 ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup(obj->name());
01085                 if(item)
01086                     saveWidget(titem, layout, domDoc, true); // save grid info for compatibility with QtDesigner
01087             }
01088             delete list;
01089             break;
01090         }
01091         default:
01092         {
01093             for(ObjectTreeItem *objIt = item->children()->first(); objIt; objIt = item->children()->next())
01094                 saveWidget(objIt, tclass, domDoc);
01095         }
01096     }
01097 
01098     addIncludeFileName(lib->includeFileName(item->widget()->className()), domDoc);
01099 
01100     if(resetCurrentForm)
01101         m_currentForm = 0;
01102     m_currentItem = 0;
01103 }
01104 
01105 void
01106 FormIO::cleanClipboard(QDomElement &uiElement)
01107 {
01108     // remove includehints element not needed
01109     if(!uiElement.namedItem("includehints").isNull())
01110         uiElement.removeChild(uiElement.namedItem("includehints"));
01111     // and ensure images and connection are at the end
01112     if(!uiElement.namedItem("connections").isNull())
01113         uiElement.insertAfter(uiElement.namedItem("connections"), QDomNode());
01114     if(!uiElement.namedItem("images").isNull())
01115         uiElement.insertAfter(uiElement.namedItem("images"), QDomNode());
01116 }
01117 
01118 void
01119 FormIO::loadWidget(Container *container, const QDomElement &el, QWidget *parent)
01120 {
01121     bool resetCurrentForm = false;
01122     if(!m_currentForm) // pasting widget
01123     {
01124         resetCurrentForm = true;
01125         m_currentForm = container->form();
01126     }
01127 
01128     // We first look for the widget's name
01129     QString wname;
01130     for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
01131     {
01132         if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
01133         {
01134             wname = n.toElement().text();
01135             break;
01136         }
01137     }
01138 
01139     QWidget *w;
01140     QCString classname, alternate;
01141     // We translate some name (for compatibility)
01142     if(el.tagName() == "spacer")
01143         classname = "Spring";
01144     else if(el.attribute("class") == "QLayoutWidget")
01145     {
01146         for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
01147         {
01148             QString tagName = n.toElement().tagName();
01149             if(tagName == "property")
01150                 continue;
01151             if(tagName == "hbox")
01152                 classname = "HBox";
01153             else if(tagName == "vbox")
01154                 classname = "VBox";
01155             else if(tagName == "grid") {
01156                 // first, see if it is flow layout
01157                 for(QDomNode child = n.firstChild(); !child.isNull(); child = child.nextSibling())  {
01158                     if((child.toElement().tagName() == "property") 
01159                         && (child.toElement().attribute("name") == "customLayout"))
01160                     {
01161                         classname = child.toElement().text().latin1();
01162                         break;
01163                     }
01164                 }
01165 
01166                 if(classname.isEmpty()) // normal grid
01167                     classname = "Grid";
01168             }
01169         }
01170     }
01171     else
01172     // We check if this classname is an alternate one, and replace it if necessary
01173     {
01174         classname = el.attribute("class").latin1();
01175         alternate = container->form()->library()->classNameForAlternate(classname);
01176     }
01177 
01178     if(alternate == "CustomWidget")
01179         w = new CustomWidget(classname, container->widget(), wname.latin1());
01180     else
01181     {
01182         if(!alternate.isNull())
01183             classname = alternate;
01184 
01185         int widgetOptions = WidgetFactory::DefaultOptions;
01186         if (!container->form()->designMode()) {
01187             widgetOptions ^= WidgetFactory::DesignViewMode;
01188         }
01189 
01190         if(!parent)
01191             w = container->form()->library()->createWidget(classname, container->widget(), 
01192                 wname.latin1(), container, widgetOptions);
01193         else
01194             w = container->form()->library()->createWidget(classname, parent, wname.latin1(), 
01195                 container, widgetOptions);
01196     }
01197 
01198     if(!w)
01199         return;
01200 #if KDE_VERSION >= KDE_MAKE_VERSION(3,4,0) 
01202     if (m_currentForm->designMode()) {
01203         //don't generate accelerators for widgets in design mode
01204         KAcceleratorManager::setNoAccel(w);
01205     }
01206 #endif
01207     w->setStyle(&(container->widget()->style()));
01208     w->show();
01209 
01210     // We create and insert the ObjectTreeItem at the good place in the ObjectTree
01211     ObjectTreeItem *item = container->form()->objectTree()->lookup(wname);
01212     if (!item)  {
01213         // not yet created
01214         item =  new ObjectTreeItem(container->form()->library()->displayName(classname), 
01215             wname, w, container);
01216         if(parent)  {
01217             ObjectTreeItem *titem = container->form()->objectTree()->lookup(parent->name());
01218             if(titem)
01219                 container->form()->objectTree()->addItem(titem, item);
01220             else
01221                 kdDebug() << "FORMIO :: ERROR no parent widget "  << endl;
01222         }
01223         else
01224             container->form()->objectTree()->addItem(container->objectTree(), item);
01225     }
01226     //assign item for its widget if it supports DesignTimeDynamicChildWidgetHandler interface
01227     //(e.g. KexiDBAutoField)
01228     if (container->form()->designMode() && dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)) {
01229         dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)->assignItem(item);
01230     }
01231 
01232     m_currentItem = item;
01233     // if we are inside a Grid, we need to insert the widget in the good cell
01234     if(container->layoutType() == Container::Grid)  {
01235         QGridLayout *layout = (QGridLayout*)container->layout();
01236         if(el.hasAttribute("rowspan")) { // widget spans multiple cells
01237             if(layout)
01238                 layout->addMultiCellWidget(w, el.attribute("row").toInt(), el.attribute("row").toInt() + el.attribute("rowspan").toInt()-1,
01239                      el.attribute("column").toInt(),  el.attribute("column").toInt() + el.attribute("colspan").toInt()-1);
01240              item->setGridPos(el.attribute("row").toInt(),  el.attribute("column").toInt(), el.attribute("rowspan").toInt(),
01241                el.attribute("colspan").toInt());
01242         }
01243         else  {
01244             if(layout)
01245                 layout->addWidget(w, el.attribute("row").toInt(), el.attribute("column").toInt());
01246             item->setGridPos(el.attribute("row").toInt(),  el.attribute("column").toInt(), 0, 0);
01247         }
01248     }
01249     else if(container->layout())
01250         container->layout()->add(w);
01251 
01252     readChildNodes(item, container, el, w);
01253 
01254     if(item->container() && item->container()->layout())
01255         item->container()->layout()->activate();
01256 
01257     // We add the autoSaveProperties in the modifProp list of the ObjectTreeItem, so that they are saved later
01258     QValueList<QCString> list(container->form()->library()->autoSaveProperties(w->className()));
01259     QValueList<QCString>::ConstIterator endIt = list.constEnd();
01260     KFormDesigner::WidgetWithSubpropertiesInterface* subpropIface 
01261         = dynamic_cast<KFormDesigner::WidgetWithSubpropertiesInterface*>(w);
01262     QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;
01263     for(QValueList<QCString>::ConstIterator it = list.constBegin(); it != endIt; ++it) {
01264         if(subwidget->metaObject()->findProperty(*it, true) != -1)
01265             item->addModifiedProperty(*it, subwidget->property(*it));
01266     }
01267 
01268     if(resetCurrentForm)
01269         m_currentForm = 0;
01270     m_currentItem = 0;
01271 }
01272 
01273 void
01274 FormIO::createToplevelWidget(Form *form, QWidget *container, QDomElement &el)
01275 {
01276     // We first look for the widget's name
01277     QString wname;
01278     for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
01279     {
01280         if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
01281         {
01282             wname = n.toElement().text();
01283             break;
01284         }
01285 
01286     }
01287     // And rename the widget and its ObjectTreeItem
01288     container->setName(wname.latin1());
01289     if(form->objectTree())
01290         form->objectTree()->rename(form->objectTree()->name(), wname);
01291     form->setInteractiveMode(false);
01292 
01293     QDict<QLabel>  *oldBuddies = 0;
01294     if(m_buddies)  // save old buddies (for subforms)
01295         oldBuddies = m_buddies;
01296     m_buddies = new QDict<QLabel>();
01297     m_currentItem = form->objectTree();
01298 
01299     readChildNodes(form->objectTree(), form->toplevelContainer(), el, container);
01300 
01301     // Now the Form is fully loaded, we can assign the buddies
01302     QDictIterator<QLabel> it(*m_buddies);
01303     for(; it.current(); ++it)
01304     {
01305         ObjectTreeItem *item = form->objectTree()->lookup(it.currentKey());
01306         if(!item || !item->widget())
01307         {
01308             kdDebug() << "Cannot assign buddy for widget " << it.current()->name() << " to " << it.currentKey() << endl;
01309             continue;
01310         }
01311         it.current()->setBuddy(item->widget());
01312     }
01313     delete m_buddies;
01314     m_buddies = oldBuddies; // and restore it
01315 
01316     m_currentItem = 0;
01317 
01318     form->setInteractiveMode(true);
01319 }
01320 
01321 void
01322 FormIO::readChildNodes(ObjectTreeItem *item, Container *container, const QDomElement &el, QWidget *w)
01323 {
01324     QString eltag = el.tagName();
01325 
01326     WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(w);
01327     QWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;
01328 
01329     for(QDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
01330     {
01331         QString tag = n.toElement().tagName();
01332         QDomElement node = n.toElement();
01333 
01334         if((tag == "property") || (tag == "attribute"))
01335         {
01336             QString name = node.attribute("name");
01337             //if(name == "geometry")
01338             //  hasGeometryProp = true;
01339             if( ((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
01340                   (name == "name")) // we don't care about layout names
01341                 continue;
01342 
01343             if (node.attribute("subwidget")=="true") {
01344                 //this is property for subwidget: remember it for delayed setting
01345                 //because now the subwidget could be not created yet (true e.g. for KexiDBAutoField)
01346                 const QVariant val( readPropertyValue(node.firstChild(), w, name) );
01347                 kdDebug() << val.toStringList() << endl;
01348                 item->addSubproperty( name.latin1(), val );
01349                 //subwidget->setProperty(name.latin1(), val);
01350                 item->addModifiedProperty( name.latin1(), val );
01351                 continue;
01352             }
01353 
01354             // We cannot assign the buddy now as the buddy widget may not be created yet
01355             if(name == "buddy")
01356                 m_buddies->insert(readPropertyValue(node.firstChild(), w, name).toString(), (QLabel*)w);
01357             else if(((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
01358               item->container() && item->container()->layout()) {
01359               // We load the margin of a Layout
01360                 if(name == "margin")  {
01361                     int margin = readPropertyValue(node.firstChild(), w, name).toInt();
01362                     item->container()->setLayoutMargin(margin);
01363                     item->container()->layout()->setMargin(margin);
01364                 }
01365                 // We load the spacing of a Layout
01366                 else if(name == "spacing")  {
01367                     int spacing = readPropertyValue(node.firstChild(), w, name).toInt();
01368                     item->container()->setLayoutSpacing(spacing);
01369                     item->container()->layout()->setSpacing(spacing);
01370                 }
01371                 else if((name == "justify")){
01372                     bool justify = readPropertyValue(node.firstChild(), w, name).toBool();
01373                     KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
01374                     if(flow)
01375                         flow->setJustified(justify);
01376                 }
01377             }
01378             // If the object doesn't have this property, we let the Factory handle it (maybe a special property)
01379             else if(subwidget->metaObject()->findProperty(name.latin1(), true) == -1)
01380             {
01381                 if(w->className() == QString::fromLatin1("CustomWidget"))
01382                     item->storeUnknownProperty(node);
01383                 else {
01384                     bool read = container->form()->library()->readSpecialProperty(
01385                         w->className(), node, w, item);
01386                     if(!read) // the factory doesn't support this property neither
01387                         item->storeUnknownProperty(node);
01388                 }
01389             }
01390             else // we have a normal property, let's load it
01391             {
01392                 QVariant val( readPropertyValue(node.firstChild(), w, name) );
01393                 if(name == "geometry" && dynamic_cast<FormWidget*>(w)) {
01394                     //fix geometry if needed - this is top level form widget
01395                     QRect r( val.toRect() );
01396                     if (r.left()<0) //negative X!
01397                         r.moveLeft(0);
01398                     if (r.top()<0) //negative Y!
01399                         r.moveTop(0);
01400                     val = r;
01401                 }
01402                 subwidget->setProperty(name.latin1(), val);
01403 //              int count = w->metaObject()->findProperty(name, true);
01404 //              const QMetaProperty *meta = w->metaObject()->property(count, true);
01405 //              if(meta && meta->isEnumType()) {
01406 //                  val = w->property(name.latin1()); //update: we want a numeric value of enum
01407 //              }
01408                 item->addModifiedProperty(name.latin1(), val);
01409             }
01410         }
01411         else if(tag == "widget") // a child widget
01412         {
01413             if(item->container()) // we are a Container
01414                 loadWidget(item->container(), node);
01415             else
01416                 loadWidget(container, node, w);
01417         }
01418         else if(tag == "spacer")  {
01419             loadWidget(container, node, w);
01420         }
01421         else if(tag == "grid") {
01422             // first, see if it is flow layout
01423             QString layoutName;
01424             for(QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling())  {
01425                 if((child.toElement().tagName() == "property") && (child.toElement().attribute("name") == "customLayout"))  {
01426                     layoutName = child.toElement().text();
01427                     break;
01428                 }
01429             }
01430 
01431              if(layoutName == "HFlow") {
01432                 item->container()->m_layType = Container::HFlow;
01433                 KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
01434                 layout->setOrientation(Horizontal);
01435                 item->container()->m_layout = (QLayout*)layout;
01436             }
01437             else if(layoutName == "VFlow") {
01438                 item->container()->m_layType = Container::VFlow;
01439                 KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
01440                 layout->setOrientation(Vertical);
01441                 item->container()->m_layout = (QLayout*)layout;
01442             }
01443             else { // grid layout
01444                 item->container()->m_layType = Container::Grid;
01445                 QGridLayout *layout = new QGridLayout(item->widget(), 1, 1);
01446                 item->container()->m_layout = (QLayout*)layout;
01447             }
01448             readChildNodes(item, container, node, w);
01449         }
01450         else if(tag == "vbox")  {
01451             item->container()->m_layType = Container::VBox;
01452             QVBoxLayout *layout = new QVBoxLayout(item->widget());
01453             item->container()->m_layout = (QLayout*)layout;
01454             readChildNodes(item, container, node, w);
01455         }
01456         else if(tag == "hbox") {
01457             item->container()->m_layType = Container::HBox;
01458             QHBoxLayout *layout = new QHBoxLayout(item->widget());
01459             item->container()->m_layout = (QLayout*)layout;
01460             readChildNodes(item, container, node, w);
01461         }
01462         else {// unknown tag, we let the Factory handle it
01463             if(w->className() == QString::fromLatin1("CustomWidget"))
01464                 item->storeUnknownProperty(node);
01465             else {
01466                 bool read = container->form()->library()->readSpecialProperty(
01467                     w->className(), node, w, item);
01468                 if(!read) // the factory doesn't suport this property neither
01469                     item->storeUnknownProperty(node);
01470             }
01471         }
01472     }
01473 }
01474 
01478 
01479 void
01480 FormIO::addIncludeFileName(const QString &include, QDomDocument &domDoc)
01481 {
01482     if(include.isEmpty())
01483         return;
01484 
01485     QDomElement includes;
01486     QDomElement uiEl = domDoc.namedItem("UI").toElement();
01487     if(uiEl.namedItem("includehints").isNull())
01488     {
01489         includes = domDoc.createElement("includehints");
01490         uiEl.appendChild(includes);
01491     }
01492     else
01493         includes = uiEl.namedItem("includehints").toElement();
01494 
01495     // Check if this include has already been saved, and return if it is the case
01496     for(QDomNode n = includes.firstChild(); !n.isNull(); n = n.nextSibling())
01497     {
01498         if(n.toElement().text() == include)
01499             return;
01500     }
01501 
01502     QDomElement includeHint = domDoc.createElement("includehint");
01503     includes.appendChild(includeHint);
01504     QDomText includeText = domDoc.createTextNode(include);
01505     includeHint.appendChild(includeText);
01506 }
01507 
01509 
01510 QString
01511 FormIO::saveImage(QDomDocument &domDoc, const QPixmap &pixmap)
01512 {
01513     QDomNode node = domDoc.namedItem("images");
01514     QDomElement images;
01515     if(node.isNull())
01516     {
01517         images = domDoc.createElement("images");
01518         QDomElement ui = domDoc.namedItem("UI").toElement();
01519         ui.appendChild(images);
01520     }
01521     else
01522         images = node.toElement();
01523 
01524     int count = images.childNodes().count();
01525     QDomElement image = domDoc.createElement("image");
01526     QString name = "image" + QString::number(count);
01527     image.setAttribute("name", name);
01528 
01529     QImage img = pixmap.convertToImage();
01530     QByteArray ba;
01531     QBuffer buf(ba);
01532     buf.open( IO_WriteOnly | IO_Translate );
01533     QString format = img.depth() > 1 ? "XPM" : "XBM";
01534     QImageIO iio( &buf, format.latin1() );
01535     iio.setImage( img );
01536     iio.write();
01537     buf.close();
01538     QByteArray bazip = qCompress( ba );
01539     ulong len = bazip.size();
01540 
01541     QDomElement data = domDoc.createElement("data");
01542     data.setAttribute("format", format + ".GZ");
01543     data.setAttribute("length", ba.size());
01544 
01545     static const char hexchars[] = "0123456789abcdef";
01546     QString content;
01547     for(int i = 4; i < (int)len; ++i)
01548     {
01549     uchar s = (uchar) bazip[i];
01550     content += hexchars[s >> 4];
01551     content += hexchars[s & 0x0f];
01552     }
01553 
01554     QDomText text = domDoc.createTextNode(content);
01555     data.appendChild(text);
01556     image.appendChild(data);
01557     images.appendChild(image);
01558 
01559     return name;
01560 }
01561 
01562 QPixmap
01563 FormIO::loadImage(QDomDocument domDoc, const QString& name)
01564 {
01565     QDomElement images = domDoc.namedItem("UI").namedItem("images").toElement();
01566     if(images.isNull())
01567         return 0;
01568 
01569     QDomElement image;
01570     for(QDomNode n = images.firstChild(); !n.isNull(); n = n.nextSibling())
01571     {
01572         if((n.toElement().tagName() == "image") && (n.toElement().attribute("name") == name))
01573         {
01574             image = n.toElement();
01575             break;
01576         }
01577     }
01578 
01579     QPixmap pix;
01580     QString data = image.namedItem("data").toElement().text();
01581     const int lengthOffset = 4;
01582     int baSize = data.length() / 2 + lengthOffset;
01583     uchar *ba = new uchar[baSize];
01584     for(int i = lengthOffset; i < baSize; ++i)
01585     {
01586         char h = data[2 * (i-lengthOffset)].latin1();
01587         char l = data[2 * (i-lengthOffset) + 1].latin1();
01588         uchar r = 0;
01589         if(h <= '9')
01590             r += h - '0';
01591         else
01592             r += h - 'a' + 10;
01593         r = r << 4;
01594         if(l <= '9')
01595             r += l - '0';
01596         else
01597             r += l - 'a' + 10;
01598         ba[i] = r;
01599     }
01600 
01601     QString format = image.namedItem("data").toElement().attribute("format", "PNG");
01602     if((format == "XPM.GZ") || (format == "XBM.GZ"))
01603     {
01604         ulong len = image.attribute("length").toULong();
01605         if(len < data.length() * 5)
01606             len = data.length() * 5;
01607         // qUncompress() expects the first 4 bytes to be the expected length of
01608         // the uncompressed data
01609         ba[0] = ( len & 0xff000000 ) >> 24;
01610         ba[1] = ( len & 0x00ff0000 ) >> 16;
01611         ba[2] = ( len & 0x0000ff00 ) >> 8;
01612         ba[3] = ( len & 0x000000ff );
01613         QByteArray baunzip = qUncompress(ba, baSize);
01614         pix.loadFromData( (const uchar*)baunzip.data(), baunzip.size(), format.left(format.find('.')).latin1() );
01615     }
01616     else
01617         pix.loadFromData( (const uchar*)ba+lengthOffset, baSize-lengthOffset, format.latin1() );
01618 
01619     delete[] ba;
01620 
01621     return pix;
01622 }
01623 
01625 
01626 #include "formIO.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys