You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1629 lines
52 KiB
1629 lines
52 KiB
/* 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()) ? TQT_TQOBJECT(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;
|
|
#if TDE_VERSION >= TDE_MAKE_VERSION(3,4,0)
|
|
//! @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);
|
|
}
|
|
#endif
|
|
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(), TQT_TQOBJECT(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(), TQT_TQOBJECT(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(), TQT_TQOBJECT(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(), TQT_TQOBJECT(w), name).toInt();
|
|
item->container()->setLayoutSpacing(spacing);
|
|
item->container()->layout()->setSpacing(spacing);
|
|
}
|
|
else if((name == "justify")){
|
|
bool justify = readPropertyValue(node.firstChild(), TQT_TQOBJECT(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(), TQT_TQOBJECT(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"
|