summaryrefslogtreecommitdiffstats
path: root/src/designer/src/lib/shared/widgetdatabase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/designer/src/lib/shared/widgetdatabase.cpp')
-rw-r--r--src/designer/src/lib/shared/widgetdatabase.cpp865
1 files changed, 865 insertions, 0 deletions
diff --git a/src/designer/src/lib/shared/widgetdatabase.cpp b/src/designer/src/lib/shared/widgetdatabase.cpp
new file mode 100644
index 000000000..aa1a77592
--- /dev/null
+++ b/src/designer/src/lib/shared/widgetdatabase.cpp
@@ -0,0 +1,865 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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/QScopedPointer>
+#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();
+ QScopedPointer<DomUI> domUI(QDesignerWidgetBox::xmlToUi(className, widget.domXml(), false));
+ if (domUI.isNull())
+ return QString();
+ domUI->setAttributeVersion(QLatin1String("4.0"));
+ 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();
+ }
+ 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