/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** 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 either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** 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.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at http://www.qtsoftware.com/contact. ** $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 #include #include #include #include #include #include #include #include #include #include #include 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 &list) { m_defaultPropertyValues = list; } QList 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 (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 NameIndexMap; typedef QList ItemList; typedef QMap NameItemMap; typedef QSet 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 WidgetDataBase::defaultPropertyValues(const QString &name) { WidgetFactory *factory = qobject_cast(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(); } // Get properties from sheet. QList result; if (const QDesignerPropertySheetExtension *sheet = qt_extension(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 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(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 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("\n") << name << QLatin1String("\n") << QLatin1String("\n") << QLatin1String("\n00") << NewFormWidth << QLatin1String("") << NewFormHeight << QLatin1String("\n\n"); str << QLatin1String("\n") << name << QLatin1String("\n\n"); if (similarClassName == QLatin1String("QMainWindow")) { str << QLatin1String("\n"); } else { if (similarClassName == QLatin1String("QWizard")) str << QLatin1String("\n"); } str << QLatin1String("\n\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 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