/* This file is part of the KDE project
   Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
   Copyright (C) 2005-2007 Jaroslaw Staniek <js@iidea.pl>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include <kdebug.h>

#include <tqmetaobject.h>
#include <tqdom.h>
#include <tqfile.h>
#include <tqtextstream.h>
#include <tqcursor.h>
#include <tqbuffer.h>
#include <tqimage.h>
#include <tqlayout.h>
#include <tqobjectlist.h>
#include <tqdatetime.h>
#include <tqlabel.h>
#include <tqpainter.h>

#include <tdefiledialog.h>
#include <tdelocale.h>
#include <kcommand.h>
#include <tdeaccelmanager.h>

#include "form.h"
#include "container.h"
#include "objecttree.h"
#include "formmanager.h"
#include "widgetlibrary.h"
#include "spring.h"
#include "pixmapcollection.h"
#include "events.h"
#include "utils.h"
#include "kexiflowlayout.h"
#include "widgetwithsubpropertiesinterface.h"
#include "formIO.h"

/// A blank widget used when the class name is not supported
CustomWidget::CustomWidget(const TQCString &className, TQWidget *parent, const char *name)
: TQWidget(parent, name), m_className(className)
{
	setBackgroundMode(TQt::PaletteDark);
}

CustomWidget::~CustomWidget()
{
}

void
CustomWidget::paintEvent(TQPaintEvent *)
{
	TQPainter p(this);
	p.setPen(palette().active().text());
	TQRect r(rect());
	r.setX(r.x()+2);
	p.drawText(r, TQt::AlignTop, m_className);
}

using namespace KFormDesigner;

TQDict<TQLabel> *FormIO::m_buddies = 0;
ObjectTreeItem *FormIO::m_currentItem = 0;
Form *FormIO::m_currentForm = 0;
bool FormIO::m_savePixmapsInline = false;

// FormIO itself

KFORMEDITOR_EXPORT uint KFormDesigner::version()
{
	return KFORMDESIGNER_VERSION;
}

/////////////////////////////////////////////////////////////////////////////
///////////// Saving/loading functions //////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

FormIO::FormIO()
{
}

FormIO::~FormIO()
{
}

bool
FormIO::saveFormToFile(Form *form, const TQString &filename)
{
	TQString m_filename;
	if(!form->filename().isNull() && filename.isNull())
		m_filename = form->filename();

	if(filename.isNull())
	{
		m_filename = KFileDialog::getSaveFileName(TQString(), i18n("*.ui|TQt Designer UI Files"));
		if(m_filename.isNull())
			return false;
	}
	else
		m_filename = filename;
	form->setFilename(m_filename);

	TQDomDocument domDoc;
	if (!saveFormToDom(form, domDoc))
		return false;

	TQFile file(m_filename);
	if (!file.open(IO_WriteOnly))
		return false;

	TQTextStream stream(&file);
	stream << domDoc.toString(3) << endl;
	file.close();

	return true;
}

bool
FormIO::saveFormToByteArray(Form *form, TQByteArray &dest)
{
	TQDomDocument domDoc;
	if (!saveFormToDom(form, domDoc))
		return false;
	dest = domDoc.toCString();
	return true;
}

bool
FormIO::saveFormToString(Form *form, TQString &dest, int indent)
{
	TQDomDocument domDoc;
	if (!saveFormToDom(form, domDoc))
		return false;
	dest = domDoc.toString(indent);
	return true;
}

bool
FormIO::saveFormToDom(Form *form, TQDomDocument &domDoc)
{
	m_currentForm = form;

	domDoc = TQDomDocument("UI");
	TQDomElement uiElement = domDoc.createElement("UI");
	domDoc.appendChild(uiElement);
	uiElement.setAttribute("version", "3.1");
	uiElement.setAttribute("stdsetdef", 1);

	//update format version information
	form->headerProperties()->insert("version", TQString::number(form->formatVersion()));
	//custom properties
	TQDomElement headerPropertiesEl = domDoc.createElement("kfd:customHeader");
	for (TQMapConstIterator<TQCString,TQString> it=form->headerProperties()->constBegin(); it!=form->headerProperties()->constEnd(); ++it) {
		headerPropertiesEl.setAttribute(it.key(), it.data());
	}
	uiElement.appendChild(headerPropertiesEl);

	/// We save the savePixmapsInline property in the Form
	TQDomElement inlinePix = domDoc.createElement("pixmapinproject");
	uiElement.appendChild(inlinePix);

	// We create the top class element
	TQDomElement baseClass = domDoc.createElement("class");
	uiElement.appendChild(baseClass);
	TQDomText baseClassV = domDoc.createTextNode("TQWidget");
	baseClass.appendChild(baseClassV);

	// Save the toplevel widgets, and so the whole Form
	saveWidget(form->objectTree(), uiElement, domDoc);

	// We then save the layoutdefaults element
	TQDomElement layoutDefaults = domDoc.createElement("layoutDefaults");
	layoutDefaults.setAttribute("spacing", TQString::number(form->defaultSpacing()));
	layoutDefaults.setAttribute("margin", TQString::number(form->defaultMargin()));
	uiElement.appendChild(layoutDefaults);

	/// Save tab Stops
	if(form->autoTabStops())
		form->autoAssignTabStops();
	TQDomElement tabStops = domDoc.createElement("tabstops");
	uiElement.appendChild(tabStops);
	for(ObjectTreeListIterator it( form->tabStopsIterator() ); it.current(); ++it)
	{
		TQDomElement tabstop = domDoc.createElement("tabstop");
		tabStops.appendChild(tabstop);
		TQDomText tabStopText = domDoc.createTextNode(it.current()->name());
		tabstop.appendChild(tabStopText);
	}

	// Save the Form 's PixmapCollection
	form->pixmapCollection()->save(uiElement);
	// Save the Form connections
	form->connectionBuffer()->save(uiElement);

	form->commandHistory()->documentSaved();

	m_currentForm = 0;
	m_currentItem = 0;
	//m_currentWidget = 0;

	return true;
}

bool
FormIO::loadFormFromByteArray(Form *form, TQWidget *container, TQByteArray &src, bool preview)
{
	TQString errMsg;
	int errLine;
	int errCol;

	TQDomDocument inBuf;
	bool parsed = inBuf.setContent(src, false, &errMsg, &errLine, &errCol);

	if(!parsed)
	{
		kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
		kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
		return false;
	}

	if (!loadFormFromDom(form, container, inBuf))
		return false;
	if(preview)
		form->setDesignMode(false);
	return true;
}

bool
FormIO::loadFormFromString(Form *form, TQWidget *container, TQString &src, bool preview)
{
	TQString errMsg;
	int errLine;
	int errCol;

#ifdef KEXI_DEBUG_GUI
	form->m_recentlyLoadedUICode = src;
#endif

	TQDomDocument inBuf;
	bool parsed = inBuf.setContent(src, false, &errMsg, &errLine, &errCol);

	if(!parsed)
	{
		kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
		kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
		return false;
	}

	if (!loadFormFromDom(form, container, inBuf))
		return false;
	if(preview)
		form->setDesignMode(false);
	return true;
}

bool
FormIO::loadFormFromFile(Form *form, TQWidget *container, const TQString &filename)
{
	TQString errMsg;
	int errLine;
	int errCol;
	TQString m_filename;

	if(filename.isNull())
	{
		m_filename = KFileDialog::getOpenFileName(TQString(), i18n("*.ui|TQt Designer UI Files"));
		if(m_filename.isNull())
			return false;
	}
	else
		m_filename = filename;

	TQFile file(m_filename);
	if(!file.open(IO_ReadOnly))
	{
		kdDebug() << "Cannot open the file " << filename << endl;
		return false;
	}
	TQTextStream stream(&file);
	TQString text = stream.read();

	TQDomDocument inBuf;
	bool parsed = inBuf.setContent(text, false, &errMsg, &errLine, &errCol);

	if(!parsed)
	{
		kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
		kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
		return false;
	}

	return loadFormFromDom(form, container, inBuf);
}

bool
FormIO::loadFormFromDom(Form *form, TQWidget *container, TQDomDocument &inBuf)
{
	m_currentForm = form;

	TQDomElement ui = inBuf.namedItem("UI").toElement();

	//custom properties
	form->headerProperties()->clear();
	TQDomElement headerPropertiesEl = ui.namedItem("kfd:customHeader").toElement();
	TQDomAttr attr = headerPropertiesEl.firstChild().toAttr();
	while (!attr.isNull() && attr.isAttr()) {
		form->headerProperties()->insert(attr.name().latin1(), attr.value());
		attr = attr.nextSibling().toAttr();
	}
	//update format version information
	uint ver = 1; //the default
	if (form->headerProperties()->contains("version")) {
		bool ok;
		uint v = (*form->headerProperties())["version"].toUInt(&ok);
		if (ok)
			ver = v;
	}
	kdDebug() << "FormIO::loadFormFromDom(): original format version: " << ver << endl;
	form->setOriginalFormatVersion( ver );
	if (ver < KFormDesigner::version()) {
//! @todo We can either 1) convert from old format and later save in a new one or 2) keep old format.
//!     To do this we may need to look at the original format version number.
		kdDebug() << "FormIO::loadFormFromDom(): original format is older than current: " << KFormDesigner::version() << endl;
		form->setFormatVersion( KFormDesigner::version() );
	}
	else
		form->setFormatVersion( ver );

	if (ver > KFormDesigner::version()) {
//! @todo display information about too new format and that "some information will not be available".
		kdDebug() << "FormIO::loadFormFromDom(): original format is newer than current: " << KFormDesigner::version() << endl;
	}

	// Load the pixmap collection
	m_savePixmapsInline = ( (ui.namedItem("pixmapinproject").isNull()) || (!ui.namedItem("images").isNull()) );
	form->pixmapCollection()->load(ui.namedItem("collection"));

	TQDomElement element = ui.namedItem("widget").toElement();
	createToplevelWidget(form, container, element);

	// Loading the tabstops
	TQDomElement tabStops = ui.namedItem("tabstops").toElement();
//	if(tabStops.isNull())
//		return 1;
	if(!tabStops.isNull()) {
		int i = 0;
		uint itemsNotFound = 0;
		for(TQDomNode n = tabStops.firstChild(); !n.isNull(); n = n.nextSibling(), i++)
		{
			TQString name = n.toElement().text();
			ObjectTreeItem *item = form->objectTree()->lookup(name);
			if(!item)
			{
				kdDebug() << "FormIO::loadFormFromDom ERROR : no ObjectTreeItem " << endl;
				continue;
			}
			const int index = form->tabStops()->findRef(item);
			/* Compute a real destination index: "a number of not found items so far". */
			const int realIndex = i - itemsNotFound;
			if((index != -1) && (index != realIndex)) // the widget is not in the same place, so we move it
			{
				form->tabStops()->remove(item);
				form->tabStops()->insert(realIndex, item);
			}
			if(index == -1) {
				itemsNotFound++;
				kdDebug() << "FormIO: item '" << name << "' not in list" << endl;
			}
		}
	}

	// Load the form connections
	form->connectionBuffer()->load(ui.namedItem("connections"));

	m_currentForm = 0;
	m_currentItem = 0;

	return true;
}

/////////////////////////////////////////////////////////////////////////////
///////////// Functions to save/load properties /////////////////////////////
/////////////////////////////////////////////////////////////////////////////

void
FormIO::savePropertyValue(TQDomElement &parentNode, TQDomDocument &parent, const char *name, 
	const TQVariant &value, TQWidget *w, WidgetLibrary *lib)
{
	// Widget specific properties and attributes ///////////////
//	kdDebug() << "FormIO::savePropertyValue()  Saving the property: " << name << endl;
	WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(w);
	TQWidget *subwidget = w;
	bool addSubwidgetFlag = false;
	int propertyId = w->metaObject()->findProperty(name, true);
	if (propertyId == -1 && subpropIface && subpropIface->subwidget()) { // try property from subwidget
		subwidget = subpropIface->subwidget();
		propertyId = subpropIface->subwidget()->metaObject()->findProperty(name, true);
		addSubwidgetFlag = true;
	}
	if(propertyId == -1)
	{
		kdDebug() << "FormIO::savePropertyValue()  The object doesn't have this property. Let's try the WidgetLibrary." << endl;
		if(lib)
			lib->saveSpecialProperty(w->className(), name, value, w, parentNode, parent);
		return;
	}

	const TQMetaProperty *meta = subwidget->metaObject()->property(propertyId, true);
	if (!meta->stored( subwidget )) //not storable
		return;
	TQDomElement propertyE = parent.createElement("property");
	propertyE.setAttribute("name", name);
	if (addSubwidgetFlag)
		propertyE.setAttribute("subwidget", "true");

	if(meta && meta->isEnumType())
	{
		// this property is enum or set type
		TQDomElement type;
		TQDomText valueE;

		if(meta->isSetType())
		{
			TQStringList list = TQStringList::fromStrList(meta->valueToKeys(value.toInt()));
			type = parent.createElement("set");
			valueE = parent.createTextNode(list.join("|"));
			type.appendChild(valueE);
		}
		else
		{
			TQString s = meta->valueToKey(value.toInt());
			type = parent.createElement("enum");
			valueE = parent.createTextNode(s);
			type.appendChild(valueE);
		}
		propertyE.appendChild(type);
		parentNode.appendChild(propertyE);
		return;
	}

	if(value.type() == TQVariant::Pixmap) {
		TQDomText valueE;
		TQDomElement type = parent.createElement("pixmap");
		TQCString property = propertyE.attribute("name").latin1();
//todo		TQCString pixmapName = m_currentItem->widget()->property("pixmapName").toCString();
		if(m_savePixmapsInline /* (js)too risky: || m_currentItem->pixmapName(property).isNull() */)
			valueE = parent.createTextNode(saveImage(parent, value.toPixmap()));
		else
			valueE = parent.createTextNode(m_currentItem->pixmapName(property));
		type.appendChild(valueE);
		propertyE.appendChild(type);
		parentNode.appendChild(propertyE);
		return;
	}

	// Saving a "normal" property
	writeVariant(parent, propertyE, value);
	parentNode.appendChild(propertyE);
}

void
FormIO::writeVariant(TQDomDocument &parent, TQDomElement &parentNode, TQVariant value)
{
	TQDomElement type;
	TQDomText valueE;

	switch(value.type())
	{
		case TQVariant::String:
		{
			type = parent.createElement("string");
			valueE = parent.createTextNode(value.toString());
			type.appendChild(valueE);
			break;
		}
		case TQVariant::CString:
		{
			type = parent.createElement("cstring");
			valueE = parent.createTextNode(value.toString());
			type.appendChild(valueE);
			break;
		}
		case TQVariant::Rect:
		{
			type = parent.createElement("rect");
			TQDomElement x = parent.createElement("x");
			TQDomElement y = parent.createElement("y");
			TQDomElement w = parent.createElement("width");
			TQDomElement h = parent.createElement("height");
			TQDomText valueX = parent.createTextNode(TQString::number(value.toRect().x()));
			TQDomText valueY = parent.createTextNode(TQString::number(value.toRect().y()));
			TQDomText valueW = parent.createTextNode(TQString::number(value.toRect().width()));
			TQDomText valueH = parent.createTextNode(TQString::number(value.toRect().height()));

			x.appendChild(valueX);
			y.appendChild(valueY);
			w.appendChild(valueW);
			h.appendChild(valueH);

			type.appendChild(x);
			type.appendChild(y);
			type.appendChild(w);
			type.appendChild(h);
			break;
		}
		case TQVariant::Color:
		{
			type = parent.createElement("color");
			TQDomElement r = parent.createElement("red");
			TQDomElement g = parent.createElement("green");
			TQDomElement b = parent.createElement("blue");
			TQDomText valueR = parent.createTextNode(TQString::number(value.toColor().red()));
			TQDomText valueG = parent.createTextNode(TQString::number(value.toColor().green()));
			TQDomText valueB = parent.createTextNode(TQString::number(value.toColor().blue()));

			r.appendChild(valueR);
			g.appendChild(valueG);
			b.appendChild(valueB);

			type.appendChild(r);
			type.appendChild(g);
			type.appendChild(b);
			break;
		}
		case TQVariant::Bool:
		{
			type = parent.createElement("bool");
			//valueE = parent.createTextNode(TQString::number(value.toBool()));
			valueE = parent.createTextNode(value.toBool() ? "true" : "false");
			type.appendChild(valueE);
			break;
		}
		case TQVariant::Int:
		case TQVariant::UInt:
		{
			type = parent.createElement("number");
			valueE = parent.createTextNode(TQString::number(value.toInt()));
			type.appendChild(valueE);
			break;
		}
		case TQVariant::Size:
		{
			type = parent.createElement("size");
			TQDomElement w = parent.createElement("width");
			TQDomElement h = parent.createElement("height");
			TQDomText valueW = parent.createTextNode(TQString::number(value.toSize().width()));
			TQDomText valueH = parent.createTextNode(TQString::number(value.toSize().height()));

			w.appendChild(valueW);
			h.appendChild(valueH);

			type.appendChild(w);
			type.appendChild(h);
			break;
		}
		case TQVariant::Point:
		{
			type = parent.createElement("point");
			TQDomElement x = parent.createElement("x");
			TQDomElement y = parent.createElement("y");
			TQDomText valueX = parent.createTextNode(TQString::number(value.toPoint().x()));
			TQDomText valueY = parent.createTextNode(TQString::number(value.toPoint().y()));

			x.appendChild(valueX);
			y.appendChild(valueY);

			type.appendChild(x);
			type.appendChild(y);
			break;
		}
		case TQVariant::Font:
		{
			type = parent.createElement("font");
			TQDomElement f = parent.createElement("family");
			TQDomElement p = parent.createElement("pointsize");
			TQDomElement w = parent.createElement("weight");
			TQDomElement b = parent.createElement("bold");
			TQDomElement i = parent.createElement("italic");
			TQDomElement u = parent.createElement("underline");
			TQDomElement s = parent.createElement("strikeout");
			TQDomText valueF = parent.createTextNode(value.toFont().family());
			TQDomText valueP = parent.createTextNode(TQString::number(value.toFont().pointSize()));
			TQDomText valueW = parent.createTextNode(TQString::number(value.toFont().weight()));
			TQDomText valueB = parent.createTextNode(TQString::number(value.toFont().bold()));
			TQDomText valueI = parent.createTextNode(TQString::number(value.toFont().italic()));
			TQDomText valueU = parent.createTextNode(TQString::number(value.toFont().underline()));
			TQDomText valueS = parent.createTextNode(TQString::number(value.toFont().strikeOut()));

			f.appendChild(valueF);
			p.appendChild(valueP);
			w.appendChild(valueW);
			b.appendChild(valueB);
			i.appendChild(valueI);
			u.appendChild(valueU);
			s.appendChild(valueS);

			type.appendChild(f);
			type.appendChild(p);
			type.appendChild(w);
			type.appendChild(b);
			type.appendChild(i);
			type.appendChild(u);
			type.appendChild(s);
			break;
		}
		case TQVariant::Cursor:
		{
			type = parent.createElement("cursor");
			valueE = parent.createTextNode(TQString::number(value.toCursor().shape()));
			type.appendChild(valueE);
			break;
		}
		case TQVariant::SizePolicy:
		{
			type = parent.createElement("sizepolicy");
			TQDomElement h = parent.createElement("hsizetype");
			TQDomElement v = parent.createElement("vsizetype");
			TQDomElement hs = parent.createElement("horstretch");
			TQDomElement vs = parent.createElement("verstretch");
			TQDomText valueH = parent.createTextNode(TQString::number(value.toSizePolicy().horData()));
			TQDomText valueV = parent.createTextNode(TQString::number(value.toSizePolicy().verData()));
			TQDomText valueHS = parent.createTextNode(TQString::number(value.toSizePolicy().horStretch()));
			TQDomText valueVS = parent.createTextNode(TQString::number(value.toSizePolicy().verStretch()));

			h.appendChild(valueH);
			v.appendChild(valueV);
			hs.appendChild(valueHS);
			vs.appendChild(valueVS);

			type.appendChild(h);
			type.appendChild(v);
			type.appendChild(hs);
			type.appendChild(vs);
			break;
		}
		case TQVariant::Time:
		{
			type = parent.createElement("time");
			TQDomElement h = parent.createElement("hour");
			TQDomElement m = parent.createElement("minute");
			TQDomElement s = parent.createElement("second");
			TQDomText valueH = parent.createTextNode(TQString::number(value.toTime().hour()));
			TQDomText valueM = parent.createTextNode(TQString::number(value.toTime().minute()));
			TQDomText valueS = parent.createTextNode(TQString::number(value.toTime().second()));

			h.appendChild(valueH);
			m.appendChild(valueM);
			s.appendChild(valueS);

			type.appendChild(h);
			type.appendChild(m);
			type.appendChild(s);
			break;
		}
		case TQVariant::Date:
		{
			type = parent.createElement("date");
			TQDomElement y = parent.createElement("year");
			TQDomElement m = parent.createElement("month");
			TQDomElement d = parent.createElement("day");
			TQDomText valueY = parent.createTextNode(TQString::number(value.toDate().year()));
			TQDomText valueM = parent.createTextNode(TQString::number(value.toDate().month()));
			TQDomText valueD = parent.createTextNode(TQString::number(value.toDate().day()));

			y.appendChild(valueY);
			m.appendChild(valueM);
			d.appendChild(valueD);

			type.appendChild(y);
			type.appendChild(m);
			type.appendChild(d);
			break;
		}
		case TQVariant::DateTime:
		{
			type = parent.createElement("datetime");
			TQDomElement h = parent.createElement("hour");
			TQDomElement m = parent.createElement("minute");
			TQDomElement s = parent.createElement("second");
			TQDomElement y = parent.createElement("year");
			TQDomElement mo = parent.createElement("month");
			TQDomElement d = parent.createElement("day");
			TQDomText valueH = parent.createTextNode(TQString::number(value.toDateTime().time().hour()));
			TQDomText valueM = parent.createTextNode(TQString::number(value.toDateTime().time().minute()));
			TQDomText valueS = parent.createTextNode(TQString::number(value.toDateTime().time().second()));
			TQDomText valueY = parent.createTextNode(TQString::number(value.toDateTime().date().year()));
			TQDomText valueMo = parent.createTextNode(TQString::number(value.toDateTime().date().month()));
			TQDomText valueD = parent.createTextNode(TQString::number(value.toDateTime().date().day()));

			h.appendChild(valueH);
			m.appendChild(valueM);
			s.appendChild(valueS);
			y.appendChild(valueY);
			mo.appendChild(valueMo);
			d.appendChild(valueD);

			type.appendChild(h);
			type.appendChild(m);
			type.appendChild(s);
			type.appendChild(y);
			type.appendChild(mo);
			type.appendChild(d);
			break;
		}
		default:
			break;
	}

	parentNode.appendChild(type);
}

void
FormIO::savePropertyElement(TQDomElement &parentNode, TQDomDocument &domDoc, const TQString &tagName, const TQString &property, const TQVariant &value)
{
	TQDomElement propertyE = domDoc.createElement(tagName);
	propertyE.setAttribute("name", property);
	writeVariant(domDoc, propertyE, value);
	parentNode.appendChild(propertyE);
}

TQVariant
FormIO::readPropertyValue(TQDomNode node, TQObject *obj, const TQString &name)
{
	TQDomElement tag = node.toElement();
	TQString text = tag.text();
	TQString type = tag.tagName();

	if(type == "string" || type == "cstring")
		return text;
	else if(type == "rect")
	{
		TQDomElement x = node.namedItem("x").toElement();
		TQDomElement y = node.namedItem("y").toElement();
		TQDomElement w = node.namedItem("width").toElement();
		TQDomElement h = node.namedItem("height").toElement();

		int rx = x.text().toInt();
		int ry = y.text().toInt();
		int rw = w.text().toInt();
		int rh = h.text().toInt();

		return TQRect(rx, ry, rw, rh);
	}
	else if(type == "color")
	{
		TQDomElement r = node.namedItem("red").toElement();
		TQDomElement g = node.namedItem("green").toElement();
		TQDomElement b = node.namedItem("blue").toElement();

		int red = r.text().toInt();
		int green = g.text().toInt();
		int blue = b.text().toInt();

		return TQColor(red, green, blue);
	}
	else if(type == "bool")
	{
		if(text == "true")
			return TQVariant(true);
		else if(text == "false")
			return TQVariant(false);
		return TQVariant(text.toInt());
	}
	else if(type == "number")
	{
		return text.toInt();
	}
	else if(type == "size")
	{
		TQDomElement w = node.namedItem("width").toElement();
		TQDomElement h = node.namedItem("height").toElement();

		return TQSize(w.text().toInt(), h.text().toInt());
	}
	else if(type == "point")
	{
		TQDomElement x = node.namedItem("x").toElement();
		TQDomElement y = node.namedItem("y").toElement();

		return TQPoint(x.text().toInt(), y.text().toInt());
	}
	else if(type == "font")
	{
		TQDomElement fa = node.namedItem("family").toElement();
		TQDomElement p = node.namedItem("pointsize").toElement();
		TQDomElement w = node.namedItem("weight").toElement();
		TQDomElement b = node.namedItem("bold").toElement();
		TQDomElement i = node.namedItem("italic").toElement();
		TQDomElement u = node.namedItem("underline").toElement();
		TQDomElement s = node.namedItem("strikeout").toElement();

		TQFont f;
		f.setFamily(fa.text());
		f.setPointSize(p.text().toInt());
		f.setWeight(w.text().toInt());
		f.setBold(b.text().toInt());
		f.setItalic(i.text().toInt());
		f.setUnderline(u.text().toInt());
		f.setStrikeOut(s.text().toInt());

		return f;
	}
	else if(type == "cursor")
	{
		return TQCursor(text.toInt());
	}
	else if(type == "time")
	{
		TQDomElement h = node.namedItem("hour").toElement();
		TQDomElement m = node.namedItem("minute").toElement();
		TQDomElement s = node.namedItem("second").toElement();

		return TQTime(h.text().toInt(), m.text().toInt(), s.text().toInt());
	}
	else if(type == "date")
	{
		TQDomElement y = node.namedItem("year").toElement();
		TQDomElement m = node.namedItem("month").toElement();
		TQDomElement d = node.namedItem("day").toElement();

		return TQDate(y.text().toInt(), m.text().toInt(), d.text().toInt());
	}
	else if(type == "datetime")
	{
		TQDomElement h = node.namedItem("hour").toElement();
		TQDomElement m = node.namedItem("minute").toElement();
		TQDomElement s = node.namedItem("second").toElement();
		TQDomElement y = node.namedItem("year").toElement();
		TQDomElement mo = node.namedItem("month").toElement();
		TQDomElement d = node.namedItem("day").toElement();

		TQTime t(h.text().toInt(), m.text().toInt(), s.text().toInt());
		TQDate da(y.text().toInt(), mo.text().toInt(), d.text().toInt());

		return TQDateTime(da, t);
	}
	else if(type == "sizepolicy")
	{
		TQDomElement h = node.namedItem("hsizetype").toElement();
		TQDomElement v = node.namedItem("vsizetype").toElement();
		TQDomElement hs = node.namedItem("horstretch").toElement();
		TQDomElement vs = node.namedItem("verstretch").toElement();

		TQSizePolicy s;
		s.setHorData((TQSizePolicy::SizeType)h.text().toInt());
		s.setVerData((TQSizePolicy::SizeType)v.text().toInt());
		s.setHorStretch(hs.text().toInt());
		s.setVerStretch(vs.text().toInt());
		return s;
	}
	else if(type == "pixmap")
	{
		if(m_savePixmapsInline || !m_currentForm || !m_currentItem || !m_currentForm->pixmapCollection()->contains(text))
			return loadImage(tag.ownerDocument(), text);
		else
		{
			m_currentItem->setPixmapName(name.latin1(), text);
			return m_currentForm->pixmapCollection()->getPixmap(text);
		}
		return TQVariant(TQPixmap());
	}
	else if(type == "enum")
		return text;
	else if(type == "set")
	{
		WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(obj);
		TQObject *subobject = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : obj;
		const int count = subobject->metaObject()->findProperty(name.latin1(), true);
		const TQMetaProperty *meta = count!=-1 ? subobject->metaObject()->property(count, true) : 0;

		if (meta) {
			if (meta->isSetType()) {
				TQStrList keys;
				const TQStringList list( TQStringList::split("|", text) );
				for (TQStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
					keys.append((*it).latin1());

				return meta->keysToValue(keys);
			}
		}
		else {
			// Metaproperty not found, probably because subwidget is not created.
			// We will return a string list here with hope that names will 
			// be resolved and translated into an integer value later when subwidget is created,
			// e.g. near KexiFormView::updateValuesForSubproperties()
			return TQStringList::split("|", text);
		}
	}
	return TQVariant();
}

/////////////////////////////////////////////////////////////////////////////
///////////// Functions to save/load widgets ////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

void
FormIO::saveWidget(ObjectTreeItem *item, TQDomElement &parent, TQDomDocument &domDoc, bool insideGridLayout)
{
	if (!item)
		return;
	bool savedAlignment = false;
	// we let Spring class handle saving itself
	if(item->className() == "Spring")
	{
		Spring::saveSpring(item, parent, domDoc, insideGridLayout);
		return;
	}

	bool resetCurrentForm = false;
	m_currentItem = item;
	if(!m_currentForm) // copying widget
	{
		resetCurrentForm = true;
		m_currentForm = item->container() ? item->container()->form() : item->parent()->container()->form();
	}


	WidgetLibrary *lib = m_currentForm->library();
//	if(item->container())
//		lib = item->container()->form()->manager()->lib();
//	else
//		lib = item->parent()->container()->form()->manager()->lib();

	// We create the "widget" element
	TQDomElement tclass = domDoc.createElement("widget");
	parent.appendChild(tclass);

	if(insideGridLayout)
	{
		tclass.setAttribute("row", item->gridRow());
		tclass.setAttribute("column", item->gridCol());
		if(item->spanMultipleCells())
		{
			tclass.setAttribute("rowspan", item->gridRowSpan());
			tclass.setAttribute("colspan", item->gridColSpan());
		}
	}

	if(!item->parent()) // Toplevel widget
		tclass.setAttribute("class", "TQWidget");
	// For compatibility, HBox, VBox and Grid are saved as "TQLayoutWidget"
	else if(item->widget()->isA("HBox") || item->widget()->isA("VBox") || item->widget()->isA("Grid")
			|| item->widget()->isA("HFlow") || item->widget()->isA("VFlow"))
		tclass.setAttribute("class", "TQLayoutWidget");
	else if(item->widget()->isA("CustomWidget"))
		tclass.setAttribute("class", item->className());
	else // Normal widgets
		tclass.setAttribute("class", lib->savingName(item->widget()->className()) );

	savePropertyValue(tclass, domDoc, "name", item->widget()->property("name"), item->widget());

	// Important: save dataSource property FIRST before properties like "alignment"
	// - needed when subproperties are defined after subwidget creation, and subwidget is created after setting "dataSource"
	//   (this is the case for KexiDBAutoField)
//! @todo more properties like "dataSource" may needed here...
//	if (-1 != item->widget()->metaObject()->findProperty("dataSource"))
	//	savePropertyValue(tclass, domDoc, "dataSource", item->widget()->property("dataSource"), item->widget());

	// We don't want to save the geometry if the widget is inside a layout (so parent.tagName() == "grid" for example)
	if(item && !item->parent()) {
		// save form widget size, but not its position
		savePropertyValue(tclass, domDoc, "geometry",
			TQRect( TQPoint(0,0), item->widget()->size()),
			item->widget());
	}
	// normal widget (if == "UI', it means we're copying widget)
	else if(parent.tagName() == "widget" || parent.tagName() == "UI")
		savePropertyValue(tclass, domDoc, "geometry", item->widget()->property("geometry"), item->widget());

	// Save the buddy widget for a label
	if(item->widget()->inherits("TQLabel") && ((TQLabel*)item->widget())->buddy())
		savePropertyElement(tclass, domDoc, "property", "buddy", ((TQLabel*)item->widget())->buddy()->name());

	// We save every property in the modifProp list of the ObjectTreeItem
	TQStringVariantMap *map = new TQStringVariantMap( *(item->modifiedProperties()) );
	TQStringVariantMap::ConstIterator endIt = map->constEnd();
	for(TQStringVariantMap::ConstIterator it = map->constBegin(); it != endIt; ++it)
	{
		const TQCString name( it.key().latin1() );
		if(name == "hAlign" || name == "vAlign" || name == "wordbreak" || name == "alignment") {
			if(!savedAlignment) // not to save it twice
			{
				savePropertyValue(tclass, domDoc, "alignment", item->widget()->property("alignment"), item->widget());
				savedAlignment = true;
			}
		}
		else if(name == "name" || name == "geometry" || name == "layout") {
			// these have already been saved
		}
		else {
			savePropertyValue(tclass, domDoc, it.key().latin1(), item->widget()->property(it.key().latin1()), 
				item->widget(), lib);
		}
	}
	delete map;

	if(item->widget()->isA("CustomWidget")) {
		TQDomDocument doc("TEMP");
		doc.setContent(item->m_unknownProps);
		for(TQDomNode n = doc.firstChild(); !n.isNull(); n = n.nextSibling()) {
			tclass.appendChild(n.cloneNode());
		}

	}
	// Saving container 's layout if there is one
	TQDomElement layout;
	if(item->container() && item->container()->layoutType() != Container::NoLayout)
	{
		if(item->container()->layout()) // there is a layout
		{
			layout = domDoc.createElement("temp");
			savePropertyValue(layout, domDoc, "name", "unnamed", item->widget());
			if(item->modifiedProperties()->contains("layoutMargin"))
				savePropertyElement(layout, domDoc, "property", "margin", item->container()->layoutMargin());
			if(item->modifiedProperties()->contains("layoutSpacing"))
				savePropertyElement(layout, domDoc, "property", "spacing", item->container()->layoutSpacing());
			tclass.appendChild(layout);
		}
	}

	int layoutType = item->container() ? item->container()->layoutType() : Container::NoLayout;
	switch(layoutType) {
		case Container::Grid: // grid layout
		{
			layout.setTagName("grid");
			for(ObjectTreeItem *objIt = item->children()->first(); objIt; objIt = item->children()->next())
				saveWidget(objIt, layout, domDoc, true);
			break;
		}
		case Container::HBox: case Container::VBox:
		{
			// as we don't save geometry, we need to sort widgets in the right order, not creation order
			WidgetList *list;
			if(layout.tagName() == "hbox") {
				list = new HorWidgetList(item->container()->form()->toplevelContainer()->widget());
				layout.setTagName("hbox");
			}
			else {
				list = new VerWidgetList(item->container()->form()->toplevelContainer()->widget());
				layout.setTagName("vbox");
			}

			for(ObjectTreeItem *objTree = item->children()->first(); objTree; objTree = item->children()->next())
				list->append(objTree->widget());
			list->sort();

			for(TQWidget *obj = list->first(); obj; obj = list->next()) {
				ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup(obj->name());
				if(item)
					saveWidget(titem, layout, domDoc);
			}
			delete list;
			break;
		}
		case Container::HFlow: case Container::VFlow:
		{
			layout.setTagName("grid");
			KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
			if(!flow)  break;
			WidgetList *list = (WidgetList*)flow->widgetList();

			// save some special properties
			savePropertyElement(layout, domDoc, "property", "customLayout", Container::layoutTypeToString(item->container()->layoutType()) );
			savePropertyElement(layout, domDoc, "property", "justify", TQVariant(static_cast<KexiFlowLayout*>(item->container()->layout())->isJustified()) );

			// fill the widget's grid info, ie just simulate grid layout
			item->container()->createGridLayout(true);
			for(TQWidget *obj = list->first(); obj; obj = list->next()) {
				ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup(obj->name());
				if(item)
					saveWidget(titem, layout, domDoc, true); // save grid info for compatibility with TQtDesigner
			}
			delete list;
			break;
		}
		default:
		{
			for(ObjectTreeItem *objIt = item->children()->first(); objIt; objIt = item->children()->next())
				saveWidget(objIt, tclass, domDoc);
		}
	}

	addIncludeFileName(lib->includeFileName(item->widget()->className()), domDoc);

	if(resetCurrentForm)
		m_currentForm = 0;
	m_currentItem = 0;
}

void
FormIO::cleanClipboard(TQDomElement &uiElement)
{
	// remove includes element not needed
	if(!uiElement.namedItem("includes").isNull())
		uiElement.removeChild(uiElement.namedItem("includes"));
	// and ensure images and connection are at the end
	if(!uiElement.namedItem("connections").isNull())
		uiElement.insertAfter(uiElement.namedItem("connections"), TQDomNode());
	if(!uiElement.namedItem("images").isNull())
		uiElement.insertAfter(uiElement.namedItem("images"), TQDomNode());
}

void
FormIO::loadWidget(Container *container, const TQDomElement &el, TQWidget *parent)
{
	bool resetCurrentForm = false;
	if(!m_currentForm) // pasting widget
	{
		resetCurrentForm = true;
		m_currentForm = container->form();
	}

	// We first look for the widget's name
	TQString wname;
	for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
	{
		if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
		{
			wname = n.toElement().text();
			break;
		}
	}

	TQWidget *w;
	TQCString classname, alternate;
	// We translate some name (for compatibility)
	if(el.tagName() == "spacer")
		classname = "Spring";
	else if(el.attribute("class") == "TQLayoutWidget")
	{
		for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
		{
			TQString tagName = n.toElement().tagName();
			if(tagName == "property")
				continue;
			if(tagName == "hbox")
				classname = "HBox";
			else if(tagName == "vbox")
				classname = "VBox";
			else if(tagName == "grid") {
				// first, see if it is flow layout
				for(TQDomNode child = n.firstChild(); !child.isNull(); child = child.nextSibling())  {
					if((child.toElement().tagName() == "property") 
						&& (child.toElement().attribute("name") == "customLayout"))
					{
						classname = child.toElement().text().latin1();
						break;
					}
				}

				if(classname.isEmpty()) // normal grid
					classname = "Grid";
			}
		}
	}
	else
	// We check if this classname is an alternate one, and replace it if necessary
	{
		classname = el.attribute("class").latin1();
		alternate = container->form()->library()->classNameForAlternate(classname);
	}

	if(alternate == "CustomWidget")
		w = new CustomWidget(classname, container->widget(), wname.latin1());
	else
	{
		if(!alternate.isNull())
			classname = alternate;

		int widgetOptions = WidgetFactory::DefaultOptions;
		if (!container->form()->designMode()) {
			widgetOptions ^= WidgetFactory::DesignViewMode;
		}

		if(!parent)
			w = container->form()->library()->createWidget(classname, container->widget(), 
				wname.latin1(), container, widgetOptions);
		else
			w = container->form()->library()->createWidget(classname, parent, wname.latin1(), 
				container, widgetOptions);
	}

	if(!w)
		return;
//! @todo allow setting this for data view mode as well
	if (m_currentForm->designMode()) {
		//don't generate accelerators for widgets in design mode
		TDEAcceleratorManager::setNoAccel(w);
	}
	w->setStyle(&(container->widget()->style()));
	w->show();

	// We create and insert the ObjectTreeItem at the good place in the ObjectTree
	ObjectTreeItem *item = container->form()->objectTree()->lookup(wname);
	if (!item)  {
		// not yet created
		item =  new ObjectTreeItem(container->form()->library()->displayName(classname), 
			wname, w, container);
		if(parent)  {
			ObjectTreeItem *titem = container->form()->objectTree()->lookup(parent->name());
			if(titem)
				container->form()->objectTree()->addItem(titem, item);
			else
				kdDebug() << "FORMIO :: ERROR no parent widget "  << endl;
		}
		else
			container->form()->objectTree()->addItem(container->objectTree(), item);
	}
	//assign item for its widget if it supports DesignTimeDynamicChildWidgetHandler interface
	//(e.g. KexiDBAutoField)
	if (container->form()->designMode() && dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)) {
		dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)->assignItem(item);
	}

	m_currentItem = item;
	// if we are inside a Grid, we need to insert the widget in the good cell
	if(container->layoutType() == Container::Grid)  {
		TQGridLayout *layout = (TQGridLayout*)container->layout();
		if(el.hasAttribute("rowspan")) { // widget spans multiple cells
			if(layout)
				layout->addMultiCellWidget(w, el.attribute("row").toInt(), el.attribute("row").toInt() + el.attribute("rowspan").toInt()-1,
					 el.attribute("column").toInt(),  el.attribute("column").toInt() + el.attribute("colspan").toInt()-1);
			 item->setGridPos(el.attribute("row").toInt(),  el.attribute("column").toInt(), el.attribute("rowspan").toInt(),
			   el.attribute("colspan").toInt());
		}
		else  {
			if(layout)
				layout->addWidget(w, el.attribute("row").toInt(), el.attribute("column").toInt());
			item->setGridPos(el.attribute("row").toInt(),  el.attribute("column").toInt(), 0, 0);
		}
	}
	else if(container->layout())
		container->layout()->add(w);

	readChildNodes(item, container, el, w);

	if(item->container() && item->container()->layout())
		item->container()->layout()->activate();

	// We add the autoSaveProperties in the modifProp list of the ObjectTreeItem, so that they are saved later
	TQValueList<TQCString> list(container->form()->library()->autoSaveProperties(w->className()));
	TQValueList<TQCString>::ConstIterator endIt = list.constEnd();
	KFormDesigner::WidgetWithSubpropertiesInterface* subpropIface 
		= dynamic_cast<KFormDesigner::WidgetWithSubpropertiesInterface*>(w);
	TQWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;
	for(TQValueList<TQCString>::ConstIterator it = list.constBegin(); it != endIt; ++it) {
		if(subwidget->metaObject()->findProperty(*it, true) != -1)
			item->addModifiedProperty(*it, subwidget->property(*it));
	}

	if(resetCurrentForm)
		m_currentForm = 0;
	m_currentItem = 0;
}

void
FormIO::createToplevelWidget(Form *form, TQWidget *container, TQDomElement &el)
{
	// We first look for the widget's name
	TQString wname;
	for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
	{
		if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
		{
			wname = n.toElement().text();
			break;
		}

	}
	// And rename the widget and its ObjectTreeItem
	container->setName(wname.latin1());
	if(form->objectTree())
		form->objectTree()->rename(form->objectTree()->name(), wname);
	form->setInteractiveMode(false);

	TQDict<TQLabel>  *oldBuddies = 0;
	if(m_buddies)  // save old buddies (for subforms)
		oldBuddies = m_buddies;
	m_buddies = new TQDict<TQLabel>();
	m_currentItem = form->objectTree();

	readChildNodes(form->objectTree(), form->toplevelContainer(), el, container);

	// Now the Form is fully loaded, we can assign the buddies
	TQDictIterator<TQLabel> it(*m_buddies);
	for(; it.current(); ++it)
	{
		ObjectTreeItem *item = form->objectTree()->lookup(it.currentKey());
		if(!item || !item->widget())
		{
			kdDebug() << "Cannot assign buddy for widget " << it.current()->name() << " to " << it.currentKey() << endl;
			continue;
		}
		it.current()->setBuddy(item->widget());
	}
	delete m_buddies;
	m_buddies = oldBuddies; // and restore it

	m_currentItem = 0;

	form->setInteractiveMode(true);
}

void
FormIO::readChildNodes(ObjectTreeItem *item, Container *container, const TQDomElement &el, TQWidget *w)
{
	TQString eltag = el.tagName();

	WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(w);
	TQWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;

	for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
	{
		TQString tag = n.toElement().tagName();
		TQDomElement node = n.toElement();

		if((tag == "property") || (tag == "attribute"))
		{
			TQString name = node.attribute("name");
			//if(name == "geometry")
			//	hasGeometryProp = true;
			if( ((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
			      (name == "name")) // we don't care about layout names
				continue;

			if (node.attribute("subwidget")=="true") {
				//this is property for subwidget: remember it for delayed setting
				//because now the subwidget could be not created yet (true e.g. for KexiDBAutoField)
				const TQVariant val( readPropertyValue(node.firstChild(), w, name) );
				kdDebug() << val.toStringList() << endl;
				item->addSubproperty( name.latin1(), val );
				//subwidget->setProperty(name.latin1(), val);
				item->addModifiedProperty( name.latin1(), val );
				continue;
			}

			// We cannot assign the buddy now as the buddy widget may not be created yet
			if(name == "buddy")
				m_buddies->insert(readPropertyValue(node.firstChild(), w, name).toString(), (TQLabel*)w);
			else if(((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
			  item->container() && item->container()->layout()) {
			  // We load the margin of a Layout
				if(name == "margin")  {
					int margin = readPropertyValue(node.firstChild(), w, name).toInt();
					item->container()->setLayoutMargin(margin);
					item->container()->layout()->setMargin(margin);
				}
				// We load the spacing of a Layout
				else if(name == "spacing")  {
					int spacing = readPropertyValue(node.firstChild(), w, name).toInt();
					item->container()->setLayoutSpacing(spacing);
					item->container()->layout()->setSpacing(spacing);
				}
				else if((name == "justify")){
					bool justify = readPropertyValue(node.firstChild(), w, name).toBool();
					KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
					if(flow)
						flow->setJustified(justify);
				}
			}
			// If the object doesn't have this property, we let the Factory handle it (maybe a special property)
			else if(subwidget->metaObject()->findProperty(name.latin1(), true) == -1)
			{
				if(w->className() == TQString::fromLatin1("CustomWidget"))
					item->storeUnknownProperty(node);
				else {
					bool read = container->form()->library()->readSpecialProperty(
						w->className(), node, w, item);
					if(!read) // the factory doesn't support this property neither
						item->storeUnknownProperty(node);
				}
			}
			else // we have a normal property, let's load it
			{
				TQVariant val( readPropertyValue(node.firstChild(), w, name) );
				if(name == "geometry" && dynamic_cast<FormWidget*>(w)) {
					//fix geometry if needed - this is top level form widget
					TQRect r( val.toRect() );
					if (r.left()<0) //negative X!
						r.moveLeft(0);
					if (r.top()<0) //negative Y!
						r.moveTop(0);
					val = r;
				}
				subwidget->setProperty(name.latin1(), val);
//				int count = w->metaObject()->findProperty(name, true);
//				const TQMetaProperty *meta = w->metaObject()->property(count, true);
//				if(meta && meta->isEnumType()) {
//					val = w->property(name.latin1()); //update: we want a numeric value of enum
//				}
				item->addModifiedProperty(name.latin1(), val);
			}
		}
		else if(tag == "widget") // a child widget
		{
			if(item->container()) // we are a Container
				loadWidget(item->container(), node);
			else
				loadWidget(container, node, w);
		}
		else if(tag == "spacer")  {
			loadWidget(container, node, w);
		}
		else if(tag == "grid") {
			// first, see if it is flow layout
			TQString layoutName;
			for(TQDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling())  {
				if((child.toElement().tagName() == "property") && (child.toElement().attribute("name") == "customLayout"))  {
					layoutName = child.toElement().text();
					break;
				}
			}

			 if(layoutName == "HFlow") {
				item->container()->m_layType = Container::HFlow;
				KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
				layout->setOrientation(TQt::Horizontal);
				item->container()->m_layout = (TQLayout*)layout;
			}
			else if(layoutName == "VFlow") {
				item->container()->m_layType = Container::VFlow;
				KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
				layout->setOrientation(TQt::Vertical);
				item->container()->m_layout = (TQLayout*)layout;
			}
			else { // grid layout
				item->container()->m_layType = Container::Grid;
				TQGridLayout *layout = new TQGridLayout(item->widget(), 1, 1);
				item->container()->m_layout = (TQLayout*)layout;
			}
			readChildNodes(item, container, node, w);
		}
		else if(tag == "vbox")  {
			item->container()->m_layType = Container::VBox;
			TQVBoxLayout *layout = new TQVBoxLayout(item->widget());
			item->container()->m_layout = (TQLayout*)layout;
			readChildNodes(item, container, node, w);
		}
		else if(tag == "hbox") {
			item->container()->m_layType = Container::HBox;
			TQHBoxLayout *layout = new TQHBoxLayout(item->widget());
			item->container()->m_layout = (TQLayout*)layout;
			readChildNodes(item, container, node, w);
		}
		else {// unknown tag, we let the Factory handle it
			if(w->className() == TQString::fromLatin1("CustomWidget"))
				item->storeUnknownProperty(node);
			else {
				bool read = container->form()->library()->readSpecialProperty(
					w->className(), node, w, item);
				if(!read) // the factory doesn't suport this property neither
					item->storeUnknownProperty(node);
			}
		}
	}
}

/////////////////////////////////////////////////////////////////////////////
///////////// Helper functions //////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////

void
FormIO::addIncludeFileName(const TQString &include, TQDomDocument &domDoc)
{
	if(include.isEmpty())
		return;

	TQDomElement includes;
	TQDomElement uiEl = domDoc.namedItem("UI").toElement();
	if(uiEl.namedItem("includes").isNull())
	{
		includes = domDoc.createElement("includes");
		uiEl.appendChild(includes);
	}
	else
		includes = uiEl.namedItem("includes").toElement();

	// Check if this include has already been saved, and return if it is the case
	for(TQDomNode n = includes.firstChild(); !n.isNull(); n = n.nextSibling())
	{
		if(n.toElement().text() == include)
			return;
	}

	TQDomElement includeElement = domDoc.createElement("include");
	includes.appendChild(includeElement);
	includeElement.setAttribute("location", "global");
	includeElement.setAttribute("impldecl", "in implementation");
	TQDomText includeText = domDoc.createTextNode(include);
	includeElement.appendChild(includeText);
}

////////  TQt Designer code: these two functions were copied (and adapted) from TQt Designer for compatibility ////////

TQString
FormIO::saveImage(TQDomDocument &domDoc, const TQPixmap &pixmap)
{
	TQDomNode node = domDoc.namedItem("images");
	TQDomElement images;
	if(node.isNull())
	{
		images = domDoc.createElement("images");
		TQDomElement ui = domDoc.namedItem("UI").toElement();
		ui.appendChild(images);
	}
	else
		images = node.toElement();

	int count = images.childNodes().count();
	TQDomElement image = domDoc.createElement("image");
	TQString name = "image" + TQString::number(count);
	image.setAttribute("name", name);

	TQImage img = pixmap.convertToImage();
	TQByteArray ba;
	TQBuffer buf(ba);
	buf.open( IO_WriteOnly | IO_Translate );
	TQString format = img.depth() > 1 ? "XPM" : "XBM";
	TQImageIO iio( &buf, format.latin1() );
	iio.setImage( img );
	iio.write();
	buf.close();
	TQByteArray bazip = tqCompress( ba );
	ulong len = bazip.size();

	TQDomElement data = domDoc.createElement("data");
	data.setAttribute("format", format + ".GZ");
	data.setAttribute("length", ba.size());

	static const char hexchars[] = "0123456789abcdef";
	TQString content;
	for(int i = 4; i < (int)len; ++i)
	{
	uchar s = (uchar) bazip[i];
	content += hexchars[s >> 4];
	content += hexchars[s & 0x0f];
	}

	TQDomText text = domDoc.createTextNode(content);
	data.appendChild(text);
	image.appendChild(data);
	images.appendChild(image);

	return name;
}

TQPixmap
FormIO::loadImage(TQDomDocument domDoc, const TQString& name)
{
	TQDomElement images = domDoc.namedItem("UI").namedItem("images").toElement();
	if(images.isNull())
		return 0;

	TQDomElement image;
	for(TQDomNode n = images.firstChild(); !n.isNull(); n = n.nextSibling())
	{
		if((n.toElement().tagName() == "image") && (n.toElement().attribute("name") == name))
		{
			image = n.toElement();
			break;
		}
	}

	TQPixmap pix;
	TQString data = image.namedItem("data").toElement().text();
	const int lengthOffset = 4;
	int baSize = data.length() / 2 + lengthOffset;
	uchar *ba = new uchar[baSize];
	for(int i = lengthOffset; i < baSize; ++i)
	{
		char h = data[2 * (i-lengthOffset)].latin1();
		char l = data[2 * (i-lengthOffset) + 1].latin1();
		uchar r = 0;
		if(h <= '9')
		    r += h - '0';
		else
		    r += h - 'a' + 10;
		r = r << 4;
		if(l <= '9')
		    r += l - '0';
		else
		    r += l - 'a' + 10;
		ba[i] = r;
	}

	TQString format = image.namedItem("data").toElement().attribute("format", "PNG");
	if((format == "XPM.GZ") || (format == "XBM.GZ"))
	{
		ulong len = image.attribute("length").toULong();
		if(len < data.length() * 5)
		    len = data.length() * 5;
		// tqUncompress() expects the first 4 bytes to be the expected length of
		// the uncompressed data
		ba[0] = ( len & 0xff000000 ) >> 24;
		ba[1] = ( len & 0x00ff0000 ) >> 16;
		ba[2] = ( len & 0x0000ff00 ) >> 8;
		ba[3] = ( len & 0x000000ff );
		TQByteArray baunzip = tqUncompress(ba, baSize);
		pix.loadFromData( (const uchar*)baunzip.data(), baunzip.size(), format.left(format.find('.')).latin1() );
	}
	else
		pix.loadFromData( (const uchar*)ba+lengthOffset, baSize-lengthOffset, format.latin1() );

	delete[] ba;

	return pix;
}

//////// End of TQt Designer code ////////////////////////////////////////////////////////

#include "formIO.moc"
