tools/designer/src/lib/shared/widgetdatabase.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/designer/src/lib/shared/widgetdatabase.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,865 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Designer of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "widgetdatabase_p.h"
+#include "widgetfactory_p.h"
+#include "spacer_widget_p.h"
+#include "abstractlanguage.h"
+#include "pluginmanager_p.h"
+#include "qdesigner_widgetbox_p.h"
+#include "qdesigner_utils_p.h"
+#include <ui4_p.h>
+
+#include <QtDesigner/customwidget.h>
+#include <QtDesigner/propertysheet.h>
+#include <QtDesigner/QExtensionManager>
+#include <QtDesigner/QDesignerFormEditorInterface>
+
+#include <QtXml/QXmlStreamWriter>
+#include <QtCore/QtAlgorithms>
+#include <QtCore/qdebug.h>
+#include <QtCore/QMetaProperty>
+#include <QtCore/QTextStream>
+#include <QtCore/QRegExp>
+#include <QtCore/QCoreApplication>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+    enum { debugWidgetDataBase = 0 };
+}
+
+namespace qdesigner_internal {
+
+// ----------------------------------------------------------
+WidgetDataBaseItem::WidgetDataBaseItem(const QString &name, const QString &group)
+    : m_name(name),
+      m_group(group),
+      m_compat(0),
+      m_container(0),
+      m_form(0),
+      m_custom(0),
+      m_promoted(0)
+{
+}
+
+QString WidgetDataBaseItem::name() const
+{
+    return m_name;
+}
+
+void WidgetDataBaseItem::setName(const QString &name)
+{
+    m_name = name;
+}
+
+QString WidgetDataBaseItem::group() const
+{
+    return m_group;
+}
+
+void WidgetDataBaseItem::setGroup(const QString &group)
+{
+    m_group = group;
+}
+
+QString WidgetDataBaseItem::toolTip() const
+{
+    return m_toolTip;
+}
+
+void WidgetDataBaseItem::setToolTip(const QString &toolTip)
+{
+    m_toolTip = toolTip;
+}
+
+QString WidgetDataBaseItem::whatsThis() const
+{
+    return m_whatsThis;
+}
+
+void WidgetDataBaseItem::setWhatsThis(const QString &whatsThis)
+{
+    m_whatsThis = whatsThis;
+}
+
+QString WidgetDataBaseItem::includeFile() const
+{
+    return m_includeFile;
+}
+
+void WidgetDataBaseItem::setIncludeFile(const QString &includeFile)
+{
+    m_includeFile = includeFile;
+}
+
+QIcon WidgetDataBaseItem::icon() const
+{
+    return m_icon;
+}
+
+void WidgetDataBaseItem::setIcon(const QIcon &icon)
+{
+    m_icon = icon;
+}
+
+bool WidgetDataBaseItem::isCompat() const
+{
+    return m_compat;
+}
+
+void WidgetDataBaseItem::setCompat(bool b)
+{
+    m_compat = b;
+}
+
+bool WidgetDataBaseItem::isContainer() const
+{
+    return m_container;
+}
+
+void WidgetDataBaseItem::setContainer(bool b)
+{
+    m_container = b;
+}
+
+bool WidgetDataBaseItem::isCustom() const
+{
+    return m_custom;
+}
+
+void WidgetDataBaseItem::setCustom(bool b)
+{
+    m_custom = b;
+}
+
+QString WidgetDataBaseItem::pluginPath() const
+{
+    return m_pluginPath;
+}
+
+void WidgetDataBaseItem::setPluginPath(const QString &path)
+{
+    m_pluginPath = path;
+}
+
+bool WidgetDataBaseItem::isPromoted() const
+{
+    return m_promoted;
+}
+
+void WidgetDataBaseItem::setPromoted(bool b)
+{
+    m_promoted = b;
+}
+
+QString WidgetDataBaseItem::extends() const
+{
+    return m_extends;
+}
+
+void WidgetDataBaseItem::setExtends(const QString &s)
+{
+    m_extends = s;
+}
+
+void WidgetDataBaseItem::setDefaultPropertyValues(const QList<QVariant> &list)
+{
+    m_defaultPropertyValues = list;
+}
+
+QList<QVariant> WidgetDataBaseItem::defaultPropertyValues() const
+{
+    return m_defaultPropertyValues;
+}
+
+QStringList WidgetDataBaseItem::fakeSlots() const
+{
+    return m_fakeSlots;
+}
+
+void WidgetDataBaseItem::setFakeSlots(const QStringList &fs)
+{
+    m_fakeSlots = fs;
+}
+
+QStringList WidgetDataBaseItem::fakeSignals() const
+{
+     return m_fakeSignals;
+}
+
+void WidgetDataBaseItem::setFakeSignals(const QStringList &fs)
+{
+    m_fakeSignals = fs;
+}
+
+QString WidgetDataBaseItem::addPageMethod() const
+{
+    return m_addPageMethod;
+}
+
+void WidgetDataBaseItem::setAddPageMethod(const QString &m)
+{
+    m_addPageMethod = m;
+}
+
+WidgetDataBaseItem *WidgetDataBaseItem::clone(const QDesignerWidgetDataBaseItemInterface *item)
+{
+    WidgetDataBaseItem *rc = new WidgetDataBaseItem(item->name(), item->group());
+
+    rc->setToolTip(item->toolTip());
+    rc->setWhatsThis(item->whatsThis());
+    rc->setIncludeFile(item->includeFile());
+    rc->setIcon(item->icon());
+    rc->setCompat(item->isCompat());
+    rc->setContainer(item->isContainer());
+    rc->setCustom(item->isCustom() );
+    rc->setPluginPath(item->pluginPath());
+    rc->setPromoted(item->isPromoted());
+    rc->setExtends(item->extends());
+    rc->setDefaultPropertyValues(item->defaultPropertyValues());
+    // container page method, fake slots and signals ignored here.y
+    return rc;
+}
+
+// ----------------------------------------------------------
+WidgetDataBase::WidgetDataBase(QDesignerFormEditorInterface *core, QObject *parent)
+    : QDesignerWidgetDataBaseInterface(parent),
+      m_core(core)
+{
+#define DECLARE_LAYOUT(L, C)
+#define DECLARE_COMPAT_WIDGET(W, C) DECLARE_WIDGET(W, C)
+#define DECLARE_WIDGET(W, C) append(new WidgetDataBaseItem(QString::fromUtf8(#W)));
+
+#include "widgets.table"
+
+#undef DECLARE_COMPAT_WIDGET
+#undef DECLARE_LAYOUT
+#undef DECLARE_WIDGET
+#undef DECLARE_WIDGET_1
+
+    append(new WidgetDataBaseItem(QString::fromUtf8("Line")));
+    append(new WidgetDataBaseItem(QString::fromUtf8("Spacer")));
+    append(new WidgetDataBaseItem(QString::fromUtf8("QSplitter")));
+    append(new WidgetDataBaseItem(QString::fromUtf8("QLayoutWidget")));
+    // QDesignerWidget is used as central widget and as container for tab widgets, etc.
+    WidgetDataBaseItem *designerWidgetItem = new WidgetDataBaseItem(QString::fromUtf8("QDesignerWidget"));
+    designerWidgetItem->setContainer(true);
+    append(designerWidgetItem);
+    append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerDialog")));
+    append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerMenu")));
+    append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerMenuBar")));
+    append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerDockWidget")));
+    append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerQ3WidgetStack")));
+    append(new WidgetDataBaseItem(QString::fromUtf8("QAction")));
+    append(new WidgetDataBaseItem(QString::fromUtf8("QButtonGroup")));
+
+    // ### remove me
+    // ### check the casts
+
+#if 0 // ### enable me after 4.1
+    item(indexOfClassName(QLatin1String("QToolBar")))->setContainer(true);
+#endif
+
+    item(indexOfClassName(QLatin1String("QTabWidget")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QGroupBox")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QScrollArea")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QStackedWidget")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QToolBox")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QFrame")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QLayoutWidget")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QDesignerWidget")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QDesignerDialog")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QSplitter")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QMainWindow")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QDockWidget")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QDesignerDockWidget")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QDesignerQ3WidgetStack")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QMdiArea")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QWorkspace")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QWizard")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QWizardPage")))->setContainer(true);
+
+    item(indexOfClassName(QLatin1String("QWidget")))->setContainer(true);
+    item(indexOfClassName(QLatin1String("QDialog")))->setContainer(true);
+}
+
+WidgetDataBase::~WidgetDataBase()
+{
+}
+
+QDesignerFormEditorInterface *WidgetDataBase::core() const
+{
+    return m_core;
+}
+
+int WidgetDataBase::indexOfObject(QObject *object, bool /*resolveName*/) const
+{
+    QExtensionManager *mgr = m_core->extensionManager();
+    QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension*> (mgr, m_core);
+
+    QString id;
+
+    if (lang)
+        id = lang->classNameOf(object);
+
+    if (id.isEmpty())
+        id = WidgetFactory::classNameOf(m_core,object);
+
+    return QDesignerWidgetDataBaseInterface::indexOfClassName(id);
+}
+
+static WidgetDataBaseItem *createCustomWidgetItem(const QDesignerCustomWidgetInterface *c,
+                                                  const QDesignerCustomWidgetData &data)
+{
+    WidgetDataBaseItem *item = new WidgetDataBaseItem(c->name(), c->group());
+    item->setContainer(c->isContainer());
+    item->setCustom(true);
+    item->setIcon(c->icon());
+    item->setIncludeFile(c->includeFile());
+    item->setToolTip(c->toolTip());
+    item->setWhatsThis(c->whatsThis());
+    item->setPluginPath(data.pluginPath());
+    item->setAddPageMethod(data.xmlAddPageMethod());
+    item->setExtends(data.xmlExtends());
+    return item;
+}
+
+void WidgetDataBase::loadPlugins()
+{
+    typedef QMap<QString, int> NameIndexMap;
+    typedef QList<QDesignerWidgetDataBaseItemInterface*> ItemList;
+    typedef QMap<QString, QDesignerWidgetDataBaseItemInterface*> NameItemMap;
+    typedef QSet<QString> NameSet;
+    // 1) create a map of existing custom classes
+    NameIndexMap existingCustomClasses;
+    NameSet nonCustomClasses;
+    const int count = m_items.size();
+    for (int i = 0; i < count; i++)    {
+        const QDesignerWidgetDataBaseItemInterface* item =  m_items[i];
+        if (item->isCustom() && !item->isPromoted())
+            existingCustomClasses.insert(item->name(), i);
+        else
+            nonCustomClasses.insert(item->name());
+    }
+    // 2) create a list plugins
+    ItemList pluginList;
+    const QDesignerPluginManager *pm = m_core->pluginManager();
+    foreach(QDesignerCustomWidgetInterface* c, pm->registeredCustomWidgets())
+        pluginList += createCustomWidgetItem(c, pm->customWidgetData(c));
+
+    // 3) replace custom classes or add new ones, remove them from existingCustomClasses,
+    // leaving behind deleted items
+    unsigned replacedPlugins = 0;
+    unsigned addedPlugins = 0;
+    unsigned removedPlugins = 0;
+    if (!pluginList.empty()) {
+        ItemList::const_iterator cend = pluginList.constEnd();
+        for (ItemList::const_iterator it = pluginList.constBegin();it != cend; ++it )  {
+            QDesignerWidgetDataBaseItemInterface* pluginItem = *it;
+            const QString pluginName = pluginItem->name();
+            NameIndexMap::iterator existingIt = existingCustomClasses.find(pluginName);
+            if (existingIt == existingCustomClasses.end()) {
+                // Add new class.
+                if (nonCustomClasses.contains(pluginName)) {
+                    designerWarning(tr("A custom widget plugin whose class name (%1) matches that of an existing class has been found.").arg(pluginName));
+                } else {
+                    append(pluginItem);
+                    addedPlugins++;
+                }
+            } else {
+                // replace existing info
+                const int existingIndex = existingIt.value();
+                delete m_items[existingIndex];
+                m_items[existingIndex] = pluginItem;
+                existingCustomClasses.erase(existingIt);
+                replacedPlugins++;
+
+            }
+        }
+    }
+    // 4) remove classes that have not been matched. The stored indexes become invalid while deleting.
+    if (!existingCustomClasses.empty()) {
+        NameIndexMap::const_iterator cend = existingCustomClasses.constEnd();
+        for (NameIndexMap::const_iterator it = existingCustomClasses.constBegin();it != cend; ++it )  {
+            const int index = indexOfClassName(it.key());
+            if (index != -1) {
+                remove(index);
+                removedPlugins++;
+            }
+        }
+    }
+    if (debugWidgetDataBase)
+        qDebug() << "WidgetDataBase::loadPlugins(): " << addedPlugins << " added, " << replacedPlugins << " replaced, " << removedPlugins << "deleted.";
+}
+
+void WidgetDataBase::remove(int index)
+{
+    Q_ASSERT(index < m_items.size());
+    delete m_items.takeAt(index);
+}
+
+QList<QVariant> WidgetDataBase::defaultPropertyValues(const QString &name)
+{
+    WidgetFactory *factory = qobject_cast<WidgetFactory *>(m_core->widgetFactory());
+    Q_ASSERT(factory);
+    // Create non-widgets, widgets in order
+    QObject* object = factory->createObject(name, 0);
+    if (!object)
+        object = factory->createWidget(name, 0);
+    if (!object) {
+        qDebug() << "** WARNING Factory failed to create " << name;
+        return QList<QVariant>();
+    }
+    // Get properties from sheet.
+    QList<QVariant> result;
+    if (const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_core->extensionManager(), object)) {
+        const int propertyCount = sheet->count();
+        for (int i = 0; i < propertyCount; ++i) {
+            result.append(sheet->property(i));
+        }
+    }
+    delete object;
+    return result;
+}
+
+void WidgetDataBase::grabDefaultPropertyValues()
+{
+    const int itemCount = count();
+    for (int i = 0; i < itemCount; ++i) {
+        QDesignerWidgetDataBaseItemInterface *dbItem = item(i);
+        const QList<QVariant> default_prop_values = defaultPropertyValues(dbItem->name());
+        dbItem->setDefaultPropertyValues(default_prop_values);
+    }
+}
+
+void WidgetDataBase::grabStandardWidgetBoxIcons()
+{
+    // At this point, grab the default icons for the non-custom widgets from
+    // the widget box. They will show up in the object inspector.
+    if (const QDesignerWidgetBox *wb = qobject_cast<const QDesignerWidgetBox *>(m_core->widgetBox())) {
+        const QString qWidgetClass = QLatin1String("QWidget");
+        const int itemCount = count();
+        for (int i = 0; i < itemCount; ++i) {
+            QDesignerWidgetDataBaseItemInterface *dbItem = item(i);
+            if (!dbItem->isCustom() && dbItem->icon().isNull()) {
+                // Careful not to catch the layout icons when looking for
+                // QWidget
+                const QString name = dbItem->name();
+                if (name == qWidgetClass) {
+                    dbItem->setIcon(wb->iconForWidget(name, QLatin1String("Containers")));
+                } else {
+                    dbItem->setIcon(wb->iconForWidget(name));
+                }
+            }
+        }
+    }
+}
+
+// --------------------- Functions relevant generation of new forms based on widgets (apart from the standard templates)
+
+enum { NewFormWidth = 400, NewFormHeight = 300 };
+
+// Check if class is suitable to generate a form from
+static inline bool isExistingTemplate(const QString &className)
+{
+    return className == QLatin1String("QWidget") || className == QLatin1String("QDialog") || className == QLatin1String("QMainWindow");
+}
+
+// Check if class is suitable to generate a form from
+static inline bool suitableForNewForm(const QString &className)
+{
+    if (className.isEmpty()) // Missing custom widget information
+        return false;
+    if (className == QLatin1String("QWorkspace"))
+         return false;
+    if (className == QLatin1String("QSplitter"))
+         return false;
+    if (className.startsWith(QLatin1String("QDesigner")) || className.startsWith(QLatin1String("Q3")) ||  className.startsWith(QLatin1String("QLayout")))
+        return false;
+    return true;
+}
+
+// Return a list of widget classes from which new forms can be generated.
+// Suitable for 'New form' wizards in integrations.
+QStringList WidgetDataBase::formWidgetClasses(const QDesignerFormEditorInterface *core)
+{
+    static QStringList rc;
+    if (rc.empty()) {
+        const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
+        const int widgetCount = wdb->count();
+        for (int i = 0; i < widgetCount; i++) {
+            const QDesignerWidgetDataBaseItemInterface *item = wdb->item(i);
+            if (item->isContainer() && !item->isCustom() && !item->isPromoted()) {
+                const QString name = item->name(); // Standard Widgets: no existing templates
+                if (!isExistingTemplate(name) && suitableForNewForm(name))
+                    rc += name;
+            }
+        }
+    }
+    return rc;
+}
+
+// Return a list of custom widget classes from which new forms can be generated.
+// Suitable for 'New form' wizards in integrations.
+QStringList WidgetDataBase::customFormWidgetClasses(const QDesignerFormEditorInterface *core)
+{
+    QStringList rc;
+    const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
+    const int widgetCount = wdb->count();
+    for (int i = 0; i < widgetCount; i++) { // Custom widgets: check name and base class.
+        const QDesignerWidgetDataBaseItemInterface *item = wdb->item(i);
+        if (item->isContainer() && item->isCustom() && !item->isPromoted()) {
+            if (suitableForNewForm(item->name()) && suitableForNewForm(item->extends()))
+                rc += item->name();
+        }
+    }
+    return rc;
+}
+
+// Get XML for a new form from the widget box. Change objectName/geometry
+// properties to be suitable for new forms
+static QString xmlFromWidgetBox(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName)
+{
+    typedef QList<DomProperty*> PropertyList;
+
+    QDesignerWidgetBoxInterface::Widget widget;
+    const bool found = QDesignerWidgetBox::findWidget(core->widgetBox(), className, QString(), &widget);
+    if (!found)
+        return QString();
+    DomUI *domUI = QDesignerWidgetBox::xmlToUi(className, widget.domXml(), false);
+    domUI->setAttributeVersion(QLatin1String("4.0"));
+    if (!domUI)
+        return QString();
+    DomWidget *domWidget = domUI->elementWidget();
+    if (!domWidget)
+        return QString();
+    // Properties: Remove the "objectName" property in favour of the name attribute and check geometry.
+    domWidget->setAttributeName(objectName);
+    const QString geometryProperty = QLatin1String("geometry");
+    const QString objectNameProperty  = QLatin1String("objectName");
+    PropertyList properties = domWidget->elementProperty();
+    for (PropertyList::iterator it = properties.begin(); it != properties.end(); ) {
+        DomProperty *property = *it;
+        if (property->attributeName() == objectNameProperty) { // remove  "objectName"
+            it = properties.erase(it);
+            delete property;
+        } else {
+            if (property->attributeName() == geometryProperty) { // Make sure form is at least 400, 300
+                if (DomRect *geom = property->elementRect()) {
+                    if (geom->elementWidth() < NewFormWidth)
+                        geom->setElementWidth(NewFormWidth);
+                    if (geom->elementHeight() < NewFormHeight)
+                        geom->setElementHeight(NewFormHeight);
+                }
+            }
+            ++it;
+        }
+    }
+    // Add a window title property
+    DomString *windowTitleString = new DomString;
+    windowTitleString->setText(objectName);
+    DomProperty *windowTitleProperty = new DomProperty;
+    windowTitleProperty->setAttributeName(QLatin1String("windowTitle"));
+    windowTitleProperty->setElementString(windowTitleString);
+    properties.push_back(windowTitleProperty);
+    // ------
+    domWidget->setElementProperty(properties);
+    // Embed in in DomUI and get string. Omit the version number.
+    domUI->setElementClass(objectName);
+
+    QString rc;
+    { // Serialize domUI
+        QXmlStreamWriter writer(&rc);
+        writer.setAutoFormatting(true);
+        writer.setAutoFormattingIndent(1);
+        writer.writeStartDocument();
+        domUI->write(writer);
+        writer.writeEndDocument();
+    }
+    delete domUI;
+    return rc;
+}
+
+// Generate default standard ui new form xml based on the class passed on as similarClassName.
+static QString generateNewFormXML(const QString &className, const QString &similarClassName, const QString &name)
+{
+    QString rc; {
+        QTextStream str(&rc);
+        str << QLatin1String("<ui version=\"4.0\" >\n<class>") << name << QLatin1String("</class>\n")
+            <<  QLatin1String("<widget class=\"") << className << QLatin1String("\" name=\"") << name << QLatin1String("\" >\n")
+            <<  QLatin1String("<property name=\"geometry\" >\n<rect><x>0</x><y>0</y><width>")
+            << NewFormWidth << QLatin1String("</width><height>") << NewFormHeight << QLatin1String("</height></rect>\n</property>\n");
+        str << QLatin1String("<property name=\"windowTitle\" >\n<string>") << name << QLatin1String("</string>\n</property>\n");
+
+        if (similarClassName == QLatin1String("QMainWindow")) {
+            str << QLatin1String("<widget class=\"QWidget\" name=\"centralwidget\" />\n");
+        } else {
+            if (similarClassName == QLatin1String("QWizard"))
+                str << QLatin1String("<widget class=\"QWizardPage\" name=\"wizardPage1\" /><widget class=\"QWizardPage\" name=\"wizardPage2\" />\n");
+        }
+        str << QLatin1String("</widget>\n</ui>\n");
+    }
+    return rc;
+}
+
+// Generate a form template using a class name obtained from formWidgetClasses(), customFormWidgetClasses().
+QString WidgetDataBase::formTemplate(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName)
+{
+    // How to find suitable XML for a class:
+    // 1) Look in widget box (as all the required centralwidgets, tab widget pages, etc. should be there).
+    const QString widgetBoxXml = xmlFromWidgetBox(core, className, objectName);
+    if (!widgetBoxXml.isEmpty())
+        return widgetBoxXml;
+    // 2) If that fails, only custom main windows, custom dialogs and unsupported Qt Widgets should
+    //    be left over. Generate something that is similar to the default templates. Find a similar class.
+    const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
+    QString similarClass = QLatin1String("QWidget");
+    const int index = wdb->indexOfClassName(className);
+    if (index != -1) {
+        const QDesignerWidgetDataBaseItemInterface *item = wdb->item(index);
+        similarClass = item->isCustom() ? item->extends() : item->name();
+    }
+    // Generate standard ui based on the class passed on as baseClassName.
+    const QString rc = generateNewFormXML(className, similarClass, objectName);
+    return rc;
+}
+
+// Set a fixed size on a XML template
+QString WidgetDataBase::scaleFormTemplate(const QString &xml, const QSize &size, bool fixed)
+{
+    typedef QList<DomProperty*> PropertyList;
+    DomUI *domUI = QDesignerWidgetBox::xmlToUi(QLatin1String("Form"), xml, false);
+    if (!domUI)
+        return QString();
+    DomWidget *domWidget = domUI->elementWidget();
+    if (!domWidget)
+        return QString();
+    // Properties: Find/Ensure the geometry, minimum and maximum sizes properties
+    const QString geometryPropertyName = QLatin1String("geometry");
+    const QString minimumSizePropertyName = QLatin1String("minimumSize");
+    const QString maximumSizePropertyName = QLatin1String("maximumSize");
+    DomProperty *geomProperty = 0;
+    DomProperty *minimumSizeProperty = 0;
+    DomProperty *maximumSizeProperty = 0;
+
+    PropertyList properties = domWidget->elementProperty();
+    const PropertyList::const_iterator cend = properties.constEnd();
+    for (PropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) {
+        const QString name = (*it)->attributeName();
+        if (name == geometryPropertyName) {
+            geomProperty = *it;
+        } else {
+            if (name == minimumSizePropertyName) {
+                minimumSizeProperty = *it;
+            } else {
+                if (name == maximumSizePropertyName)
+                    maximumSizeProperty = *it;
+            }
+        }
+    }
+    if (!geomProperty) {
+        geomProperty = new DomProperty;
+        geomProperty->setAttributeName(geometryPropertyName);
+        geomProperty->setElementRect(new DomRect);
+        properties.push_front(geomProperty);
+    }
+    if (fixed) {
+        if (!minimumSizeProperty) {
+            minimumSizeProperty = new DomProperty;
+            minimumSizeProperty->setAttributeName(minimumSizePropertyName);
+            minimumSizeProperty->setElementSize(new DomSize);
+            properties.push_back(minimumSizeProperty);
+        }
+        if (!maximumSizeProperty) {
+            maximumSizeProperty = new DomProperty;
+            maximumSizeProperty->setAttributeName(maximumSizePropertyName);
+            maximumSizeProperty->setElementSize(new DomSize);
+            properties.push_back(maximumSizeProperty);
+        }
+    }
+    // Set values of geometry, minimum and maximum sizes properties
+    const int width = size.width();
+    const int height = size.height();
+    if (DomRect *geom = geomProperty->elementRect()) {
+        geom->setElementWidth(width);
+        geom->setElementHeight(height);
+    }
+    if (fixed) {
+        if (DomSize *s = minimumSizeProperty->elementSize()) {
+            s->setElementWidth(width);
+            s->setElementHeight(height);
+        }
+        if (DomSize *s = maximumSizeProperty->elementSize()) {
+            s->setElementWidth(width);
+            s->setElementHeight(height);
+        }
+    }
+    // write back
+    domWidget->setElementProperty(properties);
+
+    QString rc;
+    { // serialize domUI
+        QXmlStreamWriter writer(&rc);
+        writer.setAutoFormatting(true);
+        writer.setAutoFormattingIndent(1);
+        writer.writeStartDocument();
+        domUI->write(writer);
+        writer.writeEndDocument();
+    }
+
+    delete domUI;
+    return rc;
+}
+
+// ---- free functions
+QDESIGNER_SHARED_EXPORT IncludeSpecification  includeSpecification(QString includeFile)
+{
+    const bool global = !includeFile.isEmpty() &&
+                        includeFile[0] == QLatin1Char('<') &&
+                        includeFile[includeFile.size() - 1] ==  QLatin1Char('>');
+    if (global) {
+        includeFile.remove(includeFile.size() - 1, 1);
+        includeFile.remove(0, 1);
+    }
+    return IncludeSpecification(includeFile, global ? IncludeGlobal : IncludeLocal);
+}
+
+QDESIGNER_SHARED_EXPORT QString buildIncludeFile(QString includeFile, IncludeType includeType) {
+    if (includeType == IncludeGlobal && !includeFile.isEmpty()) {
+        includeFile.append(QLatin1Char('>'));
+        includeFile.insert(0, QLatin1Char('<'));
+    }
+    return includeFile;
+}
+
+
+/* Appends a derived class to the database inheriting the data of the base class. Used
+   for custom and promoted widgets.
+
+   Depending on whether an entry exists, the existing or a newly created entry is
+   returned. A return value of 0 indicates that the base class could not be found. */
+
+QDESIGNER_SHARED_EXPORT QDesignerWidgetDataBaseItemInterface *
+        appendDerived(QDesignerWidgetDataBaseInterface *db,
+                      const QString &className, const QString &group,
+                      const QString &baseClassName,
+                      const QString &includeFile,
+                      bool promoted, bool custom)
+{
+    if (debugWidgetDataBase)
+        qDebug() << "appendDerived " << className << " derived from " << baseClassName;
+    // Check.
+    if (className.isEmpty() || baseClassName.isEmpty()) {
+        qWarning("** WARNING %s called with an empty class names: '%s' extends '%s'.",
+                 Q_FUNC_INFO, className.toUtf8().constData(), baseClassName.toUtf8().constData());
+        return 0;
+    }
+    // Check whether item already exists.
+    QDesignerWidgetDataBaseItemInterface *derivedItem = 0;
+    const int existingIndex = db->indexOfClassName(className);
+    if ( existingIndex != -1)
+        derivedItem =  db->item(existingIndex);
+    if (derivedItem) {
+        // Check the existing item for base class mismatch. This will likely
+        // happen when loading a file written by an instance with missing plugins.
+        // In that case, just warn and ignore the file properties.
+        //
+        // An empty base class indicates that it is not known (for example, for custom plugins).
+        // In this case, the widget DB is later updated once the widget is created
+        // by DOM (by querying the metaobject). Suppress the warning.
+        const QString existingBaseClass = derivedItem->extends();
+        if (existingBaseClass.isEmpty() || baseClassName ==  existingBaseClass)
+            return derivedItem;
+
+        // Warn about mismatches
+        designerWarning(QCoreApplication::translate("WidgetDataBase",
+          "The file contains a custom widget '%1' whose base class (%2)"
+          " differs from the current entry in the widget database (%3)."
+          " The widget database is left unchanged.").
+                        arg(className, baseClassName, existingBaseClass));
+        return derivedItem;
+    }
+    // Create this item, inheriting its base properties
+    const int baseIndex = db->indexOfClassName(baseClassName);
+    if (baseIndex == -1) {
+        if (debugWidgetDataBase)
+            qDebug() << "appendDerived failed due to missing base class";
+        return 0;
+    }
+    const QDesignerWidgetDataBaseItemInterface *baseItem = db->item(baseIndex);
+    derivedItem = WidgetDataBaseItem::clone(baseItem);
+    // Sort of hack: If base class is QWidget, we most likely
+    // do not want to inherit the container attribute.
+    static const QString qWidgetName = QLatin1String("QWidget");
+    if (baseItem->name() == qWidgetName)
+        derivedItem->setContainer(false);
+    // set new props
+    derivedItem->setName(className);
+    derivedItem->setGroup(group);
+    derivedItem->setCustom(custom);
+    derivedItem->setPromoted(promoted);
+    derivedItem->setExtends(baseClassName);
+    derivedItem->setIncludeFile(includeFile);
+    db->append(derivedItem);
+    return derivedItem;
+}
+
+/* Return a list of database items to which a class can be promoted to. */
+
+QDESIGNER_SHARED_EXPORT WidgetDataBaseItemList
+        promotionCandidates(const QDesignerWidgetDataBaseInterface *db,
+                            const QString &baseClassName)
+{
+    WidgetDataBaseItemList rc;
+    // find existing promoted widgets deriving from base.
+    const int count = db->count();
+    for (int i = 0; i < count; ++i) {
+        QDesignerWidgetDataBaseItemInterface *item = db->item(i);
+        if (item->isPromoted() && item->extends() == baseClassName) {
+            rc.push_back(item);
+        }
+    }
+    return rc;
+}
+} // namespace qdesigner_internal
+
+QT_END_NAMESPACE