| /**************************************************************************** |
| ** |
| ** 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$ |
| ** GNU Lesser General Public License Usage |
| ** 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. |
| ** |
| ** 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. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $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 |