source: trunk/tools/designer/src/lib/shared/widgetdatabase.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 31.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the Qt Designer of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "widgetdatabase_p.h"
43#include "widgetfactory_p.h"
44#include "spacer_widget_p.h"
45#include "abstractlanguage.h"
46#include "pluginmanager_p.h"
47#include "qdesigner_widgetbox_p.h"
48#include "qdesigner_utils_p.h"
49#include <ui4_p.h>
50
51#include <QtDesigner/customwidget.h>
52#include <QtDesigner/propertysheet.h>
53#include <QtDesigner/QExtensionManager>
54#include <QtDesigner/QDesignerFormEditorInterface>
55
56#include <QtXml/QXmlStreamWriter>
57#include <QtCore/QtAlgorithms>
58#include <QtCore/qdebug.h>
59#include <QtCore/QMetaProperty>
60#include <QtCore/QTextStream>
61#include <QtCore/QRegExp>
62#include <QtCore/QCoreApplication>
63
64QT_BEGIN_NAMESPACE
65
66namespace {
67 enum { debugWidgetDataBase = 0 };
68}
69
70namespace qdesigner_internal {
71
72// ----------------------------------------------------------
73WidgetDataBaseItem::WidgetDataBaseItem(const QString &name, const QString &group)
74 : m_name(name),
75 m_group(group),
76 m_compat(0),
77 m_container(0),
78 m_form(0),
79 m_custom(0),
80 m_promoted(0)
81{
82}
83
84QString WidgetDataBaseItem::name() const
85{
86 return m_name;
87}
88
89void WidgetDataBaseItem::setName(const QString &name)
90{
91 m_name = name;
92}
93
94QString WidgetDataBaseItem::group() const
95{
96 return m_group;
97}
98
99void WidgetDataBaseItem::setGroup(const QString &group)
100{
101 m_group = group;
102}
103
104QString WidgetDataBaseItem::toolTip() const
105{
106 return m_toolTip;
107}
108
109void WidgetDataBaseItem::setToolTip(const QString &toolTip)
110{
111 m_toolTip = toolTip;
112}
113
114QString WidgetDataBaseItem::whatsThis() const
115{
116 return m_whatsThis;
117}
118
119void WidgetDataBaseItem::setWhatsThis(const QString &whatsThis)
120{
121 m_whatsThis = whatsThis;
122}
123
124QString WidgetDataBaseItem::includeFile() const
125{
126 return m_includeFile;
127}
128
129void WidgetDataBaseItem::setIncludeFile(const QString &includeFile)
130{
131 m_includeFile = includeFile;
132}
133
134QIcon WidgetDataBaseItem::icon() const
135{
136 return m_icon;
137}
138
139void WidgetDataBaseItem::setIcon(const QIcon &icon)
140{
141 m_icon = icon;
142}
143
144bool WidgetDataBaseItem::isCompat() const
145{
146 return m_compat;
147}
148
149void WidgetDataBaseItem::setCompat(bool b)
150{
151 m_compat = b;
152}
153
154bool WidgetDataBaseItem::isContainer() const
155{
156 return m_container;
157}
158
159void WidgetDataBaseItem::setContainer(bool b)
160{
161 m_container = b;
162}
163
164bool WidgetDataBaseItem::isCustom() const
165{
166 return m_custom;
167}
168
169void WidgetDataBaseItem::setCustom(bool b)
170{
171 m_custom = b;
172}
173
174QString WidgetDataBaseItem::pluginPath() const
175{
176 return m_pluginPath;
177}
178
179void WidgetDataBaseItem::setPluginPath(const QString &path)
180{
181 m_pluginPath = path;
182}
183
184bool WidgetDataBaseItem::isPromoted() const
185{
186 return m_promoted;
187}
188
189void WidgetDataBaseItem::setPromoted(bool b)
190{
191 m_promoted = b;
192}
193
194QString WidgetDataBaseItem::extends() const
195{
196 return m_extends;
197}
198
199void WidgetDataBaseItem::setExtends(const QString &s)
200{
201 m_extends = s;
202}
203
204void WidgetDataBaseItem::setDefaultPropertyValues(const QList<QVariant> &list)
205{
206 m_defaultPropertyValues = list;
207}
208
209QList<QVariant> WidgetDataBaseItem::defaultPropertyValues() const
210{
211 return m_defaultPropertyValues;
212}
213
214QStringList WidgetDataBaseItem::fakeSlots() const
215{
216 return m_fakeSlots;
217}
218
219void WidgetDataBaseItem::setFakeSlots(const QStringList &fs)
220{
221 m_fakeSlots = fs;
222}
223
224QStringList WidgetDataBaseItem::fakeSignals() const
225{
226 return m_fakeSignals;
227}
228
229void WidgetDataBaseItem::setFakeSignals(const QStringList &fs)
230{
231 m_fakeSignals = fs;
232}
233
234QString WidgetDataBaseItem::addPageMethod() const
235{
236 return m_addPageMethod;
237}
238
239void WidgetDataBaseItem::setAddPageMethod(const QString &m)
240{
241 m_addPageMethod = m;
242}
243
244WidgetDataBaseItem *WidgetDataBaseItem::clone(const QDesignerWidgetDataBaseItemInterface *item)
245{
246 WidgetDataBaseItem *rc = new WidgetDataBaseItem(item->name(), item->group());
247
248 rc->setToolTip(item->toolTip());
249 rc->setWhatsThis(item->whatsThis());
250 rc->setIncludeFile(item->includeFile());
251 rc->setIcon(item->icon());
252 rc->setCompat(item->isCompat());
253 rc->setContainer(item->isContainer());
254 rc->setCustom(item->isCustom() );
255 rc->setPluginPath(item->pluginPath());
256 rc->setPromoted(item->isPromoted());
257 rc->setExtends(item->extends());
258 rc->setDefaultPropertyValues(item->defaultPropertyValues());
259 // container page method, fake slots and signals ignored here.y
260 return rc;
261}
262
263// ----------------------------------------------------------
264WidgetDataBase::WidgetDataBase(QDesignerFormEditorInterface *core, QObject *parent)
265 : QDesignerWidgetDataBaseInterface(parent),
266 m_core(core)
267{
268#define DECLARE_LAYOUT(L, C)
269#define DECLARE_COMPAT_WIDGET(W, C) DECLARE_WIDGET(W, C)
270#define DECLARE_WIDGET(W, C) append(new WidgetDataBaseItem(QString::fromUtf8(#W)));
271
272#include "widgets.table"
273
274#undef DECLARE_COMPAT_WIDGET
275#undef DECLARE_LAYOUT
276#undef DECLARE_WIDGET
277#undef DECLARE_WIDGET_1
278
279 append(new WidgetDataBaseItem(QString::fromUtf8("Line")));
280 append(new WidgetDataBaseItem(QString::fromUtf8("Spacer")));
281 append(new WidgetDataBaseItem(QString::fromUtf8("QSplitter")));
282 append(new WidgetDataBaseItem(QString::fromUtf8("QLayoutWidget")));
283 // QDesignerWidget is used as central widget and as container for tab widgets, etc.
284 WidgetDataBaseItem *designerWidgetItem = new WidgetDataBaseItem(QString::fromUtf8("QDesignerWidget"));
285 designerWidgetItem->setContainer(true);
286 append(designerWidgetItem);
287 append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerDialog")));
288 append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerMenu")));
289 append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerMenuBar")));
290 append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerDockWidget")));
291 append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerQ3WidgetStack")));
292 append(new WidgetDataBaseItem(QString::fromUtf8("QAction")));
293 append(new WidgetDataBaseItem(QString::fromUtf8("QButtonGroup")));
294
295 // ### remove me
296 // ### check the casts
297
298#if 0 // ### enable me after 4.1
299 item(indexOfClassName(QLatin1String("QToolBar")))->setContainer(true);
300#endif
301
302 item(indexOfClassName(QLatin1String("QTabWidget")))->setContainer(true);
303 item(indexOfClassName(QLatin1String("QGroupBox")))->setContainer(true);
304 item(indexOfClassName(QLatin1String("QScrollArea")))->setContainer(true);
305 item(indexOfClassName(QLatin1String("QStackedWidget")))->setContainer(true);
306 item(indexOfClassName(QLatin1String("QToolBox")))->setContainer(true);
307 item(indexOfClassName(QLatin1String("QFrame")))->setContainer(true);
308 item(indexOfClassName(QLatin1String("QLayoutWidget")))->setContainer(true);
309 item(indexOfClassName(QLatin1String("QDesignerWidget")))->setContainer(true);
310 item(indexOfClassName(QLatin1String("QDesignerDialog")))->setContainer(true);
311 item(indexOfClassName(QLatin1String("QSplitter")))->setContainer(true);
312 item(indexOfClassName(QLatin1String("QMainWindow")))->setContainer(true);
313 item(indexOfClassName(QLatin1String("QDockWidget")))->setContainer(true);
314 item(indexOfClassName(QLatin1String("QDesignerDockWidget")))->setContainer(true);
315 item(indexOfClassName(QLatin1String("QDesignerQ3WidgetStack")))->setContainer(true);
316 item(indexOfClassName(QLatin1String("QMdiArea")))->setContainer(true);
317 item(indexOfClassName(QLatin1String("QWorkspace")))->setContainer(true);
318 item(indexOfClassName(QLatin1String("QWizard")))->setContainer(true);
319 item(indexOfClassName(QLatin1String("QWizardPage")))->setContainer(true);
320
321 item(indexOfClassName(QLatin1String("QWidget")))->setContainer(true);
322 item(indexOfClassName(QLatin1String("QDialog")))->setContainer(true);
323}
324
325WidgetDataBase::~WidgetDataBase()
326{
327}
328
329QDesignerFormEditorInterface *WidgetDataBase::core() const
330{
331 return m_core;
332}
333
334int WidgetDataBase::indexOfObject(QObject *object, bool /*resolveName*/) const
335{
336 QExtensionManager *mgr = m_core->extensionManager();
337 QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension*> (mgr, m_core);
338
339 QString id;
340
341 if (lang)
342 id = lang->classNameOf(object);
343
344 if (id.isEmpty())
345 id = WidgetFactory::classNameOf(m_core,object);
346
347 return QDesignerWidgetDataBaseInterface::indexOfClassName(id);
348}
349
350static WidgetDataBaseItem *createCustomWidgetItem(const QDesignerCustomWidgetInterface *c,
351 const QDesignerCustomWidgetData &data)
352{
353 WidgetDataBaseItem *item = new WidgetDataBaseItem(c->name(), c->group());
354 item->setContainer(c->isContainer());
355 item->setCustom(true);
356 item->setIcon(c->icon());
357 item->setIncludeFile(c->includeFile());
358 item->setToolTip(c->toolTip());
359 item->setWhatsThis(c->whatsThis());
360 item->setPluginPath(data.pluginPath());
361 item->setAddPageMethod(data.xmlAddPageMethod());
362 item->setExtends(data.xmlExtends());
363 return item;
364}
365
366void WidgetDataBase::loadPlugins()
367{
368 typedef QMap<QString, int> NameIndexMap;
369 typedef QList<QDesignerWidgetDataBaseItemInterface*> ItemList;
370 typedef QMap<QString, QDesignerWidgetDataBaseItemInterface*> NameItemMap;
371 typedef QSet<QString> NameSet;
372 // 1) create a map of existing custom classes
373 NameIndexMap existingCustomClasses;
374 NameSet nonCustomClasses;
375 const int count = m_items.size();
376 for (int i = 0; i < count; i++) {
377 const QDesignerWidgetDataBaseItemInterface* item = m_items[i];
378 if (item->isCustom() && !item->isPromoted())
379 existingCustomClasses.insert(item->name(), i);
380 else
381 nonCustomClasses.insert(item->name());
382 }
383 // 2) create a list plugins
384 ItemList pluginList;
385 const QDesignerPluginManager *pm = m_core->pluginManager();
386 foreach(QDesignerCustomWidgetInterface* c, pm->registeredCustomWidgets())
387 pluginList += createCustomWidgetItem(c, pm->customWidgetData(c));
388
389 // 3) replace custom classes or add new ones, remove them from existingCustomClasses,
390 // leaving behind deleted items
391 unsigned replacedPlugins = 0;
392 unsigned addedPlugins = 0;
393 unsigned removedPlugins = 0;
394 if (!pluginList.empty()) {
395 ItemList::const_iterator cend = pluginList.constEnd();
396 for (ItemList::const_iterator it = pluginList.constBegin();it != cend; ++it ) {
397 QDesignerWidgetDataBaseItemInterface* pluginItem = *it;
398 const QString pluginName = pluginItem->name();
399 NameIndexMap::iterator existingIt = existingCustomClasses.find(pluginName);
400 if (existingIt == existingCustomClasses.end()) {
401 // Add new class.
402 if (nonCustomClasses.contains(pluginName)) {
403 designerWarning(tr("A custom widget plugin whose class name (%1) matches that of an existing class has been found.").arg(pluginName));
404 } else {
405 append(pluginItem);
406 addedPlugins++;
407 }
408 } else {
409 // replace existing info
410 const int existingIndex = existingIt.value();
411 delete m_items[existingIndex];
412 m_items[existingIndex] = pluginItem;
413 existingCustomClasses.erase(existingIt);
414 replacedPlugins++;
415
416 }
417 }
418 }
419 // 4) remove classes that have not been matched. The stored indexes become invalid while deleting.
420 if (!existingCustomClasses.empty()) {
421 NameIndexMap::const_iterator cend = existingCustomClasses.constEnd();
422 for (NameIndexMap::const_iterator it = existingCustomClasses.constBegin();it != cend; ++it ) {
423 const int index = indexOfClassName(it.key());
424 if (index != -1) {
425 remove(index);
426 removedPlugins++;
427 }
428 }
429 }
430 if (debugWidgetDataBase)
431 qDebug() << "WidgetDataBase::loadPlugins(): " << addedPlugins << " added, " << replacedPlugins << " replaced, " << removedPlugins << "deleted.";
432}
433
434void WidgetDataBase::remove(int index)
435{
436 Q_ASSERT(index < m_items.size());
437 delete m_items.takeAt(index);
438}
439
440QList<QVariant> WidgetDataBase::defaultPropertyValues(const QString &name)
441{
442 WidgetFactory *factory = qobject_cast<WidgetFactory *>(m_core->widgetFactory());
443 Q_ASSERT(factory);
444 // Create non-widgets, widgets in order
445 QObject* object = factory->createObject(name, 0);
446 if (!object)
447 object = factory->createWidget(name, 0);
448 if (!object) {
449 qDebug() << "** WARNING Factory failed to create " << name;
450 return QList<QVariant>();
451 }
452 // Get properties from sheet.
453 QList<QVariant> result;
454 if (const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_core->extensionManager(), object)) {
455 const int propertyCount = sheet->count();
456 for (int i = 0; i < propertyCount; ++i) {
457 result.append(sheet->property(i));
458 }
459 }
460 delete object;
461 return result;
462}
463
464void WidgetDataBase::grabDefaultPropertyValues()
465{
466 const int itemCount = count();
467 for (int i = 0; i < itemCount; ++i) {
468 QDesignerWidgetDataBaseItemInterface *dbItem = item(i);
469 const QList<QVariant> default_prop_values = defaultPropertyValues(dbItem->name());
470 dbItem->setDefaultPropertyValues(default_prop_values);
471 }
472}
473
474void WidgetDataBase::grabStandardWidgetBoxIcons()
475{
476 // At this point, grab the default icons for the non-custom widgets from
477 // the widget box. They will show up in the object inspector.
478 if (const QDesignerWidgetBox *wb = qobject_cast<const QDesignerWidgetBox *>(m_core->widgetBox())) {
479 const QString qWidgetClass = QLatin1String("QWidget");
480 const int itemCount = count();
481 for (int i = 0; i < itemCount; ++i) {
482 QDesignerWidgetDataBaseItemInterface *dbItem = item(i);
483 if (!dbItem->isCustom() && dbItem->icon().isNull()) {
484 // Careful not to catch the layout icons when looking for
485 // QWidget
486 const QString name = dbItem->name();
487 if (name == qWidgetClass) {
488 dbItem->setIcon(wb->iconForWidget(name, QLatin1String("Containers")));
489 } else {
490 dbItem->setIcon(wb->iconForWidget(name));
491 }
492 }
493 }
494 }
495}
496
497// --------------------- Functions relevant generation of new forms based on widgets (apart from the standard templates)
498
499enum { NewFormWidth = 400, NewFormHeight = 300 };
500
501// Check if class is suitable to generate a form from
502static inline bool isExistingTemplate(const QString &className)
503{
504 return className == QLatin1String("QWidget") || className == QLatin1String("QDialog") || className == QLatin1String("QMainWindow");
505}
506
507// Check if class is suitable to generate a form from
508static inline bool suitableForNewForm(const QString &className)
509{
510 if (className.isEmpty()) // Missing custom widget information
511 return false;
512 if (className == QLatin1String("QWorkspace"))
513 return false;
514 if (className == QLatin1String("QSplitter"))
515 return false;
516 if (className.startsWith(QLatin1String("QDesigner")) || className.startsWith(QLatin1String("Q3")) || className.startsWith(QLatin1String("QLayout")))
517 return false;
518 return true;
519}
520
521// Return a list of widget classes from which new forms can be generated.
522// Suitable for 'New form' wizards in integrations.
523QStringList WidgetDataBase::formWidgetClasses(const QDesignerFormEditorInterface *core)
524{
525 static QStringList rc;
526 if (rc.empty()) {
527 const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
528 const int widgetCount = wdb->count();
529 for (int i = 0; i < widgetCount; i++) {
530 const QDesignerWidgetDataBaseItemInterface *item = wdb->item(i);
531 if (item->isContainer() && !item->isCustom() && !item->isPromoted()) {
532 const QString name = item->name(); // Standard Widgets: no existing templates
533 if (!isExistingTemplate(name) && suitableForNewForm(name))
534 rc += name;
535 }
536 }
537 }
538 return rc;
539}
540
541// Return a list of custom widget classes from which new forms can be generated.
542// Suitable for 'New form' wizards in integrations.
543QStringList WidgetDataBase::customFormWidgetClasses(const QDesignerFormEditorInterface *core)
544{
545 QStringList rc;
546 const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
547 const int widgetCount = wdb->count();
548 for (int i = 0; i < widgetCount; i++) { // Custom widgets: check name and base class.
549 const QDesignerWidgetDataBaseItemInterface *item = wdb->item(i);
550 if (item->isContainer() && item->isCustom() && !item->isPromoted()) {
551 if (suitableForNewForm(item->name()) && suitableForNewForm(item->extends()))
552 rc += item->name();
553 }
554 }
555 return rc;
556}
557
558// Get XML for a new form from the widget box. Change objectName/geometry
559// properties to be suitable for new forms
560static QString xmlFromWidgetBox(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName)
561{
562 typedef QList<DomProperty*> PropertyList;
563
564 QDesignerWidgetBoxInterface::Widget widget;
565 const bool found = QDesignerWidgetBox::findWidget(core->widgetBox(), className, QString(), &widget);
566 if (!found)
567 return QString();
568 DomUI *domUI = QDesignerWidgetBox::xmlToUi(className, widget.domXml(), false);
569 domUI->setAttributeVersion(QLatin1String("4.0"));
570 if (!domUI)
571 return QString();
572 DomWidget *domWidget = domUI->elementWidget();
573 if (!domWidget)
574 return QString();
575 // Properties: Remove the "objectName" property in favour of the name attribute and check geometry.
576 domWidget->setAttributeName(objectName);
577 const QString geometryProperty = QLatin1String("geometry");
578 const QString objectNameProperty = QLatin1String("objectName");
579 PropertyList properties = domWidget->elementProperty();
580 for (PropertyList::iterator it = properties.begin(); it != properties.end(); ) {
581 DomProperty *property = *it;
582 if (property->attributeName() == objectNameProperty) { // remove "objectName"
583 it = properties.erase(it);
584 delete property;
585 } else {
586 if (property->attributeName() == geometryProperty) { // Make sure form is at least 400, 300
587 if (DomRect *geom = property->elementRect()) {
588 if (geom->elementWidth() < NewFormWidth)
589 geom->setElementWidth(NewFormWidth);
590 if (geom->elementHeight() < NewFormHeight)
591 geom->setElementHeight(NewFormHeight);
592 }
593 }
594 ++it;
595 }
596 }
597 // Add a window title property
598 DomString *windowTitleString = new DomString;
599 windowTitleString->setText(objectName);
600 DomProperty *windowTitleProperty = new DomProperty;
601 windowTitleProperty->setAttributeName(QLatin1String("windowTitle"));
602 windowTitleProperty->setElementString(windowTitleString);
603 properties.push_back(windowTitleProperty);
604 // ------
605 domWidget->setElementProperty(properties);
606 // Embed in in DomUI and get string. Omit the version number.
607 domUI->setElementClass(objectName);
608
609 QString rc;
610 { // Serialize domUI
611 QXmlStreamWriter writer(&rc);
612 writer.setAutoFormatting(true);
613 writer.setAutoFormattingIndent(1);
614 writer.writeStartDocument();
615 domUI->write(writer);
616 writer.writeEndDocument();
617 }
618 delete domUI;
619 return rc;
620}
621
622// Generate default standard ui new form xml based on the class passed on as similarClassName.
623static QString generateNewFormXML(const QString &className, const QString &similarClassName, const QString &name)
624{
625 QString rc; {
626 QTextStream str(&rc);
627 str << QLatin1String("<ui version=\"4.0\" >\n<class>") << name << QLatin1String("</class>\n")
628 << QLatin1String("<widget class=\"") << className << QLatin1String("\" name=\"") << name << QLatin1String("\" >\n")
629 << QLatin1String("<property name=\"geometry\" >\n<rect><x>0</x><y>0</y><width>")
630 << NewFormWidth << QLatin1String("</width><height>") << NewFormHeight << QLatin1String("</height></rect>\n</property>\n");
631 str << QLatin1String("<property name=\"windowTitle\" >\n<string>") << name << QLatin1String("</string>\n</property>\n");
632
633 if (similarClassName == QLatin1String("QMainWindow")) {
634 str << QLatin1String("<widget class=\"QWidget\" name=\"centralwidget\" />\n");
635 } else {
636 if (similarClassName == QLatin1String("QWizard"))
637 str << QLatin1String("<widget class=\"QWizardPage\" name=\"wizardPage1\" /><widget class=\"QWizardPage\" name=\"wizardPage2\" />\n");
638 }
639 str << QLatin1String("</widget>\n</ui>\n");
640 }
641 return rc;
642}
643
644// Generate a form template using a class name obtained from formWidgetClasses(), customFormWidgetClasses().
645QString WidgetDataBase::formTemplate(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName)
646{
647 // How to find suitable XML for a class:
648 // 1) Look in widget box (as all the required centralwidgets, tab widget pages, etc. should be there).
649 const QString widgetBoxXml = xmlFromWidgetBox(core, className, objectName);
650 if (!widgetBoxXml.isEmpty())
651 return widgetBoxXml;
652 // 2) If that fails, only custom main windows, custom dialogs and unsupported Qt Widgets should
653 // be left over. Generate something that is similar to the default templates. Find a similar class.
654 const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
655 QString similarClass = QLatin1String("QWidget");
656 const int index = wdb->indexOfClassName(className);
657 if (index != -1) {
658 const QDesignerWidgetDataBaseItemInterface *item = wdb->item(index);
659 similarClass = item->isCustom() ? item->extends() : item->name();
660 }
661 // Generate standard ui based on the class passed on as baseClassName.
662 const QString rc = generateNewFormXML(className, similarClass, objectName);
663 return rc;
664}
665
666// Set a fixed size on a XML template
667QString WidgetDataBase::scaleFormTemplate(const QString &xml, const QSize &size, bool fixed)
668{
669 typedef QList<DomProperty*> PropertyList;
670 DomUI *domUI = QDesignerWidgetBox::xmlToUi(QLatin1String("Form"), xml, false);
671 if (!domUI)
672 return QString();
673 DomWidget *domWidget = domUI->elementWidget();
674 if (!domWidget)
675 return QString();
676 // Properties: Find/Ensure the geometry, minimum and maximum sizes properties
677 const QString geometryPropertyName = QLatin1String("geometry");
678 const QString minimumSizePropertyName = QLatin1String("minimumSize");
679 const QString maximumSizePropertyName = QLatin1String("maximumSize");
680 DomProperty *geomProperty = 0;
681 DomProperty *minimumSizeProperty = 0;
682 DomProperty *maximumSizeProperty = 0;
683
684 PropertyList properties = domWidget->elementProperty();
685 const PropertyList::const_iterator cend = properties.constEnd();
686 for (PropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) {
687 const QString name = (*it)->attributeName();
688 if (name == geometryPropertyName) {
689 geomProperty = *it;
690 } else {
691 if (name == minimumSizePropertyName) {
692 minimumSizeProperty = *it;
693 } else {
694 if (name == maximumSizePropertyName)
695 maximumSizeProperty = *it;
696 }
697 }
698 }
699 if (!geomProperty) {
700 geomProperty = new DomProperty;
701 geomProperty->setAttributeName(geometryPropertyName);
702 geomProperty->setElementRect(new DomRect);
703 properties.push_front(geomProperty);
704 }
705 if (fixed) {
706 if (!minimumSizeProperty) {
707 minimumSizeProperty = new DomProperty;
708 minimumSizeProperty->setAttributeName(minimumSizePropertyName);
709 minimumSizeProperty->setElementSize(new DomSize);
710 properties.push_back(minimumSizeProperty);
711 }
712 if (!maximumSizeProperty) {
713 maximumSizeProperty = new DomProperty;
714 maximumSizeProperty->setAttributeName(maximumSizePropertyName);
715 maximumSizeProperty->setElementSize(new DomSize);
716 properties.push_back(maximumSizeProperty);
717 }
718 }
719 // Set values of geometry, minimum and maximum sizes properties
720 const int width = size.width();
721 const int height = size.height();
722 if (DomRect *geom = geomProperty->elementRect()) {
723 geom->setElementWidth(width);
724 geom->setElementHeight(height);
725 }
726 if (fixed) {
727 if (DomSize *s = minimumSizeProperty->elementSize()) {
728 s->setElementWidth(width);
729 s->setElementHeight(height);
730 }
731 if (DomSize *s = maximumSizeProperty->elementSize()) {
732 s->setElementWidth(width);
733 s->setElementHeight(height);
734 }
735 }
736 // write back
737 domWidget->setElementProperty(properties);
738
739 QString rc;
740 { // serialize domUI
741 QXmlStreamWriter writer(&rc);
742 writer.setAutoFormatting(true);
743 writer.setAutoFormattingIndent(1);
744 writer.writeStartDocument();
745 domUI->write(writer);
746 writer.writeEndDocument();
747 }
748
749 delete domUI;
750 return rc;
751}
752
753// ---- free functions
754QDESIGNER_SHARED_EXPORT IncludeSpecification includeSpecification(QString includeFile)
755{
756 const bool global = !includeFile.isEmpty() &&
757 includeFile[0] == QLatin1Char('<') &&
758 includeFile[includeFile.size() - 1] == QLatin1Char('>');
759 if (global) {
760 includeFile.remove(includeFile.size() - 1, 1);
761 includeFile.remove(0, 1);
762 }
763 return IncludeSpecification(includeFile, global ? IncludeGlobal : IncludeLocal);
764}
765
766QDESIGNER_SHARED_EXPORT QString buildIncludeFile(QString includeFile, IncludeType includeType) {
767 if (includeType == IncludeGlobal && !includeFile.isEmpty()) {
768 includeFile.append(QLatin1Char('>'));
769 includeFile.insert(0, QLatin1Char('<'));
770 }
771 return includeFile;
772}
773
774
775/* Appends a derived class to the database inheriting the data of the base class. Used
776 for custom and promoted widgets.
777
778 Depending on whether an entry exists, the existing or a newly created entry is
779 returned. A return value of 0 indicates that the base class could not be found. */
780
781QDESIGNER_SHARED_EXPORT QDesignerWidgetDataBaseItemInterface *
782 appendDerived(QDesignerWidgetDataBaseInterface *db,
783 const QString &className, const QString &group,
784 const QString &baseClassName,
785 const QString &includeFile,
786 bool promoted, bool custom)
787{
788 if (debugWidgetDataBase)
789 qDebug() << "appendDerived " << className << " derived from " << baseClassName;
790 // Check.
791 if (className.isEmpty() || baseClassName.isEmpty()) {
792 qWarning("** WARNING %s called with an empty class names: '%s' extends '%s'.",
793 Q_FUNC_INFO, className.toUtf8().constData(), baseClassName.toUtf8().constData());
794 return 0;
795 }
796 // Check whether item already exists.
797 QDesignerWidgetDataBaseItemInterface *derivedItem = 0;
798 const int existingIndex = db->indexOfClassName(className);
799 if ( existingIndex != -1)
800 derivedItem = db->item(existingIndex);
801 if (derivedItem) {
802 // Check the existing item for base class mismatch. This will likely
803 // happen when loading a file written by an instance with missing plugins.
804 // In that case, just warn and ignore the file properties.
805 //
806 // An empty base class indicates that it is not known (for example, for custom plugins).
807 // In this case, the widget DB is later updated once the widget is created
808 // by DOM (by querying the metaobject). Suppress the warning.
809 const QString existingBaseClass = derivedItem->extends();
810 if (existingBaseClass.isEmpty() || baseClassName == existingBaseClass)
811 return derivedItem;
812
813 // Warn about mismatches
814 designerWarning(QCoreApplication::translate("WidgetDataBase",
815 "The file contains a custom widget '%1' whose base class (%2)"
816 " differs from the current entry in the widget database (%3)."
817 " The widget database is left unchanged.").
818 arg(className, baseClassName, existingBaseClass));
819 return derivedItem;
820 }
821 // Create this item, inheriting its base properties
822 const int baseIndex = db->indexOfClassName(baseClassName);
823 if (baseIndex == -1) {
824 if (debugWidgetDataBase)
825 qDebug() << "appendDerived failed due to missing base class";
826 return 0;
827 }
828 const QDesignerWidgetDataBaseItemInterface *baseItem = db->item(baseIndex);
829 derivedItem = WidgetDataBaseItem::clone(baseItem);
830 // Sort of hack: If base class is QWidget, we most likely
831 // do not want to inherit the container attribute.
832 static const QString qWidgetName = QLatin1String("QWidget");
833 if (baseItem->name() == qWidgetName)
834 derivedItem->setContainer(false);
835 // set new props
836 derivedItem->setName(className);
837 derivedItem->setGroup(group);
838 derivedItem->setCustom(custom);
839 derivedItem->setPromoted(promoted);
840 derivedItem->setExtends(baseClassName);
841 derivedItem->setIncludeFile(includeFile);
842 db->append(derivedItem);
843 return derivedItem;
844}
845
846/* Return a list of database items to which a class can be promoted to. */
847
848QDESIGNER_SHARED_EXPORT WidgetDataBaseItemList
849 promotionCandidates(const QDesignerWidgetDataBaseInterface *db,
850 const QString &baseClassName)
851{
852 WidgetDataBaseItemList rc;
853 // find existing promoted widgets deriving from base.
854 const int count = db->count();
855 for (int i = 0; i < count; ++i) {
856 QDesignerWidgetDataBaseItemInterface *item = db->item(i);
857 if (item->isPromoted() && item->extends() == baseClassName) {
858 rc.push_back(item);
859 }
860 }
861 return rc;
862}
863} // namespace qdesigner_internal
864
865QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.