kexi

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
122 TQFile file(m_filename);
123 if (!file.open(IO_WriteOnly))
124 return false;
125
126 TQTextStream stream(&file);
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
288 TQFile file(m_filename);
289 if(!file.open(IO_ReadOnly))
290 {
291 kdDebug() << "Cannot open the file " << filename << endl;
292 return false;
293 }
294 TQTextStream stream(&file);
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) {
381 itemsNotFound++;
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);
428 if (addSubwidgetFlag)
429 propertyE.setAttribute("subwidget", "true");
430
431 if(meta && meta->isEnumType())
432 {
433 // this property is enum or set type
434 TQDomElement type;
435 TQDomText valueE;
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) {
457 TQDomText valueE;
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;
480 TQDomText valueE;
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
859 TQSizePolicy s;
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 {
881 WidgetWithSubpropertiesInterface* subpropIface = dynamic_cast<WidgetWithSubpropertiesInterface*>(obj);
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()) {
888 TQStrList keys;
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
943 if(insideGridLayout)
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
1100 if(resetCurrentForm)
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();
1175 alternate = container->form()->library()->classNameForAlternate(classname);
1176 }
1177
1178 if(alternate == "CustomWidget")
1179 w = new CustomWidget(classname, container->widget(), wname.latin1());
1180 else
1181 {
1182 if(!alternate.isNull())
1183 classname = alternate;
1184
1185 int widgetOptions = WidgetFactory::DefaultOptions;
1186 if (!container->form()->designMode()) {
1187 widgetOptions ^= WidgetFactory::DesignViewMode;
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;
1201 if (m_currentForm->designMode()) {
1202 //don't generate accelerators for widgets in design mode
1203 TDEAcceleratorManager::setNoAccel(w);
1204 }
1205 w->setStyle(&(container->widget()->style()));
1206 w->show();
1207
1208 // We create and insert the ObjectTreeItem at the good place in the ObjectTree
1209 ObjectTreeItem *item = container->form()->objectTree()->lookup(wname);
1210 if (!item) {
1211 // not yet created
1212 item = new ObjectTreeItem(container->form()->library()->displayName(classname),
1213 wname, w, container);
1214 if(parent) {
1215 ObjectTreeItem *titem = container->form()->objectTree()->lookup(parent->name());
1216 if(titem)
1217 container->form()->objectTree()->addItem(titem, item);
1218 else
1219 kdDebug() << "FORMIO :: ERROR no parent widget " << endl;
1220 }
1221 else
1222 container->form()->objectTree()->addItem(container->objectTree(), item);
1223 }
1224 //assign item for its widget if it supports DesignTimeDynamicChildWidgetHandler interface
1225 //(e.g. KexiDBAutoField)
1226 if (container->form()->designMode() && dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)) {
1227 dynamic_cast<DesignTimeDynamicChildWidgetHandler*>(w)->assignItem(item);
1228 }
1229
1230 m_currentItem = item;
1231 // if we are inside a Grid, we need to insert the widget in the good cell
1232 if(container->layoutType() == Container::Grid) {
1233 TQGridLayout *layout = (TQGridLayout*)container->layout();
1234 if(el.hasAttribute("rowspan")) { // widget spans multiple cells
1235 if(layout)
1236 layout->addMultiCellWidget(w, el.attribute("row").toInt(), el.attribute("row").toInt() + el.attribute("rowspan").toInt()-1,
1237 el.attribute("column").toInt(), el.attribute("column").toInt() + el.attribute("colspan").toInt()-1);
1238 item->setGridPos(el.attribute("row").toInt(), el.attribute("column").toInt(), el.attribute("rowspan").toInt(),
1239 el.attribute("colspan").toInt());
1240 }
1241 else {
1242 if(layout)
1243 layout->addWidget(w, el.attribute("row").toInt(), el.attribute("column").toInt());
1244 item->setGridPos(el.attribute("row").toInt(), el.attribute("column").toInt(), 0, 0);
1245 }
1246 }
1247 else if(container->layout())
1248 container->layout()->add(w);
1249
1250 readChildNodes(item, container, el, w);
1251
1252 if(item->container() && item->container()->layout())
1253 item->container()->layout()->activate();
1254
1255 // We add the autoSaveProperties in the modifProp list of the ObjectTreeItem, so that they are saved later
1256 TQValueList<TQCString> list(container->form()->library()->autoSaveProperties(w->className()));
1257 TQValueList<TQCString>::ConstIterator endIt = list.constEnd();
1260 TQWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;
1261 for(TQValueList<TQCString>::ConstIterator it = list.constBegin(); it != endIt; ++it) {
1262 if(subwidget->metaObject()->findProperty(*it, true) != -1)
1263 item->addModifiedProperty(*it, subwidget->property(*it));
1264 }
1265
1266 if(resetCurrentForm)
1267 m_currentForm = 0;
1268 m_currentItem = 0;
1269}
1270
1271void
1272FormIO::createToplevelWidget(Form *form, TQWidget *container, TQDomElement &el)
1273{
1274 // We first look for the widget's name
1275 TQString wname;
1276 for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
1277 {
1278 if((n.toElement().tagName() == "property") && (n.toElement().attribute("name") == "name"))
1279 {
1280 wname = n.toElement().text();
1281 break;
1282 }
1283
1284 }
1285 // And rename the widget and its ObjectTreeItem
1286 container->setName(wname.latin1());
1287 if(form->objectTree())
1288 form->objectTree()->rename(form->objectTree()->name(), wname);
1289 form->setInteractiveMode(false);
1290
1291 TQDict<TQLabel> *oldBuddies = 0;
1292 if(m_buddies) // save old buddies (for subforms)
1293 oldBuddies = m_buddies;
1294 m_buddies = new TQDict<TQLabel>();
1295 m_currentItem = form->objectTree();
1296
1297 readChildNodes(form->objectTree(), form->toplevelContainer(), el, container);
1298
1299 // Now the Form is fully loaded, we can assign the buddies
1300 TQDictIterator<TQLabel> it(*m_buddies);
1301 for(; it.current(); ++it)
1302 {
1303 ObjectTreeItem *item = form->objectTree()->lookup(it.currentKey());
1304 if(!item || !item->widget())
1305 {
1306 kdDebug() << "Cannot assign buddy for widget " << it.current()->name() << " to " << it.currentKey() << endl;
1307 continue;
1308 }
1309 it.current()->setBuddy(item->widget());
1310 }
1311 delete m_buddies;
1312 m_buddies = oldBuddies; // and restore it
1313
1314 m_currentItem = 0;
1315
1316 form->setInteractiveMode(true);
1317}
1318
1319void
1320FormIO::readChildNodes(ObjectTreeItem *item, Container *container, const TQDomElement &el, TQWidget *w)
1321{
1322 TQString eltag = el.tagName();
1323
1325 TQWidget *subwidget = (subpropIface && subpropIface->subwidget()) ? subpropIface->subwidget() : w;
1326
1327 for(TQDomNode n = el.firstChild(); !n.isNull(); n = n.nextSibling())
1328 {
1329 TQString tag = n.toElement().tagName();
1330 TQDomElement node = n.toElement();
1331
1332 if((tag == "property") || (tag == "attribute"))
1333 {
1334 TQString name = node.attribute("name");
1335 //if(name == "geometry")
1336 // hasGeometryProp = true;
1337 if( ((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
1338 (name == "name")) // we don't care about layout names
1339 continue;
1340
1341 if (node.attribute("subwidget")=="true") {
1342 //this is property for subwidget: remember it for delayed setting
1343 //because now the subwidget could be not created yet (true e.g. for KexiDBAutoField)
1344 const TQVariant val( readPropertyValue(node.firstChild(), w, name) );
1345 kdDebug() << val.toStringList() << endl;
1346 item->addSubproperty( name.latin1(), val );
1347 //subwidget->setProperty(name.latin1(), val);
1348 item->addModifiedProperty( name.latin1(), val );
1349 continue;
1350 }
1351
1352 // We cannot assign the buddy now as the buddy widget may not be created yet
1353 if(name == "buddy")
1354 m_buddies->insert(readPropertyValue(node.firstChild(), w, name).toString(), (TQLabel*)w);
1355 else if(((eltag == "grid") || (eltag == "hbox") || (eltag == "vbox")) &&
1356 item->container() && item->container()->layout()) {
1357 // We load the margin of a Layout
1358 if(name == "margin") {
1359 int margin = readPropertyValue(node.firstChild(), w, name).toInt();
1360 item->container()->setLayoutMargin(margin);
1361 item->container()->layout()->setMargin(margin);
1362 }
1363 // We load the spacing of a Layout
1364 else if(name == "spacing") {
1365 int spacing = readPropertyValue(node.firstChild(), w, name).toInt();
1366 item->container()->setLayoutSpacing(spacing);
1367 item->container()->layout()->setSpacing(spacing);
1368 }
1369 else if((name == "justify")){
1370 bool justify = readPropertyValue(node.firstChild(), w, name).toBool();
1371 KexiFlowLayout *flow = static_cast<KexiFlowLayout*>(item->container()->layout());
1372 if(flow)
1373 flow->setJustified(justify);
1374 }
1375 }
1376 // If the object doesn't have this property, we let the Factory handle it (maybe a special property)
1377 else if(subwidget->metaObject()->findProperty(name.latin1(), true) == -1)
1378 {
1379 if(w->className() == TQString::fromLatin1("CustomWidget"))
1380 item->storeUnknownProperty(node);
1381 else {
1382 bool read = container->form()->library()->readSpecialProperty(
1383 w->className(), node, w, item);
1384 if(!read) // the factory doesn't support this property neither
1385 item->storeUnknownProperty(node);
1386 }
1387 }
1388 else // we have a normal property, let's load it
1389 {
1390 TQVariant val( readPropertyValue(node.firstChild(), w, name) );
1391 if(name == "geometry" && dynamic_cast<FormWidget*>(w)) {
1392 //fix geometry if needed - this is top level form widget
1393 TQRect r( val.toRect() );
1394 if (r.left()<0) //negative X!
1395 r.moveLeft(0);
1396 if (r.top()<0) //negative Y!
1397 r.moveTop(0);
1398 val = r;
1399 }
1400 subwidget->setProperty(name.latin1(), val);
1401// int count = w->metaObject()->findProperty(name, true);
1402// const TQMetaProperty *meta = w->metaObject()->property(count, true);
1403// if(meta && meta->isEnumType()) {
1404// val = w->property(name.latin1()); //update: we want a numeric value of enum
1405// }
1406 item->addModifiedProperty(name.latin1(), val);
1407 }
1408 }
1409 else if(tag == "widget") // a child widget
1410 {
1411 if(item->container()) // we are a Container
1412 loadWidget(item->container(), node);
1413 else
1414 loadWidget(container, node, w);
1415 }
1416 else if(tag == "spacer") {
1417 loadWidget(container, node, w);
1418 }
1419 else if(tag == "grid") {
1420 // first, see if it is flow layout
1421 TQString layoutName;
1422 for(TQDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) {
1423 if((child.toElement().tagName() == "property") && (child.toElement().attribute("name") == "customLayout")) {
1424 layoutName = child.toElement().text();
1425 break;
1426 }
1427 }
1428
1429 if(layoutName == "HFlow") {
1430 item->container()->m_layType = Container::HFlow;
1431 KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
1432 layout->setOrientation(TQt::Horizontal);
1433 item->container()->m_layout = (TQLayout*)layout;
1434 }
1435 else if(layoutName == "VFlow") {
1436 item->container()->m_layType = Container::VFlow;
1437 KexiFlowLayout *layout = new KexiFlowLayout(item->widget());
1438 layout->setOrientation(TQt::Vertical);
1439 item->container()->m_layout = (TQLayout*)layout;
1440 }
1441 else { // grid layout
1442 item->container()->m_layType = Container::Grid;
1443 TQGridLayout *layout = new TQGridLayout(item->widget(), 1, 1);
1444 item->container()->m_layout = (TQLayout*)layout;
1445 }
1446 readChildNodes(item, container, node, w);
1447 }
1448 else if(tag == "vbox") {
1449 item->container()->m_layType = Container::VBox;
1450 TQVBoxLayout *layout = new TQVBoxLayout(item->widget());
1451 item->container()->m_layout = (TQLayout*)layout;
1452 readChildNodes(item, container, node, w);
1453 }
1454 else if(tag == "hbox") {
1455 item->container()->m_layType = Container::HBox;
1456 TQHBoxLayout *layout = new TQHBoxLayout(item->widget());
1457 item->container()->m_layout = (TQLayout*)layout;
1458 readChildNodes(item, container, node, w);
1459 }
1460 else {// unknown tag, we let the Factory handle it
1461 if(w->className() == TQString::fromLatin1("CustomWidget"))
1462 item->storeUnknownProperty(node);
1463 else {
1464 bool read = container->form()->library()->readSpecialProperty(
1465 w->className(), node, w, item);
1466 if(!read) // the factory doesn't suport this property neither
1467 item->storeUnknownProperty(node);
1468 }
1469 }
1470 }
1471}
1472
1476
1477void
1478FormIO::addIncludeFileName(const TQString &include, TQDomDocument &domDoc)
1479{
1480 if(include.isEmpty())
1481 return;
1482
1483 TQDomElement includes;
1484 TQDomElement uiEl = domDoc.namedItem("UI").toElement();
1485 if(uiEl.namedItem("includes").isNull())
1486 {
1487 includes = domDoc.createElement("includes");
1488 uiEl.appendChild(includes);
1489 }
1490 else
1491 includes = uiEl.namedItem("includes").toElement();
1492
1493 // Check if this include has already been saved, and return if it is the case
1494 for(TQDomNode n = includes.firstChild(); !n.isNull(); n = n.nextSibling())
1495 {
1496 if(n.toElement().text() == include)
1497 return;
1498 }
1499
1500 TQDomElement includeElement = domDoc.createElement("include");
1501 includes.appendChild(includeElement);
1502 includeElement.setAttribute("location", "global");
1503 includeElement.setAttribute("impldecl", "in implementation");
1504 TQDomText includeText = domDoc.createTextNode(include);
1505 includeElement.appendChild(includeText);
1506}
1507
1509
1510TQString
1511FormIO::saveImage(TQDomDocument &domDoc, const TQPixmap &pixmap)
1512{
1513 TQDomNode node = domDoc.namedItem("images");
1514 TQDomElement images;
1515 if(node.isNull())
1516 {
1517 images = domDoc.createElement("images");
1518 TQDomElement ui = domDoc.namedItem("UI").toElement();
1519 ui.appendChild(images);
1520 }
1521 else
1522 images = node.toElement();
1523
1524 int count = images.childNodes().count();
1525 TQDomElement image = domDoc.createElement("image");
1526 TQString name = "image" + TQString::number(count);
1527 image.setAttribute("name", name);
1528
1529 TQImage img = pixmap.convertToImage();
1530 TQByteArray ba;
1531 TQBuffer buf(ba);
1532 buf.open( IO_WriteOnly | IO_Translate );
1533 TQString format = img.depth() > 1 ? "XPM" : "XBM";
1534 TQImageIO iio( &buf, format.latin1() );
1535 iio.setImage( img );
1536 iio.write();
1537 buf.close();
1538 TQByteArray bazip = tqCompress( ba );
1539 ulong len = bazip.size();
1540
1541 TQDomElement data = domDoc.createElement("data");
1542 data.setAttribute("format", format + ".GZ");
1543 data.setAttribute("length", ba.size());
1544
1545 static const char hexchars[] = "0123456789abcdef";
1546 TQString content;
1547 for(int i = 4; i < (int)len; ++i)
1548 {
1549 uchar s = (uchar) bazip[i];
1550 content += hexchars[s >> 4];
1551 content += hexchars[s & 0x0f];
1552 }
1553
1554 TQDomText text = domDoc.createTextNode(content);
1555 data.appendChild(text);
1556 image.appendChild(data);
1557 images.appendChild(image);
1558
1559 return name;
1560}
1561
1562TQPixmap
1563FormIO::loadImage(TQDomDocument domDoc, const TQString& name)
1564{
1565 TQDomElement images = domDoc.namedItem("UI").namedItem("images").toElement();
1566 if(images.isNull())
1567 return 0;
1568
1569 TQDomElement image;
1570 for(TQDomNode n = images.firstChild(); !n.isNull(); n = n.nextSibling())
1571 {
1572 if((n.toElement().tagName() == "image") && (n.toElement().attribute("name") == name))
1573 {
1574 image = n.toElement();
1575 break;
1576 }
1577 }
1578
1579 TQPixmap pix;
1580 TQString data = image.namedItem("data").toElement().text();
1581 const int lengthOffset = 4;
1582 int baSize = data.length() / 2 + lengthOffset;
1583 uchar *ba = new uchar[baSize];
1584 for(int i = lengthOffset; i < baSize; ++i)
1585 {
1586 char h = data[2 * (i-lengthOffset)].latin1();
1587 char l = data[2 * (i-lengthOffset) + 1].latin1();
1588 uchar r = 0;
1589 if(h <= '9')
1590 r += h - '0';
1591 else
1592 r += h - 'a' + 10;
1593 r = r << 4;
1594 if(l <= '9')
1595 r += l - '0';
1596 else
1597 r += l - 'a' + 10;
1598 ba[i] = r;
1599 }
1600
1601 TQString format = image.namedItem("data").toElement().attribute("format", "PNG");
1602 if((format == "XPM.GZ") || (format == "XBM.GZ"))
1603 {
1604 ulong len = image.attribute("length").toULong();
1605 if(len < data.length() * 5)
1606 len = data.length() * 5;
1607 // tqUncompress() expects the first 4 bytes to be the expected length of
1608 // the uncompressed data
1609 ba[0] = ( len & 0xff000000 ) >> 24;
1610 ba[1] = ( len & 0x00ff0000 ) >> 16;
1611 ba[2] = ( len & 0x0000ff00 ) >> 8;
1612 ba[3] = ( len & 0x000000ff );
1613 TQByteArray baunzip = tqUncompress(ba, baSize);
1614 pix.loadFromData( (const uchar*)baunzip.data(), baunzip.size(), format.left(format.find('.')).latin1() );
1615 }
1616 else
1617 pix.loadFromData( (const uchar*)ba+lengthOffset, baSize-lengthOffset, format.latin1() );
1618
1619 delete[] ba;
1620
1621 return pix;
1622}
1623
1625
1626#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
static void writeVariant(TQDomDocument &parent, TQDomElement &parentNode, TQVariant value)
Definition formIO.cpp:477
static void cleanClipboard(TQDomElement &uiElement)
Definition formIO.cpp:1106
static TQPixmap loadImage(TQDomDocument domDoc, const TQString &name)
Definition formIO.cpp:1563
static void readChildNodes(ObjectTreeItem *tree, Container *container, const TQDomElement &el, TQWidget *w)
Definition formIO.cpp:1320
static bool saveFormToByteArray(Form *form, TQByteArray &dest)
Definition formIO.cpp:134
static void savePropertyElement(TQDomElement &parentNode, TQDomDocument &domDoc, const TQString &tagName, const TQString &property, const TQVariant &value)
Definition formIO.cpp:728
static bool loadFormFromFile(Form *form, TQWidget *container, const TQString &filename=TQString())
Definition formIO.cpp:272
static bool loadFormFromByteArray(Form *form, TQWidget *container, TQByteArray &src, bool preview=false)
Definition formIO.cpp:220
static bool saveFormToDom(Form *form, TQDomDocument &domDoc)
Definition formIO.cpp:154
static bool saveFormToString(Form *form, TQString &dest, int indent=0)
Definition formIO.cpp:144
static void saveWidget(ObjectTreeItem *item, TQDomElement &parent, TQDomDocument &domDoc, bool insideGridLayout=false)
Definition formIO.cpp:912
static void createToplevelWidget(Form *form, TQWidget *container, TQDomElement &element)
Definition formIO.cpp:1272
static TQString saveImage(TQDomDocument &domDoc, const TQPixmap &pixmap)
Definition formIO.cpp:1511
static void addIncludeFileName(const TQString &include, TQDomDocument &domDoc)
Definition formIO.cpp:1478
static bool saveFormToFile(Form *form, const TQString &filename=TQString())
Definition formIO.cpp:102
static TQVariant readPropertyValue(TQDomNode node, TQObject *obj, const TQString &name)
Definition formIO.cpp:737
static void loadWidget(Container *container, const TQDomElement &el, TQWidget *parent=0)
Definition formIO.cpp:1119
static void savePropertyValue(TQDomElement &parentNode, TQDomDocument &parent, const char *name, const TQVariant &value, TQWidget *w, WidgetLibrary *lib=0)
Definition formIO.cpp:401
static bool loadFormFromDom(Form *form, TQWidget *container, TQDomDocument &domDoc)
Definition formIO.cpp:311
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.
KFORMEDITOR_EXPORT uint version()
Definition formIO.cpp:84
TQPtrListIterator< ObjectTreeItem > ObjectTreeListIterator
An iterator for ObjectTreeList.
Definition objecttree.h:45