1 /****************************************************************************
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the Qt Designer of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
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"
51 #include <QtDesigner/customwidget.h>
52 #include <QtDesigner/propertysheet.h>
53 #include <QtDesigner/QExtensionManager>
54 #include <QtDesigner/QDesignerFormEditorInterface>
56 #include <QtXml/QXmlStreamWriter>
58 #include <QtCore/QScopedPointer>
59 #include <QtCore/qdebug.h>
60 #include <QtCore/QMetaProperty>
61 #include <QtCore/QTextStream>
62 #include <QtCore/QRegExp>
63 #include <QtCore/QCoreApplication>
68 enum { debugWidgetDataBase = 0 };
71 namespace qdesigner_internal {
73 // ----------------------------------------------------------
74 WidgetDataBaseItem::WidgetDataBaseItem(const QString &name, const QString &group)
85 QString WidgetDataBaseItem::name() const
90 void WidgetDataBaseItem::setName(const QString &name)
95 QString WidgetDataBaseItem::group() const
100 void WidgetDataBaseItem::setGroup(const QString &group)
105 QString WidgetDataBaseItem::toolTip() const
110 void WidgetDataBaseItem::setToolTip(const QString &toolTip)
115 QString WidgetDataBaseItem::whatsThis() const
120 void WidgetDataBaseItem::setWhatsThis(const QString &whatsThis)
122 m_whatsThis = whatsThis;
125 QString WidgetDataBaseItem::includeFile() const
127 return m_includeFile;
130 void WidgetDataBaseItem::setIncludeFile(const QString &includeFile)
132 m_includeFile = includeFile;
135 QIcon WidgetDataBaseItem::icon() const
140 void WidgetDataBaseItem::setIcon(const QIcon &icon)
145 bool WidgetDataBaseItem::isCompat() const
150 void WidgetDataBaseItem::setCompat(bool b)
155 bool WidgetDataBaseItem::isContainer() const
160 void WidgetDataBaseItem::setContainer(bool b)
165 bool WidgetDataBaseItem::isCustom() const
170 void WidgetDataBaseItem::setCustom(bool b)
175 QString WidgetDataBaseItem::pluginPath() const
180 void WidgetDataBaseItem::setPluginPath(const QString &path)
185 bool WidgetDataBaseItem::isPromoted() const
190 void WidgetDataBaseItem::setPromoted(bool b)
195 QString WidgetDataBaseItem::extends() const
200 void WidgetDataBaseItem::setExtends(const QString &s)
205 void WidgetDataBaseItem::setDefaultPropertyValues(const QList<QVariant> &list)
207 m_defaultPropertyValues = list;
210 QList<QVariant> WidgetDataBaseItem::defaultPropertyValues() const
212 return m_defaultPropertyValues;
215 QStringList WidgetDataBaseItem::fakeSlots() const
220 void WidgetDataBaseItem::setFakeSlots(const QStringList &fs)
225 QStringList WidgetDataBaseItem::fakeSignals() const
227 return m_fakeSignals;
230 void WidgetDataBaseItem::setFakeSignals(const QStringList &fs)
235 QString WidgetDataBaseItem::addPageMethod() const
237 return m_addPageMethod;
240 void WidgetDataBaseItem::setAddPageMethod(const QString &m)
245 WidgetDataBaseItem *WidgetDataBaseItem::clone(const QDesignerWidgetDataBaseItemInterface *item)
247 WidgetDataBaseItem *rc = new WidgetDataBaseItem(item->name(), item->group());
249 rc->setToolTip(item->toolTip());
250 rc->setWhatsThis(item->whatsThis());
251 rc->setIncludeFile(item->includeFile());
252 rc->setIcon(item->icon());
253 rc->setCompat(item->isCompat());
254 rc->setContainer(item->isContainer());
255 rc->setCustom(item->isCustom() );
256 rc->setPluginPath(item->pluginPath());
257 rc->setPromoted(item->isPromoted());
258 rc->setExtends(item->extends());
259 rc->setDefaultPropertyValues(item->defaultPropertyValues());
260 // container page method, fake slots and signals ignored here.y
264 // ----------------------------------------------------------
265 WidgetDataBase::WidgetDataBase(QDesignerFormEditorInterface *core, QObject *parent)
266 : QDesignerWidgetDataBaseInterface(parent),
269 #define DECLARE_LAYOUT(L, C)
270 #define DECLARE_COMPAT_WIDGET(W, C) DECLARE_WIDGET(W, C)
271 #define DECLARE_WIDGET(W, C) append(new WidgetDataBaseItem(QString::fromUtf8(#W)));
273 #include "widgets.table"
275 #undef DECLARE_COMPAT_WIDGET
276 #undef DECLARE_LAYOUT
277 #undef DECLARE_WIDGET
278 #undef DECLARE_WIDGET_1
280 append(new WidgetDataBaseItem(QString::fromUtf8("Line")));
281 append(new WidgetDataBaseItem(QString::fromUtf8("Spacer")));
282 append(new WidgetDataBaseItem(QString::fromUtf8("QSplitter")));
283 append(new WidgetDataBaseItem(QString::fromUtf8("QLayoutWidget")));
284 // QDesignerWidget is used as central widget and as container for tab widgets, etc.
285 WidgetDataBaseItem *designerWidgetItem = new WidgetDataBaseItem(QString::fromUtf8("QDesignerWidget"));
286 designerWidgetItem->setContainer(true);
287 append(designerWidgetItem);
288 append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerDialog")));
289 append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerMenu")));
290 append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerMenuBar")));
291 append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerDockWidget")));
292 append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerQ3WidgetStack")));
293 append(new WidgetDataBaseItem(QString::fromUtf8("QAction")));
294 append(new WidgetDataBaseItem(QString::fromUtf8("QButtonGroup")));
297 // ### check the casts
299 #if 0 // ### enable me after 4.1
300 item(indexOfClassName(QLatin1String("QToolBar")))->setContainer(true);
303 item(indexOfClassName(QLatin1String("QTabWidget")))->setContainer(true);
304 item(indexOfClassName(QLatin1String("QGroupBox")))->setContainer(true);
305 item(indexOfClassName(QLatin1String("QScrollArea")))->setContainer(true);
306 item(indexOfClassName(QLatin1String("QStackedWidget")))->setContainer(true);
307 item(indexOfClassName(QLatin1String("QToolBox")))->setContainer(true);
308 item(indexOfClassName(QLatin1String("QFrame")))->setContainer(true);
309 item(indexOfClassName(QLatin1String("QLayoutWidget")))->setContainer(true);
310 item(indexOfClassName(QLatin1String("QDesignerWidget")))->setContainer(true);
311 item(indexOfClassName(QLatin1String("QDesignerDialog")))->setContainer(true);
312 item(indexOfClassName(QLatin1String("QSplitter")))->setContainer(true);
313 item(indexOfClassName(QLatin1String("QMainWindow")))->setContainer(true);
314 item(indexOfClassName(QLatin1String("QDockWidget")))->setContainer(true);
315 item(indexOfClassName(QLatin1String("QDesignerDockWidget")))->setContainer(true);
316 item(indexOfClassName(QLatin1String("QDesignerQ3WidgetStack")))->setContainer(true);
317 item(indexOfClassName(QLatin1String("QMdiArea")))->setContainer(true);
318 item(indexOfClassName(QLatin1String("QWorkspace")))->setContainer(true);
319 item(indexOfClassName(QLatin1String("QWizard")))->setContainer(true);
320 item(indexOfClassName(QLatin1String("QWizardPage")))->setContainer(true);
322 item(indexOfClassName(QLatin1String("QWidget")))->setContainer(true);
323 item(indexOfClassName(QLatin1String("QDialog")))->setContainer(true);
326 WidgetDataBase::~WidgetDataBase()
330 QDesignerFormEditorInterface *WidgetDataBase::core() const
335 int WidgetDataBase::indexOfObject(QObject *object, bool /*resolveName*/) const
337 QExtensionManager *mgr = m_core->extensionManager();
338 QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension*> (mgr, m_core);
343 id = lang->classNameOf(object);
346 id = WidgetFactory::classNameOf(m_core,object);
348 return QDesignerWidgetDataBaseInterface::indexOfClassName(id);
351 static WidgetDataBaseItem *createCustomWidgetItem(const QDesignerCustomWidgetInterface *c,
352 const QDesignerCustomWidgetData &data)
354 WidgetDataBaseItem *item = new WidgetDataBaseItem(c->name(), c->group());
355 item->setContainer(c->isContainer());
356 item->setCustom(true);
357 item->setIcon(c->icon());
358 item->setIncludeFile(c->includeFile());
359 item->setToolTip(c->toolTip());
360 item->setWhatsThis(c->whatsThis());
361 item->setPluginPath(data.pluginPath());
362 item->setAddPageMethod(data.xmlAddPageMethod());
363 item->setExtends(data.xmlExtends());
367 void WidgetDataBase::loadPlugins()
369 typedef QMap<QString, int> NameIndexMap;
370 typedef QList<QDesignerWidgetDataBaseItemInterface*> ItemList;
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);
381 nonCustomClasses.insert(item->name());
383 // 2) create a list plugins
385 const QDesignerPluginManager *pm = m_core->pluginManager();
386 foreach(QDesignerCustomWidgetInterface* c, pm->registeredCustomWidgets())
387 pluginList += createCustomWidgetItem(c, pm->customWidgetData(c));
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()) {
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));
409 // replace existing info
410 const int existingIndex = existingIt.value();
411 delete m_items[existingIndex];
412 m_items[existingIndex] = pluginItem;
413 existingCustomClasses.erase(existingIt);
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());
430 if (debugWidgetDataBase)
431 qDebug() << "WidgetDataBase::loadPlugins(): " << addedPlugins << " added, " << replacedPlugins << " replaced, " << removedPlugins << "deleted.";
434 void WidgetDataBase::remove(int index)
436 Q_ASSERT(index < m_items.size());
437 delete m_items.takeAt(index);
440 QList<QVariant> WidgetDataBase::defaultPropertyValues(const QString &name)
442 WidgetFactory *factory = qobject_cast<WidgetFactory *>(m_core->widgetFactory());
444 // Create non-widgets, widgets in order
445 QObject* object = factory->createObject(name, 0);
447 object = factory->createWidget(name, 0);
449 qDebug() << "** WARNING Factory failed to create " << name;
450 return QList<QVariant>();
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));
464 void WidgetDataBase::grabDefaultPropertyValues()
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);
474 void WidgetDataBase::grabStandardWidgetBoxIcons()
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
486 const QString name = dbItem->name();
487 if (name == qWidgetClass) {
488 dbItem->setIcon(wb->iconForWidget(name, QLatin1String("Containers")));
490 dbItem->setIcon(wb->iconForWidget(name));
497 // --------------------- Functions relevant generation of new forms based on widgets (apart from the standard templates)
499 enum { NewFormWidth = 400, NewFormHeight = 300 };
501 // Check if class is suitable to generate a form from
502 static inline bool isExistingTemplate(const QString &className)
504 return className == QLatin1String("QWidget") || className == QLatin1String("QDialog") || className == QLatin1String("QMainWindow");
507 // Check if class is suitable to generate a form from
508 static inline bool suitableForNewForm(const QString &className)
510 if (className.isEmpty()) // Missing custom widget information
512 if (className == QLatin1String("QWorkspace"))
514 if (className == QLatin1String("QSplitter"))
516 if (className.startsWith(QLatin1String("QDesigner")) || className.startsWith(QLatin1String("Q3")) || className.startsWith(QLatin1String("QLayout")))
521 // Return a list of widget classes from which new forms can be generated.
522 // Suitable for 'New form' wizards in integrations.
523 QStringList WidgetDataBase::formWidgetClasses(const QDesignerFormEditorInterface *core)
525 static QStringList rc;
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))
541 // Return a list of custom widget classes from which new forms can be generated.
542 // Suitable for 'New form' wizards in integrations.
543 QStringList WidgetDataBase::customFormWidgetClasses(const QDesignerFormEditorInterface *core)
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()))
558 // Get XML for a new form from the widget box. Change objectName/geometry
559 // properties to be suitable for new forms
560 static QString xmlFromWidgetBox(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName)
562 typedef QList<DomProperty*> PropertyList;
564 QDesignerWidgetBoxInterface::Widget widget;
565 const bool found = QDesignerWidgetBox::findWidget(core->widgetBox(), className, QString(), &widget);
568 QScopedPointer<DomUI> domUI(QDesignerWidgetBox::xmlToUi(className, widget.domXml(), false));
571 domUI->setAttributeVersion(QLatin1String("4.0"));
572 DomWidget *domWidget = domUI->elementWidget();
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);
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);
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);
605 domWidget->setElementProperty(properties);
606 // Embed in in DomUI and get string. Omit the version number.
607 domUI->setElementClass(objectName);
611 QXmlStreamWriter writer(&rc);
612 writer.setAutoFormatting(true);
613 writer.setAutoFormattingIndent(1);
614 writer.writeStartDocument();
615 domUI->write(writer);
616 writer.writeEndDocument();
621 // Generate default standard ui new form xml based on the class passed on as similarClassName.
622 static QString generateNewFormXML(const QString &className, const QString &similarClassName, const QString &name)
625 QTextStream str(&rc);
626 str << QLatin1String("<ui version=\"4.0\" >\n<class>") << name << QLatin1String("</class>\n")
627 << QLatin1String("<widget class=\"") << className << QLatin1String("\" name=\"") << name << QLatin1String("\" >\n")
628 << QLatin1String("<property name=\"geometry\" >\n<rect><x>0</x><y>0</y><width>")
629 << NewFormWidth << QLatin1String("</width><height>") << NewFormHeight << QLatin1String("</height></rect>\n</property>\n");
630 str << QLatin1String("<property name=\"windowTitle\" >\n<string>") << name << QLatin1String("</string>\n</property>\n");
632 if (similarClassName == QLatin1String("QMainWindow")) {
633 str << QLatin1String("<widget class=\"QWidget\" name=\"centralwidget\" />\n");
635 if (similarClassName == QLatin1String("QWizard"))
636 str << QLatin1String("<widget class=\"QWizardPage\" name=\"wizardPage1\" /><widget class=\"QWizardPage\" name=\"wizardPage2\" />\n");
638 str << QLatin1String("</widget>\n</ui>\n");
643 // Generate a form template using a class name obtained from formWidgetClasses(), customFormWidgetClasses().
644 QString WidgetDataBase::formTemplate(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName)
646 // How to find suitable XML for a class:
647 // 1) Look in widget box (as all the required centralwidgets, tab widget pages, etc. should be there).
648 const QString widgetBoxXml = xmlFromWidgetBox(core, className, objectName);
649 if (!widgetBoxXml.isEmpty())
651 // 2) If that fails, only custom main windows, custom dialogs and unsupported Qt Widgets should
652 // be left over. Generate something that is similar to the default templates. Find a similar class.
653 const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
654 QString similarClass = QLatin1String("QWidget");
655 const int index = wdb->indexOfClassName(className);
657 const QDesignerWidgetDataBaseItemInterface *item = wdb->item(index);
658 similarClass = item->isCustom() ? item->extends() : item->name();
660 // Generate standard ui based on the class passed on as baseClassName.
661 const QString rc = generateNewFormXML(className, similarClass, objectName);
665 // Set a fixed size on a XML template
666 QString WidgetDataBase::scaleFormTemplate(const QString &xml, const QSize &size, bool fixed)
668 typedef QList<DomProperty*> PropertyList;
669 DomUI *domUI = QDesignerWidgetBox::xmlToUi(QLatin1String("Form"), xml, false);
672 DomWidget *domWidget = domUI->elementWidget();
675 // Properties: Find/Ensure the geometry, minimum and maximum sizes properties
676 const QString geometryPropertyName = QLatin1String("geometry");
677 const QString minimumSizePropertyName = QLatin1String("minimumSize");
678 const QString maximumSizePropertyName = QLatin1String("maximumSize");
679 DomProperty *geomProperty = 0;
680 DomProperty *minimumSizeProperty = 0;
681 DomProperty *maximumSizeProperty = 0;
683 PropertyList properties = domWidget->elementProperty();
684 const PropertyList::const_iterator cend = properties.constEnd();
685 for (PropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) {
686 const QString name = (*it)->attributeName();
687 if (name == geometryPropertyName) {
690 if (name == minimumSizePropertyName) {
691 minimumSizeProperty = *it;
693 if (name == maximumSizePropertyName)
694 maximumSizeProperty = *it;
699 geomProperty = new DomProperty;
700 geomProperty->setAttributeName(geometryPropertyName);
701 geomProperty->setElementRect(new DomRect);
702 properties.push_front(geomProperty);
705 if (!minimumSizeProperty) {
706 minimumSizeProperty = new DomProperty;
707 minimumSizeProperty->setAttributeName(minimumSizePropertyName);
708 minimumSizeProperty->setElementSize(new DomSize);
709 properties.push_back(minimumSizeProperty);
711 if (!maximumSizeProperty) {
712 maximumSizeProperty = new DomProperty;
713 maximumSizeProperty->setAttributeName(maximumSizePropertyName);
714 maximumSizeProperty->setElementSize(new DomSize);
715 properties.push_back(maximumSizeProperty);
718 // Set values of geometry, minimum and maximum sizes properties
719 const int width = size.width();
720 const int height = size.height();
721 if (DomRect *geom = geomProperty->elementRect()) {
722 geom->setElementWidth(width);
723 geom->setElementHeight(height);
726 if (DomSize *s = minimumSizeProperty->elementSize()) {
727 s->setElementWidth(width);
728 s->setElementHeight(height);
730 if (DomSize *s = maximumSizeProperty->elementSize()) {
731 s->setElementWidth(width);
732 s->setElementHeight(height);
736 domWidget->setElementProperty(properties);
740 QXmlStreamWriter writer(&rc);
741 writer.setAutoFormatting(true);
742 writer.setAutoFormattingIndent(1);
743 writer.writeStartDocument();
744 domUI->write(writer);
745 writer.writeEndDocument();
752 // ---- free functions
753 QDESIGNER_SHARED_EXPORT IncludeSpecification includeSpecification(QString includeFile)
755 const bool global = !includeFile.isEmpty() &&
756 includeFile[0] == QLatin1Char('<') &&
757 includeFile[includeFile.size() - 1] == QLatin1Char('>');
759 includeFile.remove(includeFile.size() - 1, 1);
760 includeFile.remove(0, 1);
762 return IncludeSpecification(includeFile, global ? IncludeGlobal : IncludeLocal);
765 QDESIGNER_SHARED_EXPORT QString buildIncludeFile(QString includeFile, IncludeType includeType) {
766 if (includeType == IncludeGlobal && !includeFile.isEmpty()) {
767 includeFile.append(QLatin1Char('>'));
768 includeFile.insert(0, QLatin1Char('<'));
774 /* Appends a derived class to the database inheriting the data of the base class. Used
775 for custom and promoted widgets.
777 Depending on whether an entry exists, the existing or a newly created entry is
778 returned. A return value of 0 indicates that the base class could not be found. */
780 QDESIGNER_SHARED_EXPORT QDesignerWidgetDataBaseItemInterface *
781 appendDerived(QDesignerWidgetDataBaseInterface *db,
782 const QString &className, const QString &group,
783 const QString &baseClassName,
784 const QString &includeFile,
785 bool promoted, bool custom)
787 if (debugWidgetDataBase)
788 qDebug() << "appendDerived " << className << " derived from " << baseClassName;
790 if (className.isEmpty() || baseClassName.isEmpty()) {
791 qWarning("** WARNING %s called with an empty class names: '%s' extends '%s'.",
792 Q_FUNC_INFO, className.toUtf8().constData(), baseClassName.toUtf8().constData());
795 // Check whether item already exists.
796 QDesignerWidgetDataBaseItemInterface *derivedItem = 0;
797 const int existingIndex = db->indexOfClassName(className);
798 if ( existingIndex != -1)
799 derivedItem = db->item(existingIndex);
801 // Check the existing item for base class mismatch. This will likely
802 // happen when loading a file written by an instance with missing plugins.
803 // In that case, just warn and ignore the file properties.
805 // An empty base class indicates that it is not known (for example, for custom plugins).
806 // In this case, the widget DB is later updated once the widget is created
807 // by DOM (by querying the metaobject). Suppress the warning.
808 const QString existingBaseClass = derivedItem->extends();
809 if (existingBaseClass.isEmpty() || baseClassName == existingBaseClass)
812 // Warn about mismatches
813 designerWarning(QCoreApplication::translate("WidgetDataBase",
814 "The file contains a custom widget '%1' whose base class (%2)"
815 " differs from the current entry in the widget database (%3)."
816 " The widget database is left unchanged.").
817 arg(className, baseClassName, existingBaseClass));
820 // Create this item, inheriting its base properties
821 const int baseIndex = db->indexOfClassName(baseClassName);
822 if (baseIndex == -1) {
823 if (debugWidgetDataBase)
824 qDebug() << "appendDerived failed due to missing base class";
827 const QDesignerWidgetDataBaseItemInterface *baseItem = db->item(baseIndex);
828 derivedItem = WidgetDataBaseItem::clone(baseItem);
829 // Sort of hack: If base class is QWidget, we most likely
830 // do not want to inherit the container attribute.
831 static const QString qWidgetName = QLatin1String("QWidget");
832 if (baseItem->name() == qWidgetName)
833 derivedItem->setContainer(false);
835 derivedItem->setName(className);
836 derivedItem->setGroup(group);
837 derivedItem->setCustom(custom);
838 derivedItem->setPromoted(promoted);
839 derivedItem->setExtends(baseClassName);
840 derivedItem->setIncludeFile(includeFile);
841 db->append(derivedItem);
845 /* Return a list of database items to which a class can be promoted to. */
847 QDESIGNER_SHARED_EXPORT WidgetDataBaseItemList
848 promotionCandidates(const QDesignerWidgetDataBaseInterface *db,
849 const QString &baseClassName)
851 WidgetDataBaseItemList rc;
852 // find existing promoted widgets deriving from base.
853 const int count = db->count();
854 for (int i = 0; i < count; ++i) {
855 QDesignerWidgetDataBaseItemInterface *item = db->item(i);
856 if (item->isPromoted() && item->extends() == baseClassName) {
862 } // namespace qdesigner_internal