formIO.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
3 Copyright (C) 2005-2007 Jaroslaw Staniek <js@iidea.pl>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <kdebug.h>
22
23#include <tqmetaobject.h>
24#include <tqdom.h>
25#include <tqfile.h>
26#include <tqtextstream.h>
27#include <tqcursor.h>
28#include <tqbuffer.h>
29#include <tqimage.h>
30#include <tqlayout.h>
31#include <tqobjectlist.h>
32#include <tqdatetime.h>
33#include <tqlabel.h>
34#include <tqpainter.h>
35
36#include <tdefiledialog.h>
37#include <tdelocale.h>
38#include <kcommand.h>
39#include <tdeaccelmanager.h>
40
41#include "form.h"
42#include "container.h"
43#include "objecttree.h"
44#include "formmanager.h"
45#include "widgetlibrary.h"
46#include "spring.h"
47#include "pixmapcollection.h"
48#include "events.h"
49#include "utils.h"
50#include "kexiflowlayout.h"
51#include "widgetwithsubpropertiesinterface.h"
52#include "formIO.h"
53
55CustomWidget::CustomWidget(const TQCString &className, TQWidget *parent, const char *name)
56: TQWidget(parent, name), m_className(className)
57{
58 setBackgroundMode(TQt::PaletteDark);
59}
60
61CustomWidget::~CustomWidget()
62{
63}
64
65void
66CustomWidget::paintEvent(TQPaintEvent *)
67{
68 TQPainter p(this);
69 p.setPen(palette().active().text());
70 TQRect r(rect());
71 r.setX(r.x()+2);
72 p.drawText(r, TQt::AlignTop, m_className);
73}
74
75using namespace KFormDesigner;
76
77TQDict<TQLabel> *FormIO::m_buddies = 0;
78ObjectTreeItem *FormIO::m_currentItem = 0;
79Form *FormIO::m_currentForm = 0;
80bool FormIO::m_savePixmapsInline = false;
81
82// FormIO itself
83
84KFORMEDITOR_EXPORT uint KFormDesigner::version()
85{
86 return KFORMDESIGNER_VERSION;
87}
88
92
93FormIO::FormIO()
94{
95}
96
97FormIO::~FormIO()
98{
99}
100
101bool
102FormIO::saveFormToFile(Form *form, const TQString &filename)
103{
104 TQString m_filename;
105 if(!form->filename().isNull() && filename.isNull())
106 m_filename = form->filename();
107
108 if(filename.isNull())
109 {
110 m_filename = KFileDialog::getSaveFileName(TQString(), i18n("*.ui|TQt Designer UI Files"));
111 if(m_filename.isNull())
112 return false;
113 }
114 else
115 m_filename = filename;
116 form->setFilename(m_filename);
117
118 TQDomDocument domDoc;
119 if (!saveFormToDom(form, domDoc))
120 return false;
121
123 if (!file.open(IO_WriteOnly))
124 return false;
125
127 stream << domDoc.toString(3) << endl;
128 file.close();
129
130 return true;
131}
132
133bool
134FormIO::saveFormToByteArray(Form *form, TQByteArray &dest)
135{
136 TQDomDocument domDoc;
137 if (!saveFormToDom(form, domDoc))
138 return false;
139 dest = domDoc.toCString();
140 return true;
141}
142
143bool
144FormIO::saveFormToString(Form *form, TQString &dest, int indent)
145{
146 TQDomDocument domDoc;
147 if (!saveFormToDom(form, domDoc))
148 return false;
149 dest = domDoc.toString(indent);
150 return true;
151}
152
153bool
154FormIO::saveFormToDom(Form *form, TQDomDocument &domDoc)
155{
156 m_currentForm = form;
157
158 domDoc = TQDomDocument("UI");
159 TQDomElement uiElement = domDoc.createElement("UI");
160 domDoc.appendChild(uiElement);
161 uiElement.setAttribute("version", "3.1");
162 uiElement.setAttribute("stdsetdef", 1);
163
164 //update format version information
165 form->headerProperties()->insert("version", TQString::number(form->formatVersion()));
166 //custom properties
167 TQDomElement headerPropertiesEl = domDoc.createElement("kfd:customHeader");
168 for (TQMapConstIterator<TQCString,TQString> it=form->headerProperties()->constBegin(); it!=form->headerProperties()->constEnd(); ++it) {
169 headerPropertiesEl.setAttribute(it.key(), it.data());
170 }
171 uiElement.appendChild(headerPropertiesEl);
172
174 TQDomElement inlinePix = domDoc.createElement("pixmapinproject");
175 uiElement.appendChild(inlinePix);
176
177 // We create the top class element
178 TQDomElement baseClass = domDoc.createElement("class");
179 uiElement.appendChild(baseClass);
180 TQDomText baseClassV = domDoc.createTextNode("TQWidget");
181 baseClass.appendChild(baseClassV);
182
183 // Save the toplevel widgets, and so the whole Form
184 saveWidget(form->objectTree(), uiElement, domDoc);
185
186 // We then save the layoutdefaults element
187 TQDomElement layoutDefaults = domDoc.createElement("layoutDefaults");
188 layoutDefaults.setAttribute("spacing", TQString::number(form->defaultSpacing()));
189 layoutDefaults.setAttribute("margin", TQString::number(form->defaultMargin()));
190 uiElement.appendChild(layoutDefaults);
191
193 if(form->autoTabStops())
194 form->autoAssignTabStops();
195 TQDomElement tabStops = domDoc.createElement("tabstops");
196 uiElement.appendChild(tabStops);
197 for(ObjectTreeListIterator it( form->tabStopsIterator() ); it.current(); ++it)
198 {
199 TQDomElement tabstop = domDoc.createElement("tabstop");
200 tabStops.appendChild(tabstop);
201 TQDomText tabStopText = domDoc.createTextNode(it.current()->name());
202 tabstop.appendChild(tabStopText);
203 }
204
205 // Save the Form 's PixmapCollection
206 form->pixmapCollection()->save(uiElement);
207 // Save the Form connections
208 form->connectionBuffer()->save(uiElement);
209
210 form->commandHistory()->documentSaved();
211
212 m_currentForm = 0;
213 m_currentItem = 0;
214 //m_currentWidget = 0;
215
216 return true;
217}
218
219bool
220FormIO::loadFormFromByteArray(Form *form, TQWidget *container, TQByteArray &src, bool preview)
221{
222 TQString errMsg;
223 int errLine;
224 int errCol;
225
226 TQDomDocument inBuf;
227 bool parsed = inBuf.setContent(src, false, &errMsg, &errLine, &errCol);
228
229 if(!parsed)
230 {
231 kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
232 kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
233 return false;
234 }
235
236 if (!loadFormFromDom(form, container, inBuf))
237 return false;
238 if(preview)
239 form->setDesignMode(false);
240 return true;
241}
242
243bool
244FormIO::loadFormFromString(Form *form, TQWidget *container, TQString &src, bool preview)
245{
246 TQString errMsg;
247 int errLine;
248 int errCol;
249
250#ifdef KEXI_DEBUG_GUI
251 form->m_recentlyLoadedUICode = src;
252#endif
253
254 TQDomDocument inBuf;
255 bool parsed = inBuf.setContent(src, false, &errMsg, &errLine, &errCol);
256
257 if(!parsed)
258 {
259 kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
260 kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
261 return false;
262 }
263
264 if (!loadFormFromDom(form, container, inBuf))
265 return false;
266 if(preview)
267 form->setDesignMode(false);
268 return true;
269}
270
271bool
272FormIO::loadFormFromFile(Form *form, TQWidget *container, const TQString &filename)
273{
274 TQString errMsg;
275 int errLine;
276 int errCol;
277 TQString m_filename;
278
279 if(filename.isNull())
280 {
281 m_filename = KFileDialog::getOpenFileName(TQString(), i18n("*.ui|TQt Designer UI Files"));
282 if(m_filename.isNull())
283 return false;
284 }
285 else
286 m_filename = filename;
287
289 if(!file.open(IO_ReadOnly))
290 {
291 kdDebug() << "Cannot open the file " << filename << endl;
292 return false;
293 }
295 TQString text = stream.read();
296
297 TQDomDocument inBuf;
298 bool parsed = inBuf.setContent(text, false, &errMsg, &errLine, &errCol);
299
300 if(!parsed)
301 {
302 kdDebug() << "WidgetWatcher::load(): " << errMsg << endl;
303 kdDebug() << "WidgetWatcher::load(): line: " << errLine << " col: " << errCol << endl;
304 return false;
305 }
306
307 return loadFormFromDom(form, container, inBuf);
308}
309
310bool
311FormIO::loadFormFromDom(Form *form, TQWidget *container, TQDomDocument &inBuf)
312{
313 m_currentForm = form;
314
315 TQDomElement ui = inBuf.namedItem("UI").toElement();
316
317 //custom properties
318 form->headerProperties()->clear();
319 TQDomElement headerPropertiesEl = ui.namedItem("kfd:customHeader").toElement();
320 TQDomAttr attr = headerPropertiesEl.firstChild().toAttr();
321 while (!attr.isNull() && attr.isAttr()) {
322 form->headerProperties()->insert(attr.name().latin1(), attr.value());
323 attr = attr.nextSibling().toAttr();
324 }
325 //update format version information
326 uint ver = 1; //the default
327 if (form->headerProperties()->contains("version")) {
328 bool ok;
329 uint v = (*form->headerProperties())["version"].toUInt(&ok);
330 if (ok)
331 ver = v;
332 }
333 kdDebug() << "FormIO::loadFormFromDom(): original format version: " << ver << endl;
334 form->setOriginalFormatVersion( ver );
335 if (ver < KFormDesigner::version()) {
338 kdDebug() << "FormIO::loadFormFromDom(): original format is older than current: " << KFormDesigner::version() << endl;
339 form->setFormatVersion( KFormDesigner::version() );
340 }
341 else
342 form->setFormatVersion( ver );
343
344 if (ver > KFormDesigner::version()) {
346 kdDebug() << "FormIO::loadFormFromDom(): original format is newer than current: " << KFormDesigner::version() << endl;
347 }
348
349 // Load the pixmap collection
350 m_savePixmapsInline = ( (ui.namedItem("pixmapinproject").isNull()) || (!ui.namedItem("images").isNull()) );
351 form->pixmapCollection()->load(ui.namedItem("collection"));
352
353 TQDomElement element = ui.namedItem("widget").toElement();
354 createToplevelWidget(form, container, element);
355
356 // Loading the tabstops
357 TQDomElement tabStops = ui.namedItem("tabstops").toElement();
358// if(tabStops.isNull())
359// return 1;
360 if(!tabStops.isNull()) {
361 int i = 0;
362 uint itemsNotFound = 0;
363 for(TQDomNode n = tabStops.firstChild(); !n.isNull(); n = n.nextSibling(), i++)
364 {
365 TQString name = n.toElement().text();
366 ObjectTreeItem *item = form->objectTree()->lookup(name);
367 if(!item)
368 {
369 kdDebug() << "FormIO::loadFormFromDom ERROR : no ObjectTreeItem " << endl;
370 continue;
371 }
372 const int index = form->tabStops()->findRef(item);
373 /* Compute a real destination index: "a number of not found items so far". */
374 const int realIndex = i - itemsNotFound;
375 if((index != -1) && (index != realIndex)) // the widget is not in the same place, so we move it
376 {
377 form->tabStops()->remove(item);
378 form->tabStops()->insert(realIndex, item);
379 }
380 if(index == -1) {
382 kdDebug() << "FormIO: item '" << name << "' not in list" << endl;
383 }
384 }
385 }
386
387 // Load the form connections
388 form->connectionBuffer()->load(ui.namedItem("connections"));
389
390 m_currentForm = 0;
391 m_currentItem = 0;
392
393 return true;
394}
395
399
400void
401FormIO::savePropertyValue(TQDomElement &parentNode, TQDomDocument &parent, const char *name,
402 const TQVariant &value, TQWidget *w, WidgetLibrary *lib)
403{
404 // Widget specific properties and attributes ///////////////
405// kdDebug() << "FormIO::savePropertyValue() Saving the property: " << name << endl;
407 TQWidget *subwidget = w;
408 bool addSubwidgetFlag = false;
409 int propertyId = w->metaObject()->findProperty(name, true);
410 if (propertyId == -1 && subpropIface && subpropIface->subwidget()) { // try property from subwidget
411 subwidget = subpropIface->subwidget();
412 propertyId = subpropIface->subwidget()->metaObject()->findProperty(name, true);
413 addSubwidgetFlag = true;
414 }
415 if(propertyId == -1)
416 {
417 kdDebug() << "FormIO::savePropertyValue() The object doesn't have this property. Let's try the WidgetLibrary." << endl;
418 if(lib)
419 lib->saveSpecialProperty(w->className(), name, value, w, parentNode, parent);
420 return;
421 }
422
423 const TQMetaProperty *meta = subwidget->metaObject()->property(propertyId, true);
424 if (!meta->stored( subwidget )) //not storable
425 return;
426 TQDomElement propertyE = parent.createElement("property");
427 propertyE.setAttribute("name", name);
429 propertyE.setAttribute("subwidget", "true");
430
431 if(meta && meta->isEnumType())
432 {
433 // this property is enum or set type
434 TQDomElement type;
436
437 if(meta->isSetType())
438 {
439 TQStringList list = TQStringList::fromStrList(meta->valueToKeys(value.toInt()));
440 type = parent.createElement("set");
441 valueE = parent.createTextNode(list.join("|"));
442 type.appendChild(valueE);
443 }
444 else
445 {
446 TQString s = meta->valueToKey(value.toInt());
447 type = parent.createElement("enum");
448 valueE = parent.createTextNode(s);
449 type.appendChild(valueE);
450 }
451 propertyE.appendChild(type);
452 parentNode.appendChild(propertyE);
453 return;
454 }
455
456 if(value.type() == TQVariant::Pixmap) {
458 TQDomElement type = parent.createElement("pixmap");
459 TQCString property = propertyE.attribute("name").latin1();
460//todo TQCString pixmapName = m_currentItem->widget()->property("pixmapName").toCString();
461 if(m_savePixmapsInline /* (js)too risky: || m_currentItem->pixmapName(property).isNull() */)
462 valueE = parent.createTextNode(saveImage(parent, value.toPixmap()));
463 else
464 valueE = parent.createTextNode(m_currentItem->pixmapName(property));
465 type.appendChild(valueE);
466 propertyE.appendChild(type);
467 parentNode.appendChild(propertyE);
468 return;
469 }
470
471 // Saving a "normal" property
472 writeVariant(parent, propertyE, value);
473 parentNode.appendChild(propertyE);
474}
475
476void
477FormIO::writeVariant(TQDomDocument &parent, TQDomElement &parentNode, TQVariant value)
478{
479 TQDomElement type;
481
482 switch(value.type())
483 {
484 case TQVariant::String:
485 {
486 type = parent.createElement("string");
487 valueE = parent.createTextNode(value.toString());
488 type.appendChild(valueE);
489 break;
490 }
491 case TQVariant::CString:
492 {
493 type = parent.createElement("cstring");
494 valueE = parent.createTextNode(value.toString());
495 type.appendChild(valueE);
496 break;
497 }
498 case TQVariant::Rect:
499 {
500 type = parent.createElement("rect");
501 TQDomElement x = parent.createElement("x");
502 TQDomElement y = parent.createElement("y");
503 TQDomElement w = parent.createElement("width");
504 TQDomElement h = parent.createElement("height");
505 TQDomText valueX = parent.createTextNode(TQString::number(value.toRect().x()));
506 TQDomText valueY = parent.createTextNode(TQString::number(value.toRect().y()));
507 TQDomText valueW = parent.createTextNode(TQString::number(value.toRect().width()));
508 TQDomText valueH = parent.createTextNode(TQString::number(value.toRect().height()));
509
510 x.appendChild(valueX);
511 y.appendChild(valueY);
512 w.appendChild(valueW);
513 h.appendChild(valueH);
514
515 type.appendChild(x);
516 type.appendChild(y);
517 type.appendChild(w);
518 type.appendChild(h);
519 break;
520 }
521 case TQVariant::Color:
522 {
523 type = parent.createElement("color");
524 TQDomElement r = parent.createElement("red");
525 TQDomElement g = parent.createElement("green");
526 TQDomElement b = parent.createElement("blue");
527 TQDomText valueR = parent.createTextNode(TQString::number(value.toColor().red()));
528 TQDomText valueG = parent.createTextNode(TQString::number(value.toColor().green()));
529 TQDomText valueB = parent.createTextNode(TQString::number(value.toColor().blue()));
530
531 r.appendChild(valueR);
532 g.appendChild(valueG);
533 b.appendChild(valueB);
534
535 type.appendChild(r);
536 type.appendChild(g);
537 type.appendChild(b);
538 break;
539 }
540 case TQVariant::Bool:
541 {
542 type = parent.createElement("bool");
543 //valueE = parent.createTextNode(TQString::number(value.toBool()));
544 valueE = parent.createTextNode(value.toBool() ? "true" : "false");
545 type.appendChild(valueE);
546 break;
547 }
548 case TQVariant::Int:
549 case TQVariant::UInt:
550 {
551 type = parent.createElement("number");
552 valueE = parent.createTextNode(TQString::number(value.toInt()));
553 type.appendChild(valueE);
554 break;
555 }
556 case TQVariant::Size:
557 {
558 type = parent.createElement("size");
559 TQDomElement w = parent.createElement("width");
560 TQDomElement h = parent.createElement("height");
561 TQDomText valueW = parent.createTextNode(TQString::number(value.toSize().width()));
562 TQDomText valueH = parent.createTextNode(TQString::number(value.toSize().height()));
563
564 w.appendChild(valueW);
565 h.appendChild(valueH);
566
567 type.appendChild(w);
568 type.appendChild(h);
569 break;
570 }
571 case TQVariant::Point:
572 {
573 type = parent.createElement("point");
574 TQDomElement x = parent.createElement("x");
575 TQDomElement y = parent.createElement("y");
576 TQDomText valueX = parent.createTextNode(TQString::number(value.toPoint().x()));
577 TQDomText valueY = parent.createTextNode(TQString::number(value.toPoint().y()));
578
579 x.appendChild(valueX);
580 y.appendChild(valueY);
581
582 type.appendChild(x);
583 type.appendChild(y);
584 break;
585 }
586 case TQVariant::Font:
587 {
588 type = parent.createElement("font");
589 TQDomElement f = parent.createElement("family");
590 TQDomElement p = parent.createElement("pointsize");
591 TQDomElement w = parent.createElement("weight");
592 TQDomElement b = parent.createElement("bold");
593 TQDomElement i = parent.createElement("italic");
594 TQDomElement u = parent.createElement("underline");
595 TQDomElement s = parent.createElement("strikeout");
596 TQDomText valueF = parent.createTextNode(value.toFont().family());
597 TQDomText valueP = parent.createTextNode(TQString::number(value.toFont().pointSize()));
598 TQDomText valueW = parent.createTextNode(TQString::number(value.toFont().weight()));
599 TQDomText valueB = parent.createTextNode(TQString::number(value.toFont().bold()));
600 TQDomText valueI = parent.createTextNode(TQString::number(value.toFont().italic()));
601 TQDomText valueU = parent.createTextNode(TQString::number(value.toFont().underline()));
602 TQDomText valueS = parent.createTextNode(TQString::number(value.toFont().strikeOut()));
603
604 f.appendChild(valueF);
605 p.appendChild(valueP);
606 w.appendChild(valueW);
607 b.appendChild(valueB);
608 i.appendChild(valueI);
609 u.appendChild(valueU);
610 s.appendChild(valueS);
611
612 type.appendChild(f);
613 type.appendChild(p);
614 type.appendChild(w);
615 type.appendChild(b);
616 type.appendChild(i);
617 type.appendChild(u);
618 type.appendChild(s);
619 break;
620 }
621 case TQVariant::Cursor:
622 {
623 type = parent.createElement("cursor");
624 valueE = parent.createTextNode(TQString::number(value.toCursor().shape()));
625 type.appendChild(valueE);
626 break;
627 }
628 case TQVariant::SizePolicy:
629 {
630 type = parent.createElement("sizepolicy");
631 TQDomElement h = parent.createElement("hsizetype");
632 TQDomElement v = parent.createElement("vsizetype");
633 TQDomElement hs = parent.createElement("horstretch");
634 TQDomElement vs = parent.createElement("verstretch");
635 TQDomText valueH = parent.createTextNode(TQString::number(value.toSizePolicy().horData()));
636 TQDomText valueV = parent.createTextNode(TQString::number(value.toSizePolicy().verData()));
637 TQDomText valueHS = parent.createTextNode(TQString::number(value.toSizePolicy().horStretch()));
638 TQDomText valueVS = parent.createTextNode(TQString::number(value.toSizePolicy().verStretch()));
639
640 h.appendChild(valueH);
641 v.appendChild(valueV);
642 hs.appendChild(valueHS);
643 vs.appendChild(valueVS);
644
645 type.appendChild(h);
646 type.appendChild(v);
647 type.appendChild(hs);
648 type.appendChild(vs);
649 break;
650 }
651 case TQVariant::Time:
652 {
653 type = parent.createElement("time");
654 TQDomElement h = parent.createElement("hour");
655 TQDomElement m = parent.createElement("minute");
656 TQDomElement s = parent.createElement("second");
657 TQDomText valueH = parent.createTextNode(TQString::number(value.toTime().hour()));
658 TQDomText valueM = parent.createTextNode(TQString::number(value.toTime().minute()));
659 TQDomText valueS = parent.createTextNode(TQString::number(value.toTime().second()));
660
661 h.appendChild(valueH);
662 m.appendChild(valueM);
663 s.appendChild(valueS);
664
665 type.appendChild(h);
666 type.appendChild(m);
667 type.appendChild(s);
668 break;
669 }
670 case TQVariant::Date:
671 {
672 type = parent.createElement("date");
673 TQDomElement y = parent.createElement("year");
674 TQDomElement m = parent.createElement("month");
675 TQDomElement d = parent.createElement("day");
676 TQDomText valueY = parent.createTextNode(TQString::number(value.toDate().year()));
677 TQDomText valueM = parent.createTextNode(TQString::number(value.toDate().month()));
678 TQDomText valueD = parent.createTextNode(TQString::number(value.toDate().day()));
679
680 y.appendChild(valueY);
681 m.appendChild(valueM);
682 d.appendChild(valueD);
683
684 type.appendChild(y);
685 type.appendChild(m);
686 type.appendChild(d);
687 break;
688 }
689 case TQVariant::DateTime:
690 {
691 type = parent.createElement("datetime");
692 TQDomElement h = parent.createElement("hour");
693 TQDomElement m = parent.createElement("minute");
694 TQDomElement s = parent.createElement("second");
695 TQDomElement y = parent.createElement("year");
696 TQDomElement mo = parent.createElement("month");
697 TQDomElement d = parent.createElement("day");
698 TQDomText valueH = parent.createTextNode(TQString::number(value.toDateTime().time().hour()));
699 TQDomText valueM = parent.createTextNode(TQString::number(value.toDateTime().time().minute()));
700 TQDomText valueS = parent.createTextNode(TQString::number(value.toDateTime().time().second()));
701 TQDomText valueY = parent.createTextNode(TQString::number(value.toDateTime().date().year()));
702 TQDomText valueMo = parent.createTextNode(TQString::number(value.toDateTime().date().month()));
703 TQDomText valueD = parent.createTextNode(TQString::number(value.toDateTime().date().day()));
704
705 h.appendChild(valueH);
706 m.appendChild(valueM);
707 s.appendChild(valueS);
708 y.appendChild(valueY);
709 mo.appendChild(valueMo);
710 d.appendChild(valueD);
711
712 type.appendChild(h);
713 type.appendChild(m);
714 type.appendChild(s);
715 type.appendChild(y);
716 type.appendChild(mo);
717 type.appendChild(d);
718 break;
719 }
720 default:
721 break;
722 }
723
724 parentNode.appendChild(type);
725}
726
727void
728FormIO::savePropertyElement(TQDomElement &parentNode, TQDomDocument &domDoc, const TQString &tagName, const TQString &property, const TQVariant &value)
729{
730 TQDomElement propertyE = domDoc.createElement(tagName);
731 propertyE.setAttribute("name", property);
732 writeVariant(domDoc, propertyE, value);
733 parentNode.appendChild(propertyE);
734}
735
736TQVariant
737FormIO::readPropertyValue(TQDomNode node, TQObject *obj, const TQString &name)
738{
739 TQDomElement tag = node.toElement();
740 TQString text = tag.text();
741 TQString type = tag.tagName();
742
743 if(type == "string" || type == "cstring")
744 return text;
745 else if(type == "rect")
746 {
747 TQDomElement x = node.namedItem("x").toElement();
748 TQDomElement y = node.namedItem("y").toElement();
749 TQDomElement w = node.namedItem("width").toElement();
750 TQDomElement h = node.namedItem("height").toElement();
751
752 int rx = x.text().toInt();
753 int ry = y.text().toInt();
754 int rw = w.text().toInt();
755 int rh = h.text().toInt();
756
757 return TQRect(rx, ry, rw, rh);
758 }
759 else if(type == "color")
760 {
761 TQDomElement r = node.namedItem("red").toElement();
762 TQDomElement g = node.namedItem("green").toElement();
763 TQDomElement b = node.namedItem("blue").toElement();
764
765 int red = r.text().toInt();
766 int green = g.text().toInt();
767 int blue = b.text().toInt();
768
769 return TQColor(red, green, blue);
770 }
771 else if(type == "bool")
772 {
773 if(text == "true")
774 return TQVariant(true);
775 else if(text == "false")
776 return TQVariant(false);
777 return TQVariant(text.toInt());
778 }
779 else if(type == "number")
780 {
781 return text.toInt();
782 }
783 else if(type == "size")
784 {
785 TQDomElement w = node.namedItem("width").toElement();
786 TQDomElement h = node.namedItem("height").toElement();
787
788 return TQSize(w.text().toInt(), h.text().toInt());
789 }
790 else if(type == "point")
791 {
792 TQDomElement x = node.namedItem("x").toElement();
793 TQDomElement y = node.namedItem("y").toElement();
794
795 return TQPoint(x.text().toInt(), y.text().toInt());
796 }
797 else if(type == "font")
798 {
799 TQDomElement fa = node.namedItem("family").toElement();
800 TQDomElement p = node.namedItem("pointsize").toElement();
801 TQDomElement w = node.namedItem("weight").toElement();
802 TQDomElement b = node.namedItem("bold").toElement();
803 TQDomElement i = node.namedItem("italic").toElement();
804 TQDomElement u = node.namedItem("underline").toElement();
805 TQDomElement s = node.namedItem("strikeout").toElement();
806
807 TQFont f;
808 f.setFamily(fa.text());
809 f.setPointSize(p.text().toInt());
810 f.setWeight(w.text().toInt());
811 f.setBold(b.text().toInt());
812 f.setItalic(i.text().toInt());
813 f.setUnderline(u.text().toInt());
814 f.setStrikeOut(s.text().toInt());
815
816 return f;
817 }
818 else if(type == "cursor")
819 {
820 return TQCursor(text.toInt());
821 }
822 else if(type == "time")
823 {
824 TQDomElement h = node.namedItem("hour").toElement();
825 TQDomElement m = node.namedItem("minute").toElement();
826 TQDomElement s = node.namedItem("second").toElement();
827
828 return TQTime(h.text().toInt(), m.text().toInt(), s.text().toInt());
829 }
830 else if(type == "date")
831 {
832 TQDomElement y = node.namedItem("year").toElement();
833 TQDomElement m = node.namedItem("month").toElement();
834 TQDomElement d = node.namedItem("day").toElement();
835
836 return TQDate(y.text().toInt(), m.text().toInt(), d.text().toInt());
837 }
838 else if(type == "datetime")
839 {
840 TQDomElement h = node.namedItem("hour").toElement();
841 TQDomElement m = node.namedItem("minute").toElement();
842 TQDomElement s = node.namedItem("second").toElement();
843 TQDomElement y = node.namedItem("year").toElement();
844 TQDomElement mo = node.namedItem("month").toElement();
845 TQDomElement d = node.namedItem("day").toElement();
846
847 TQTime t(h.text().toInt(), m.text().toInt(), s.text().toInt());
848 TQDate da(y.text().toInt(), mo.text().toInt(), d.text().toInt());
849
850 return TQDateTime(da, t);
851 }
852 else if(type == "sizepolicy")
853 {
854 TQDomElement h = node.namedItem("hsizetype").toElement();
855 TQDomElement v = node.namedItem("vsizetype").toElement();
856 TQDomElement hs = node.namedItem("horstretch").toElement();
857 TQDomElement vs = node.namedItem("verstretch").toElement();
858
860 s.setHorData((TQSizePolicy::SizeType)h.text().toInt());
861 s.setVerData((TQSizePolicy::SizeType)v.text().toInt());
862 s.setHorStretch(hs.text().toInt());
863 s.setVerStretch(vs.text().toInt());
864 return s;
865 }
866 else if(type == "pixmap")
867 {
868 if(m_savePixmapsInline || !m_currentForm || !m_currentItem || !m_currentForm->pixmapCollection()->contains(text))
869 return loadImage(tag.ownerDocument(), text);
870 else
871 {
872 m_currentItem->setPixmapName(name.latin1(), text);
873 return m_currentForm->pixmapCollection()->getPixmap(text);
874 }
875 return TQVariant(TQPixmap());
876 }
877 else if(type == "enum")
878 return text;
879 else if(type == "set")
880 {
882 TQObject *subobject = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : obj;
883 const int count = subobject->metaObject()->findProperty(name.latin1(), true);
884 const TQMetaProperty *meta = count!=-1 ? subobject->metaObject()->property(count, true) : 0;
885
886 if (meta) {
887 if (meta->isSetType()) {
889 const TQStringList list( TQStringList::split("|", text) );
890 for (TQStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
891 keys.append((*it).latin1());
892
893 return meta->keysToValue(keys);
894 }
895 }
896 else {
897 // Metaproperty not found, probably because subwidget is not created.
898 // We will return a string list here with hope that names will
899 // be resolved and translated into an integer value later when subwidget is created,
900 // e.g. near KexiFormView::updateValuesForSubproperties()
901 return TQStringList::split("|", text);
902 }
903 }
904 return TQVariant();
905}
906
910
911void
912FormIO::saveWidget(ObjectTreeItem *item, TQDomElement &parent, TQDomDocument &domDoc, bool insideGridLayout)
913{
914 if (!item)
915 return;
916 bool savedAlignment = false;
917 // we let Spring class handle saving itself
918 if(item->className() == "Spring")
919 {
920 Spring::saveSpring(item, parent, domDoc, insideGridLayout);
921 return;
922 }
923
924 bool resetCurrentForm = false;
925 m_currentItem = item;
926 if(!m_currentForm) // copying widget
927 {
928 resetCurrentForm = true;
929 m_currentForm = item->container() ? item->container()->form() : item->parent()->container()->form();
930 }
931
932
933 WidgetLibrary *lib = m_currentForm->library();
934// if(item->container())
935// lib = item->container()->form()->manager()->lib();
936// else
937// lib = item->parent()->container()->form()->manager()->lib();
938
939 // We create the "widget" element
940 TQDomElement tclass = domDoc.createElement("widget");
941 parent.appendChild(tclass);
942
944 {
945 tclass.setAttribute("row", item->gridRow());
946 tclass.setAttribute("column", item->gridCol());
947 if(item->spanMultipleCells())
948 {
949 tclass.setAttribute("rowspan", item->gridRowSpan());
950 tclass.setAttribute("colspan", item->gridColSpan());
951 }
952 }
953
954 if(!item->parent()) // Toplevel widget
955 tclass.setAttribute("class", "TQWidget");
956 // For compatibility, HBox, VBox and Grid are saved as "TQLayoutWidget"
957 else if(item->widget()->isA("HBox") || item->widget()->isA("VBox") || item->widget()->isA("Grid")
958 || item->widget()->isA("HFlow") || item->widget()->isA("VFlow"))
959 tclass.setAttribute("class", "TQLayoutWidget");
960 else if(item->widget()->isA("CustomWidget"))
961 tclass.setAttribute("class", item->className());
962 else // Normal widgets
963 tclass.setAttribute("class", lib->savingName(item->widget()->className()) );
964
965 savePropertyValue(tclass, domDoc, "name", item->widget()->property("name"), item->widget());
966
967 // Important: save dataSource property FIRST before properties like "alignment"
968 // - needed when subproperties are defined after subwidget creation, and subwidget is created after setting "dataSource"
969 // (this is the case for KexiDBAutoField)
971// if (-1 != item->widget()->metaObject()->findProperty("dataSource"))
972 // savePropertyValue(tclass, domDoc, "dataSource", item->widget()->property("dataSource"), item->widget());
973
974 // We don't want to save the geometry if the widget is inside a layout (so parent.tagName() == "grid" for example)
975 if(item && !item->parent()) {
976 // save form widget size, but not its position
977 savePropertyValue(tclass, domDoc, "geometry",
978 TQRect( TQPoint(0,0), item->widget()->size()),
979 item->widget());
980 }
981 // normal widget (if == "UI', it means we're copying widget)
982 else if(parent.tagName() == "widget" || parent.tagName() == "UI")
983 savePropertyValue(tclass, domDoc, "geometry", item->widget()->property("geometry"), item->widget());
984
985 // Save the buddy widget for a label
986 if(item->widget()->inherits("TQLabel") && ((TQLabel*)item->widget())->buddy())
987 savePropertyElement(tclass, domDoc, "property", "buddy", ((TQLabel*)item->widget())->buddy()->name());
988
989 // We save every property in the modifProp list of the ObjectTreeItem
990 TQStringVariantMap *map = new TQStringVariantMap( *(item->modifiedProperties()) );
991 TQStringVariantMap::ConstIterator endIt = map->constEnd();
992 for(TQStringVariantMap::ConstIterator it = map->constBegin(); it != endIt; ++it)
993 {
994 const TQCString name( it.key().latin1() );
995 if(name == "hAlign" || name == "vAlign" || name == "wordbreak" || name == "alignment") {
996 if(!savedAlignment) // not to save it twice
997 {
998 savePropertyValue(tclass, domDoc, "alignment", item->widget()->property("alignment"), item->widget());
999 savedAlignment = true;
1000 }
1001 }
1002 else if(name == "name" || name == "geometry" || name == "layout") {
1003 // these have already been saved
1004 }
1005 else {
1006 savePropertyValue(tclass, domDoc, it.key().latin1(), item->widget()->property(it.key().latin1()),
1007 item->widget(), lib);
1008 }
1009 }
1010 delete map;
1011
1012 if(item->widget()->isA("CustomWidget")) {
1013 TQDomDocument doc("TEMP");
1014 doc.setContent(item->m_unknownProps);
1015 for(TQDomNode n = doc.firstChild(); !n.isNull(); n = n.nextSibling()) {
1016 tclass.appendChild(n.cloneNode());
1017 }
1018
1019 }
1020 // Saving container 's layout if there is one
1021 TQDomElement layout;
1022 if(item->container() && item->container()->layoutType() != Container::NoLayout)
1023 {
1024 if(item->container()->layout()) // there is a layout
1025 {
1026 layout = domDoc.createElement("temp");
1027 savePropertyValue(layout, domDoc, "name", "unnamed", item->widget());
1028 if(item->modifiedProperties()->contains("layoutMargin"))
1029 savePropertyElement(layout, domDoc, "property", "margin", item->container()->layoutMargin());
1030 if(item->modifiedProperties()->contains("layoutSpacing"))
1031 savePropertyElement(layout, domDoc, "property", "spacing", item->container()->layoutSpacing());
1032 tclass.appendChild(layout);
1033 }
1034 }
1035
1036 int layoutType = item->container() ? item->container()->layoutType() : Container::NoLayout;
1037 switch(layoutType) {
1038 case Container::Grid: // grid layout
1039 {
1040 layout.setTagName("grid");
1041 for(ObjectTreeItem *objIt = item->children()->first(); objIt; objIt = item->children()->next())
1042 saveWidget(objIt, layout, domDoc, true);
1043 break;
1044 }
1045 case Container::HBox: case Container::VBox:
1046 {
1047 // as we don't save geometry, we need to sort widgets in the right order, not creation order
1048 WidgetList *list;
1049 if(layout.tagName() == "hbox") {
1050 list = new HorWidgetList(item->container()->form()->toplevelContainer()->widget());
1051 layout.setTagName("hbox");
1052 }
1053 else {
1054 list = new VerWidgetList(item->container()->form()->toplevelContainer()->widget());
1055 layout.setTagName("vbox");
1056 }
1057
1058 for(ObjectTreeItem *objTree = item->children()->first(); objTree; objTree = item->children()->next())
1059 list->append(objTree->widget());
1060 list->sort();
1061
1062 for(TQWidget *obj = list->first(); obj; obj = list->next()) {
1063 ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup(obj->name());
1064 if(item)
1065 saveWidget(titem, layout, domDoc);
1066 }
1067 delete list;
1068 break;
1069 }
1070 case Container::HFlow: case Container::VFlow:
1071 {
1072 layout.setTagName("grid");
1073 KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
1074 if(!flow) break;
1075 WidgetList *list = (WidgetList*)flow->widgetList();
1076
1077 // save some special properties
1078 savePropertyElement(layout, domDoc, "property", "customLayout", Container::layoutTypeToString(item->container()->layoutType()) );
1079 savePropertyElement(layout, domDoc, "property", "justify", TQVariant(static_cast<KexiFlowLayout*>(item->container()->layout())->isJustified()) );
1080
1081 // fill the widget's grid info, ie just simulate grid layout
1082 item->container()->createGridLayout(true);
1083 for(TQWidget *obj = list->first(); obj; obj = list->next()) {
1084 ObjectTreeItem *titem = item->container()->form()->objectTree()->lookup(obj->name());
1085 if(item)
1086 saveWidget(titem, layout, domDoc, true); // save grid info for compatibility with TQtDesigner
1087 }
1088 delete list;
1089 break;
1090 }
1091 default:
1092 {
1093 for(ObjectTreeItem *objIt = item->children()->first(); objIt; objIt = item->children()->next())
1094 saveWidget(objIt, tclass, domDoc);
1095 }
1096 }
1097
1098 addIncludeFileName(lib->includeFileName(item->widget()->className()), domDoc);
1099
1101 m_currentForm = 0;
1102 m_currentItem = 0;
1103}
1104
1105void
1106FormIO::cleanClipboard(TQDomElement &uiElement)
1107{
1108 // remove includes element not needed
1109 if(!uiElement.namedItem("includes").isNull())
1110 uiElement.removeChild(uiElement.namedItem("includes"));
1111 // and ensure images and connection are at the end
1112 if(!uiElement.namedItem("connections").isNull())
1113 uiElement.insertAfter(uiElement.namedItem("connections"), TQDomNode());
1114 if(!uiElement.namedItem("images").isNull())
1115 uiElement.insertAfter(uiElement.namedItem("images"), TQDomNode());
1116}
1117
1118void
1119FormIO::loadWidget(Container *container, const TQDomElement &el, TQWidget *parent)
1120{
1121 bool resetCurrentForm = false;
1122 if(!m_currentForm) // pasting widget
1123 {
1124 resetCurrentForm = true;
1125 m_currentForm = container->form();
1126 }
1127
1128 // We first look for the widget's name
1129 TQString wname;
1130 for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
1131 {
1132 if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
1133 {
1134 wname = n.toElement().text();
1135 break;
1136 }
1137 }
1138
1139 TQWidget *w;
1140 TQCString classname, alternate;
1141 // We translate some name (for compatibility)
1142 if(el.tagName() == "spacer")
1143 classname = "Spring";
1144 else if(el.attribute("class") == "TQLayoutWidget")
1145 {
1146 for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
1147 {
1148 TQString tagName = n.toElement().tagName();
1149 if(tagName == "property")
1150 continue;
1151 if(tagName == "hbox")
1152 classname = "HBox";
1153 else if(tagName == "vbox")
1154 classname = "VBox";
1155 else if(tagName == "grid") {
1156 // first, see if it is flow layout
1157 for(TQDomNode child = n.firstChild(); !child.isNull(); child = child.nextSibling()) {
1158 if((child.toElement().tagName() == "property")
1159 && (child.toElement().attribute("name") == "customLayout"))
1160 {
1161 classname = child.toElement().text().latin1();
1162 break;
1163 }
1164 }
1165
1166 if(classname.isEmpty()) // normal grid
1167 classname = "Grid";
1168 }
1169 }
1170 }
1171 else
1172 // We check if this classname is an alternate one, and replace it if necessary
1173 {
1174 classname = el.attribute("class").latin1();
1176 }
1177
1178 if(alternate == "CustomWidget")
1179 w = new CustomWidget(classname, container->widget(), wname.latin1());
1180 else
1181 {
1182 if(!alternate.isNull())
1184
1185 int widgetOptions = WidgetFactory::DefaultOptions;
1186 if (!container->form()->designMode()) {
1188 }
1189
1190 if(!parent)
1191 w = container->form()->library()->createWidget(classname, container->widget(),
1192 wname.latin1(), container, widgetOptions);
1193 else
1194 w = container->form()->library()->createWidget(classname, parent, wname.latin1(),
1195 container, widgetOptions);
1196 }
1197
1198 if(!w)
1199 return;
1200#if TDE_VERSION >= TDE_MAKE_VERSION(3,4,0)
1202 if (m_currentForm->designMode()) {
1203 //don't generate accelerators for widgets in design mode
1204 TDEAcceleratorManager::setNoAccel(w);
1205 }
1206#endif
1207 w->setStyle(&(container->widget()->style()));
1208 w->show();
1209
1210 // We create and insert the ObjectTreeItem at the good place in the ObjectTree
1211 ObjectTreeItem *item = container->form()->objectTree()->lookup(wname);
1212 if (!item) {
1213 // not yet created
1214 item = new ObjectTreeItem(container->form()->library()->displayName(classname),
1215 wname, w, container);
1216 if(parent) {
1217 ObjectTreeItem *titem = container->form()->objectTree()->lookup(parent->name());
1218 if(titem)
1219 container->form()->objectTree()->addItem(titem, item);
1220 else
1221 kdDebug() << "FORMIO :: ERROR no parent widget " << endl;
1222 }
1223 else
1224 container->form()->objectTree()->addItem(container->objectTree(), item);
1225 }
1226 //assign item for its widget if it supports DesignTimeDynamicChildWidgetHandler interface
1227 //(e.g. KexiDBAutoField)
1228 if (container->form()->designMode() && dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)) {
1229 dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)->assignItem(item);
1230 }
1231
1232 m_currentItem = item;
1233 // if we are inside a Grid, we need to insert the widget in the good cell
1234 if(container->layoutType() == Container::Grid) {
1235 TQGridLayout *layout = (TQGridLayout*)container->layout();
1236 if(el.hasAttribute("rowspan")) { // widget spans multiple cells
1237 if(layout)
1238 layout->addMultiCellWidget(w, el.attribute("row").toInt(), el.attribute("row").toInt() + el.attribute("rowspan").toInt()-1,
1239 el.attribute("column").toInt(), el.attribute("column").toInt() + el.attribute("colspan").toInt()-1);
1240 item->setGridPos(el.attribute("row").toInt(), el.attribute("column").toInt(), el.attribute("rowspan").toInt(),
1241 el.attribute("colspan").toInt());
1242 }
1243 else {
1244 if(layout)
1245 layout->addWidget(w, el.attribute("row").toInt(), el.attribute("column").toInt());
1246 item->setGridPos(el.attribute("row").toInt(), el.attribute("column").toInt(), 0, 0);
1247 }
1248 }
1249 else if(container->layout())
1250 container->layout()->add(w);
1251
1252 readChildNodes(item, container, el, w);
1253
1254 if(item->container() && item->container()->layout())
1255 item->container()->layout()->activate();
1256
1257 // We add the autoSaveProperties in the modifProp list of the ObjectTreeItem, so that they are saved later
1258 TQValueList<TQCString> list(container->form()->library()->autoSaveProperties(w->className()));
1259 TQValueList<TQCString>::ConstIterator endIt = list.constEnd();
1262 TQWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;
1263 for(TQValueList<TQCString>::ConstIterator it = list.constBegin(); it != endIt; ++it) {
1264 if(subwidget->metaObject()->findProperty(*it, true) != -1)
1265 item->addModifiedProperty(*it, subwidget->property(*it));
1266 }
1267
1269 m_currentForm = 0;
1270 m_currentItem = 0;
1271}
1272
1273void
1274FormIO::createToplevelWidget(Form *form, TQWidget *container, TQDomElement &el)
1275{
1276 // We first look for the widget's name
1277 TQString wname;
1278 for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
1279 {
1280 if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
1281 {
1282 wname = n.toElement().text();
1283 break;
1284 }
1285
1286 }
1287 // And rename the widget and its ObjectTreeItem
1288 container->setName(wname.latin1());
1289 if(form->objectTree())
1290 form->objectTree()->rename(form->objectTree()->name(), wname);
1291 form->setInteractiveMode(false);
1292
1293 TQDict<TQLabel> *oldBuddies = 0;
1294 if(m_buddies) // save old buddies (for subforms)
1295 oldBuddies = m_buddies;
1296 m_buddies = new TQDict<TQLabel>();
1297 m_currentItem = form->objectTree();
1298
1299 readChildNodes(form->objectTree(), form->toplevelContainer(), el, container);
1300
1301 // Now the Form is fully loaded, we can assign the buddies
1302 TQDictIterator<TQLabel> it(*m_buddies);
1303 for(; it.current(); ++it)
1304 {
1305 ObjectTreeItem *item = form->objectTree()->lookup(it.currentKey());
1306 if(!item || !item->widget())
1307 {
1308 kdDebug() << "Cannot assign buddy for widget " << it.current()->name() << " to " << it.currentKey() << endl;
1309 continue;
1310 }
1311 it.current()->setBuddy(item->widget());
1312 }
1313 delete m_buddies;
1314 m_buddies = oldBuddies; // and restore it
1315
1316 m_currentItem = 0;
1317
1318 form->setInteractiveMode(true);
1319}
1320
1321void
1322FormIO::readChildNodes(ObjectTreeItem *item, Container *container, const TQDomElement &el, TQWidget *w)
1323{
1324 TQString eltag = el.tagName();
1325
1327 TQWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;
1328
1329 for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
1330 {
1331 TQString tag = n.toElement().tagName();
1332 TQDomElement node = n.toElement();
1333
1334 if((tag == "property") || (tag == "attribute"))
1335 {
1336 TQString name = node.attribute("name");
1337 //if(name == "geometry")
1338 // hasGeometryProp = true;
1339 if( ((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
1340 (name == "name")) // we don't care about layout names
1341 continue;
1342
1343 if (node.attribute("subwidget")=="true") {
1344 //this is property for subwidget: remember it for delayed setting
1345 //because now the subwidget could be not created yet (true e.g. for KexiDBAutoField)
1346 const TQVariant val( readPropertyValue(node.firstChild(), w, name) );
1347 kdDebug() << val.toStringList() << endl;
1348 item->addSubproperty( name.latin1(), val );
1349 //subwidget->setProperty(name.latin1(), val);
1350 item->addModifiedProperty( name.latin1(), val );
1351 continue;
1352 }
1353
1354 // We cannot assign the buddy now as the buddy widget may not be created yet
1355 if(name == "buddy")
1356 m_buddies->insert(readPropertyValue(node.firstChild(), w, name).toString(), (TQLabel*)w);
1357 else if(((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
1358 item->container() && item->container()->layout()) {
1359 // We load the margin of a Layout
1360 if(name == "margin") {
1361 int margin = readPropertyValue(node.firstChild(), w, name).toInt();
1363 item->container()->layout()->setMargin(margin);
1364 }
1365 // We load the spacing of a Layout
1366 else if(name == "spacing") {
1367 int spacing = readPropertyValue(node.firstChild(), w, name).toInt();
1369 item->container()->layout()->setSpacing(spacing);
1370 }
1371 else if((name == "justify")){
1372 bool justify = readPropertyValue(node.firstChild(), w, name).toBool();
1373 KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
1374 if(flow)
1375 flow->setJustified(justify);
1376 }
1377 }
1378 // If the object doesn't have this property, we let the Factory handle it (maybe a special property)
1379 else if(subwidget->metaObject()->findProperty(name.latin1(), true) == -1)
1380 {
1381 if(w->className() == TQString::fromLatin1("CustomWidget"))
1382 item->storeUnknownProperty(node);
1383 else {
1384 bool read = container->form()->library()->readSpecialProperty(
1385 w->className(), node, w, item);
1386 if(!read) // the factory doesn't support this property neither
1387 item->storeUnknownProperty(node);
1388 }
1389 }
1390 else // we have a normal property, let's load it
1391 {
1392 TQVariant val( readPropertyValue(node.firstChild(), w, name) );
1393 if(name == "geometry" && dynamic_cast<FormWidget*>(w)) {
1394 //fix geometry if needed - this is top level form widget
1395 TQRect r( val.toRect() );
1396 if (r.left()<0) //negative X!
1397 r.moveLeft(0);
1398 if (r.top()<0) //negative Y!
1399 r.moveTop(0);
1400 val = r;
1401 }
1402 subwidget->setProperty(name.latin1(), val);
1403// int count = w->metaObject()->findProperty(name, true);
1404// const TQMetaProperty *meta = w->metaObject()->property(count, true);
1405// if(meta && meta->isEnumType()) {
1406// val = w->property(name.latin1()); //update: we want a numeric value of enum
1407// }
1408 item->addModifiedProperty(name.latin1(), val);
1409 }
1410 }
1411 else if(tag == "widget") // a child widget
1412 {
1413 if(item->container()) // we are a Container
1414 loadWidget(item->container(), node);
1415 else
1416 loadWidget(container, node, w);
1417 }
1418 else if(tag == "spacer") {
1419 loadWidget(container, node, w);
1420 }
1421 else if(tag == "grid") {
1422 // first, see if it is flow layout
1423 TQString layoutName;
1424 for(TQDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) {
1425 if((child.toElement().tagName() == "property") && (child.toElement().attribute("name") == "customLayout")) {
1426 layoutName = child.toElement().text();
1427 break;
1428 }
1429 }
1430
1431 if(layoutName == "HFlow") {
1432 item->container()->m_layType = Container::HFlow;
1433 KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
1434 layout->setOrientation(TQt::Horizontal);
1435 item->container()->m_layout = (TQLayout*)layout;
1436 }
1437 else if(layoutName == "VFlow") {
1438 item->container()->m_layType = Container::VFlow;
1439 KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
1440 layout->setOrientation(TQt::Vertical);
1441 item->container()->m_layout = (TQLayout*)layout;
1442 }
1443 else { // grid layout
1444 item->container()->m_layType = Container::Grid;
1445 TQGridLayout *layout = new TQGridLayout(item->widget(), 1, 1);
1446 item->container()->m_layout = (TQLayout*)layout;
1447 }
1448 readChildNodes(item, container, node, w);
1449 }
1450 else if(tag == "vbox") {
1451 item->container()->m_layType = Container::VBox;
1452 TQVBoxLayout *layout = new TQVBoxLayout(item->widget());
1453 item->container()->m_layout = (TQLayout*)layout;
1454 readChildNodes(item, container, node, w);
1455 }
1456 else if(tag == "hbox") {
1457 item->container()->m_layType = Container::HBox;
1458 TQHBoxLayout *layout = new TQHBoxLayout(item->widget());
1459 item->container()->m_layout = (TQLayout*)layout;
1460 readChildNodes(item, container, node, w);
1461 }
1462 else {// unknown tag, we let the Factory handle it
1463 if(w->className() == TQString::fromLatin1("CustomWidget"))
1464 item->storeUnknownProperty(node);
1465 else {
1466 bool read = container->form()->library()->readSpecialProperty(
1467 w->className(), node, w, item);
1468 if(!read) // the factory doesn't suport this property neither
1469 item->storeUnknownProperty(node);
1470 }
1471 }
1472 }
1473}
1474
1478
1479void
1480FormIO::addIncludeFileName(const TQString &include, TQDomDocument &domDoc)
1481{
1482 if(include.isEmpty())
1483 return;
1484
1486 TQDomElement uiEl = domDoc.namedItem("UI").toElement();
1487 if(uiEl.namedItem("includes").isNull())
1488 {
1489 includes = domDoc.createElement("includes");
1490 uiEl.appendChild(includes);
1491 }
1492 else
1493 includes = uiEl.namedItem("includes").toElement();
1494
1495 // Check if this include has already been saved, and return if it is the case
1496 for(TQDomNode n = includes.firstChild(); !n.isNull(); n = n.nextSibling())
1497 {
1498 if(n.toElement().text() == include)
1499 return;
1500 }
1501
1502 TQDomElement includeElement = domDoc.createElement("include");
1503 includes.appendChild(includeElement);
1504 includeElement.setAttribute("location", "global");
1505 includeElement.setAttribute("impldecl", "in implementation");
1506 TQDomText includeText = domDoc.createTextNode(include);
1507 includeElement.appendChild(includeText);
1508}
1509
1511
1512TQString
1513FormIO::saveImage(TQDomDocument &domDoc, const TQPixmap &pixmap)
1514{
1515 TQDomNode node = domDoc.namedItem("images");
1517 if(node.isNull())
1518 {
1519 images = domDoc.createElement("images");
1520 TQDomElement ui = domDoc.namedItem("UI").toElement();
1521 ui.appendChild(images);
1522 }
1523 else
1524 images = node.toElement();
1525
1526 int count = images.childNodes().count();
1527 TQDomElement image = domDoc.createElement("image");
1528 TQString name = "image" + TQString::number(count);
1529 image.setAttribute("name", name);
1530
1531 TQImage img = pixmap.convertToImage();
1532 TQByteArray ba;
1533 TQBuffer buf(ba);
1534 buf.open( IO_WriteOnly | IO_Translate );
1535 TQString format = img.depth() > 1 ? "XPM" : "XBM";
1536 TQImageIO iio( &buf, format.latin1() );
1537 iio.setImage( img );
1538 iio.write();
1539 buf.close();
1540 TQByteArray bazip = tqCompress( ba );
1541 ulong len = bazip.size();
1542
1543 TQDomElement data = domDoc.createElement("data");
1544 data.setAttribute("format", format + ".GZ");
1545 data.setAttribute("length", ba.size());
1546
1547 static const char hexchars[] = "0123456789abcdef";
1548 TQString content;
1549 for(int i = 4; i < (int)len; ++i)
1550 {
1551 uchar s = (uchar) bazip[i];
1552 content += hexchars[s >> 4];
1553 content += hexchars[s & 0x0f];
1554 }
1555
1556 TQDomText text = domDoc.createTextNode(content);
1557 data.appendChild(text);
1558 image.appendChild(data);
1559 images.appendChild(image);
1560
1561 return name;
1562}
1563
1564TQPixmap
1565FormIO::loadImage(TQDomDocument domDoc, const TQString& name)
1566{
1567 TQDomElement images = domDoc.namedItem("UI").namedItem("images").toElement();
1568 if(images.isNull())
1569 return 0;
1570
1572 for(TQDomNode n = images.firstChild(); !n.isNull(); n = n.nextSibling())
1573 {
1574 if((n.toElement().tagName() == "image") && (n.toElement().attribute("name") == name))
1575 {
1576 image = n.toElement();
1577 break;
1578 }
1579 }
1580
1581 TQPixmap pix;
1582 TQString data = image.namedItem("data").toElement().text();
1583 const int lengthOffset = 4;
1584 int baSize = data.length() / 2 + lengthOffset;
1585 uchar *ba = new uchar[baSize];
1586 for(int i = lengthOffset; i < baSize; ++i)
1587 {
1588 char h = data[2 * (i-lengthOffset)].latin1();
1589 char l = data[2 * (i-lengthOffset) + 1].latin1();
1590 uchar r = 0;
1591 if(h <= '9')
1592 r += h - '0';
1593 else
1594 r += h - 'a' + 10;
1595 r = r << 4;
1596 if(l <= '9')
1597 r += l - '0';
1598 else
1599 r += l - 'a' + 10;
1600 ba[i] = r;
1601 }
1602
1603 TQString format = image.namedItem("data").toElement().attribute("format", "PNG");
1604 if((format == "XPM.GZ") || (format == "XBM.GZ"))
1605 {
1606 ulong len = image.attribute("length").toULong();
1607 if(len < data.length() * 5)
1608 len = data.length() * 5;
1609 // tqUncompress() expects the first 4 bytes to be the expected length of
1610 // the uncompressed data
1611 ba[0] = ( len & 0xff000000 ) >> 24;
1612 ba[1] = ( len & 0x00ff0000 ) >> 16;
1613 ba[2] = ( len & 0x0000ff00 ) >> 8;
1614 ba[3] = ( len & 0x000000ff );
1615 TQByteArray baunzip = tqUncompress(ba, baSize);
1616 pix.loadFromData( (const uchar*)baunzip.data(), baunzip.size(), format.left(format.find('.')).latin1() );
1617 }
1618 else
1619 pix.loadFromData( (const uchar*)ba+lengthOffset, baSize-lengthOffset, format.latin1() );
1620
1621 delete[] ba;
1622
1623 return pix;
1624}
1625
1627
1628#include "formIO.moc"
A blank widget displayed when class is not supported.
Definition formIO.h:40
CustomWidget(const TQCString &className, TQWidget *parent, const char *name)
A blank widget used when the class name is not supported.
Definition formIO.cpp:55
This class makes a container out of any TQWidget.
Definition container.h:74
void setLayoutMargin(int margin)
Sets the margin of this Container.
Definition container.h:127
TQWidget * widget() const
Definition container.h:94
void setLayoutSpacing(int spacing)
Sets the spacing of this Container.
Definition container.h:124
ObjectTreeItem * objectTree() const
Definition container.h:97
LayoutType layoutType() const
Definition container.h:110
static TQString layoutTypeToString(int type)
void createGridLayout(bool testOnly=false)
TQLayout * layout() const
Definition container.h:107
Form * form() const
Definition container.h:91
Interface for adding dynamically created (at design time) widget to event eater.
Definition container.h:233
Base (virtual) class for all form widgets.
Definition form.h:54
A simple class representing a form.
Definition form.h:136
int defaultMargin()
Definition form.h:235
uint formatVersion() const
Definition form.cpp:572
TQMap< TQCString, TQString > * headerProperties() const
Definition form.h:309
bool autoTabStops() const
Definition form.h:279
Container * toplevelContainer() const
Definition form.h:161
void autoAssignTabStops()
Definition form.cpp:507
WidgetLibrary * library() const
Definition form.h:147
ObjectTree * objectTree() const
Definition form.h:167
bool designMode() const
Definition form.h:226
void setFilename(const TQString &file)
Sets the filename of this Form to filename.
Definition form.h:251
TQString filename() const
Definition form.h:248
ObjectTreeList * tabStops() const
Definition form.h:267
void setDesignMode(bool design)
Definition form.cpp:214
void setInteractiveMode(bool interactive)
Definition form.h:210
int defaultSpacing()
Definition form.h:238
A helper for sorting widgets horizontally.
An item representing a widget Holds the properties of a widget (classname, name, parent,...
Definition objecttree.h:59
Container * container() const
Definition objecttree.h:76
const TQStringVariantMap * modifiedProperties() const
Definition objecttree.h:73
void addModifiedProperty(const TQCString &property, const TQVariant &oldValue)
void addSubproperty(const TQCString &property, const TQVariant &value)
bool rename(const TQString &oldname, const TQString &newname)
ObjectTreeItem * lookup(const TQString &name)
A helper for sorting widgets vertically.
@ DesignViewMode
create widget in design view mode, otherwise preview mode
This class searches for factories and provides TDEActions for widget creation.
TQCString classNameForAlternate(const TQCString &classname)
TQWidget * createWidget(const TQCString &classname, TQWidget *parent, const char *name, Container *c, int options=WidgetFactory::DefaultOptions)
searches the right factory and creates a widget.
An interface for declaring form widgets to have subproperties.
a special "flow" layout
void setOrientation(TQt::Orientation orientation)
TQPtrList< TQWidget > * widgetList() const
TQPtrList< TQWidget > WidgetList
A list of widget pointers.
TQPtrListIterator< ObjectTreeItem > ObjectTreeListIterator
An iterator for ObjectTreeList.
Definition objecttree.h:45
type * findParent(TQObject *o, const char *className, TQObject *&prevPrev)