tools/designer/src/lib/shared/widgetdatabase.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Designer of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "widgetdatabase_p.h"
       
    43 #include "widgetfactory_p.h"
       
    44 #include "spacer_widget_p.h"
       
    45 #include "abstractlanguage.h"
       
    46 #include "pluginmanager_p.h"
       
    47 #include "qdesigner_widgetbox_p.h"
       
    48 #include "qdesigner_utils_p.h"
       
    49 #include <ui4_p.h>
       
    50 
       
    51 #include <QtDesigner/customwidget.h>
       
    52 #include <QtDesigner/propertysheet.h>
       
    53 #include <QtDesigner/QExtensionManager>
       
    54 #include <QtDesigner/QDesignerFormEditorInterface>
       
    55 
       
    56 #include <QtXml/QXmlStreamWriter>
       
    57 #include <QtCore/QtAlgorithms>
       
    58 #include <QtCore/qdebug.h>
       
    59 #include <QtCore/QMetaProperty>
       
    60 #include <QtCore/QTextStream>
       
    61 #include <QtCore/QRegExp>
       
    62 #include <QtCore/QCoreApplication>
       
    63 
       
    64 QT_BEGIN_NAMESPACE
       
    65 
       
    66 namespace {
       
    67     enum { debugWidgetDataBase = 0 };
       
    68 }
       
    69 
       
    70 namespace qdesigner_internal {
       
    71 
       
    72 // ----------------------------------------------------------
       
    73 WidgetDataBaseItem::WidgetDataBaseItem(const QString &name, const QString &group)
       
    74     : m_name(name),
       
    75       m_group(group),
       
    76       m_compat(0),
       
    77       m_container(0),
       
    78       m_form(0),
       
    79       m_custom(0),
       
    80       m_promoted(0)
       
    81 {
       
    82 }
       
    83 
       
    84 QString WidgetDataBaseItem::name() const
       
    85 {
       
    86     return m_name;
       
    87 }
       
    88 
       
    89 void WidgetDataBaseItem::setName(const QString &name)
       
    90 {
       
    91     m_name = name;
       
    92 }
       
    93 
       
    94 QString WidgetDataBaseItem::group() const
       
    95 {
       
    96     return m_group;
       
    97 }
       
    98 
       
    99 void WidgetDataBaseItem::setGroup(const QString &group)
       
   100 {
       
   101     m_group = group;
       
   102 }
       
   103 
       
   104 QString WidgetDataBaseItem::toolTip() const
       
   105 {
       
   106     return m_toolTip;
       
   107 }
       
   108 
       
   109 void WidgetDataBaseItem::setToolTip(const QString &toolTip)
       
   110 {
       
   111     m_toolTip = toolTip;
       
   112 }
       
   113 
       
   114 QString WidgetDataBaseItem::whatsThis() const
       
   115 {
       
   116     return m_whatsThis;
       
   117 }
       
   118 
       
   119 void WidgetDataBaseItem::setWhatsThis(const QString &whatsThis)
       
   120 {
       
   121     m_whatsThis = whatsThis;
       
   122 }
       
   123 
       
   124 QString WidgetDataBaseItem::includeFile() const
       
   125 {
       
   126     return m_includeFile;
       
   127 }
       
   128 
       
   129 void WidgetDataBaseItem::setIncludeFile(const QString &includeFile)
       
   130 {
       
   131     m_includeFile = includeFile;
       
   132 }
       
   133 
       
   134 QIcon WidgetDataBaseItem::icon() const
       
   135 {
       
   136     return m_icon;
       
   137 }
       
   138 
       
   139 void WidgetDataBaseItem::setIcon(const QIcon &icon)
       
   140 {
       
   141     m_icon = icon;
       
   142 }
       
   143 
       
   144 bool WidgetDataBaseItem::isCompat() const
       
   145 {
       
   146     return m_compat;
       
   147 }
       
   148 
       
   149 void WidgetDataBaseItem::setCompat(bool b)
       
   150 {
       
   151     m_compat = b;
       
   152 }
       
   153 
       
   154 bool WidgetDataBaseItem::isContainer() const
       
   155 {
       
   156     return m_container;
       
   157 }
       
   158 
       
   159 void WidgetDataBaseItem::setContainer(bool b)
       
   160 {
       
   161     m_container = b;
       
   162 }
       
   163 
       
   164 bool WidgetDataBaseItem::isCustom() const
       
   165 {
       
   166     return m_custom;
       
   167 }
       
   168 
       
   169 void WidgetDataBaseItem::setCustom(bool b)
       
   170 {
       
   171     m_custom = b;
       
   172 }
       
   173 
       
   174 QString WidgetDataBaseItem::pluginPath() const
       
   175 {
       
   176     return m_pluginPath;
       
   177 }
       
   178 
       
   179 void WidgetDataBaseItem::setPluginPath(const QString &path)
       
   180 {
       
   181     m_pluginPath = path;
       
   182 }
       
   183 
       
   184 bool WidgetDataBaseItem::isPromoted() const
       
   185 {
       
   186     return m_promoted;
       
   187 }
       
   188 
       
   189 void WidgetDataBaseItem::setPromoted(bool b)
       
   190 {
       
   191     m_promoted = b;
       
   192 }
       
   193 
       
   194 QString WidgetDataBaseItem::extends() const
       
   195 {
       
   196     return m_extends;
       
   197 }
       
   198 
       
   199 void WidgetDataBaseItem::setExtends(const QString &s)
       
   200 {
       
   201     m_extends = s;
       
   202 }
       
   203 
       
   204 void WidgetDataBaseItem::setDefaultPropertyValues(const QList<QVariant> &list)
       
   205 {
       
   206     m_defaultPropertyValues = list;
       
   207 }
       
   208 
       
   209 QList<QVariant> WidgetDataBaseItem::defaultPropertyValues() const
       
   210 {
       
   211     return m_defaultPropertyValues;
       
   212 }
       
   213 
       
   214 QStringList WidgetDataBaseItem::fakeSlots() const
       
   215 {
       
   216     return m_fakeSlots;
       
   217 }
       
   218 
       
   219 void WidgetDataBaseItem::setFakeSlots(const QStringList &fs)
       
   220 {
       
   221     m_fakeSlots = fs;
       
   222 }
       
   223 
       
   224 QStringList WidgetDataBaseItem::fakeSignals() const
       
   225 {
       
   226      return m_fakeSignals;
       
   227 }
       
   228 
       
   229 void WidgetDataBaseItem::setFakeSignals(const QStringList &fs)
       
   230 {
       
   231     m_fakeSignals = fs;
       
   232 }
       
   233 
       
   234 QString WidgetDataBaseItem::addPageMethod() const
       
   235 {
       
   236     return m_addPageMethod;
       
   237 }
       
   238 
       
   239 void WidgetDataBaseItem::setAddPageMethod(const QString &m)
       
   240 {
       
   241     m_addPageMethod = m;
       
   242 }
       
   243 
       
   244 WidgetDataBaseItem *WidgetDataBaseItem::clone(const QDesignerWidgetDataBaseItemInterface *item)
       
   245 {
       
   246     WidgetDataBaseItem *rc = new WidgetDataBaseItem(item->name(), item->group());
       
   247 
       
   248     rc->setToolTip(item->toolTip());
       
   249     rc->setWhatsThis(item->whatsThis());
       
   250     rc->setIncludeFile(item->includeFile());
       
   251     rc->setIcon(item->icon());
       
   252     rc->setCompat(item->isCompat());
       
   253     rc->setContainer(item->isContainer());
       
   254     rc->setCustom(item->isCustom() );
       
   255     rc->setPluginPath(item->pluginPath());
       
   256     rc->setPromoted(item->isPromoted());
       
   257     rc->setExtends(item->extends());
       
   258     rc->setDefaultPropertyValues(item->defaultPropertyValues());
       
   259     // container page method, fake slots and signals ignored here.y
       
   260     return rc;
       
   261 }
       
   262 
       
   263 // ----------------------------------------------------------
       
   264 WidgetDataBase::WidgetDataBase(QDesignerFormEditorInterface *core, QObject *parent)
       
   265     : QDesignerWidgetDataBaseInterface(parent),
       
   266       m_core(core)
       
   267 {
       
   268 #define DECLARE_LAYOUT(L, C)
       
   269 #define DECLARE_COMPAT_WIDGET(W, C) DECLARE_WIDGET(W, C)
       
   270 #define DECLARE_WIDGET(W, C) append(new WidgetDataBaseItem(QString::fromUtf8(#W)));
       
   271 
       
   272 #include "widgets.table"
       
   273 
       
   274 #undef DECLARE_COMPAT_WIDGET
       
   275 #undef DECLARE_LAYOUT
       
   276 #undef DECLARE_WIDGET
       
   277 #undef DECLARE_WIDGET_1
       
   278 
       
   279     append(new WidgetDataBaseItem(QString::fromUtf8("Line")));
       
   280     append(new WidgetDataBaseItem(QString::fromUtf8("Spacer")));
       
   281     append(new WidgetDataBaseItem(QString::fromUtf8("QSplitter")));
       
   282     append(new WidgetDataBaseItem(QString::fromUtf8("QLayoutWidget")));
       
   283     // QDesignerWidget is used as central widget and as container for tab widgets, etc.
       
   284     WidgetDataBaseItem *designerWidgetItem = new WidgetDataBaseItem(QString::fromUtf8("QDesignerWidget"));
       
   285     designerWidgetItem->setContainer(true);
       
   286     append(designerWidgetItem);
       
   287     append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerDialog")));
       
   288     append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerMenu")));
       
   289     append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerMenuBar")));
       
   290     append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerDockWidget")));
       
   291     append(new WidgetDataBaseItem(QString::fromUtf8("QDesignerQ3WidgetStack")));
       
   292     append(new WidgetDataBaseItem(QString::fromUtf8("QAction")));
       
   293     append(new WidgetDataBaseItem(QString::fromUtf8("QButtonGroup")));
       
   294 
       
   295     // ### remove me
       
   296     // ### check the casts
       
   297 
       
   298 #if 0 // ### enable me after 4.1
       
   299     item(indexOfClassName(QLatin1String("QToolBar")))->setContainer(true);
       
   300 #endif
       
   301 
       
   302     item(indexOfClassName(QLatin1String("QTabWidget")))->setContainer(true);
       
   303     item(indexOfClassName(QLatin1String("QGroupBox")))->setContainer(true);
       
   304     item(indexOfClassName(QLatin1String("QScrollArea")))->setContainer(true);
       
   305     item(indexOfClassName(QLatin1String("QStackedWidget")))->setContainer(true);
       
   306     item(indexOfClassName(QLatin1String("QToolBox")))->setContainer(true);
       
   307     item(indexOfClassName(QLatin1String("QFrame")))->setContainer(true);
       
   308     item(indexOfClassName(QLatin1String("QLayoutWidget")))->setContainer(true);
       
   309     item(indexOfClassName(QLatin1String("QDesignerWidget")))->setContainer(true);
       
   310     item(indexOfClassName(QLatin1String("QDesignerDialog")))->setContainer(true);
       
   311     item(indexOfClassName(QLatin1String("QSplitter")))->setContainer(true);
       
   312     item(indexOfClassName(QLatin1String("QMainWindow")))->setContainer(true);
       
   313     item(indexOfClassName(QLatin1String("QDockWidget")))->setContainer(true);
       
   314     item(indexOfClassName(QLatin1String("QDesignerDockWidget")))->setContainer(true);
       
   315     item(indexOfClassName(QLatin1String("QDesignerQ3WidgetStack")))->setContainer(true);
       
   316     item(indexOfClassName(QLatin1String("QMdiArea")))->setContainer(true);
       
   317     item(indexOfClassName(QLatin1String("QWorkspace")))->setContainer(true);
       
   318     item(indexOfClassName(QLatin1String("QWizard")))->setContainer(true);
       
   319     item(indexOfClassName(QLatin1String("QWizardPage")))->setContainer(true);
       
   320 
       
   321     item(indexOfClassName(QLatin1String("QWidget")))->setContainer(true);
       
   322     item(indexOfClassName(QLatin1String("QDialog")))->setContainer(true);
       
   323 }
       
   324 
       
   325 WidgetDataBase::~WidgetDataBase()
       
   326 {
       
   327 }
       
   328 
       
   329 QDesignerFormEditorInterface *WidgetDataBase::core() const
       
   330 {
       
   331     return m_core;
       
   332 }
       
   333 
       
   334 int WidgetDataBase::indexOfObject(QObject *object, bool /*resolveName*/) const
       
   335 {
       
   336     QExtensionManager *mgr = m_core->extensionManager();
       
   337     QDesignerLanguageExtension *lang = qt_extension<QDesignerLanguageExtension*> (mgr, m_core);
       
   338 
       
   339     QString id;
       
   340 
       
   341     if (lang)
       
   342         id = lang->classNameOf(object);
       
   343 
       
   344     if (id.isEmpty())
       
   345         id = WidgetFactory::classNameOf(m_core,object);
       
   346 
       
   347     return QDesignerWidgetDataBaseInterface::indexOfClassName(id);
       
   348 }
       
   349 
       
   350 static WidgetDataBaseItem *createCustomWidgetItem(const QDesignerCustomWidgetInterface *c,
       
   351                                                   const QDesignerCustomWidgetData &data)
       
   352 {
       
   353     WidgetDataBaseItem *item = new WidgetDataBaseItem(c->name(), c->group());
       
   354     item->setContainer(c->isContainer());
       
   355     item->setCustom(true);
       
   356     item->setIcon(c->icon());
       
   357     item->setIncludeFile(c->includeFile());
       
   358     item->setToolTip(c->toolTip());
       
   359     item->setWhatsThis(c->whatsThis());
       
   360     item->setPluginPath(data.pluginPath());
       
   361     item->setAddPageMethod(data.xmlAddPageMethod());
       
   362     item->setExtends(data.xmlExtends());
       
   363     return item;
       
   364 }
       
   365 
       
   366 void WidgetDataBase::loadPlugins()
       
   367 {
       
   368     typedef QMap<QString, int> NameIndexMap;
       
   369     typedef QList<QDesignerWidgetDataBaseItemInterface*> ItemList;
       
   370     typedef QMap<QString, QDesignerWidgetDataBaseItemInterface*> NameItemMap;
       
   371     typedef QSet<QString> NameSet;
       
   372     // 1) create a map of existing custom classes
       
   373     NameIndexMap existingCustomClasses;
       
   374     NameSet nonCustomClasses;
       
   375     const int count = m_items.size();
       
   376     for (int i = 0; i < count; i++)    {
       
   377         const QDesignerWidgetDataBaseItemInterface* item =  m_items[i];
       
   378         if (item->isCustom() && !item->isPromoted())
       
   379             existingCustomClasses.insert(item->name(), i);
       
   380         else
       
   381             nonCustomClasses.insert(item->name());
       
   382     }
       
   383     // 2) create a list plugins
       
   384     ItemList pluginList;
       
   385     const QDesignerPluginManager *pm = m_core->pluginManager();
       
   386     foreach(QDesignerCustomWidgetInterface* c, pm->registeredCustomWidgets())
       
   387         pluginList += createCustomWidgetItem(c, pm->customWidgetData(c));
       
   388 
       
   389     // 3) replace custom classes or add new ones, remove them from existingCustomClasses,
       
   390     // leaving behind deleted items
       
   391     unsigned replacedPlugins = 0;
       
   392     unsigned addedPlugins = 0;
       
   393     unsigned removedPlugins = 0;
       
   394     if (!pluginList.empty()) {
       
   395         ItemList::const_iterator cend = pluginList.constEnd();
       
   396         for (ItemList::const_iterator it = pluginList.constBegin();it != cend; ++it )  {
       
   397             QDesignerWidgetDataBaseItemInterface* pluginItem = *it;
       
   398             const QString pluginName = pluginItem->name();
       
   399             NameIndexMap::iterator existingIt = existingCustomClasses.find(pluginName);
       
   400             if (existingIt == existingCustomClasses.end()) {
       
   401                 // Add new class.
       
   402                 if (nonCustomClasses.contains(pluginName)) {
       
   403                     designerWarning(tr("A custom widget plugin whose class name (%1) matches that of an existing class has been found.").arg(pluginName));
       
   404                 } else {
       
   405                     append(pluginItem);
       
   406                     addedPlugins++;
       
   407                 }
       
   408             } else {
       
   409                 // replace existing info
       
   410                 const int existingIndex = existingIt.value();
       
   411                 delete m_items[existingIndex];
       
   412                 m_items[existingIndex] = pluginItem;
       
   413                 existingCustomClasses.erase(existingIt);
       
   414                 replacedPlugins++;
       
   415 
       
   416             }
       
   417         }
       
   418     }
       
   419     // 4) remove classes that have not been matched. The stored indexes become invalid while deleting.
       
   420     if (!existingCustomClasses.empty()) {
       
   421         NameIndexMap::const_iterator cend = existingCustomClasses.constEnd();
       
   422         for (NameIndexMap::const_iterator it = existingCustomClasses.constBegin();it != cend; ++it )  {
       
   423             const int index = indexOfClassName(it.key());
       
   424             if (index != -1) {
       
   425                 remove(index);
       
   426                 removedPlugins++;
       
   427             }
       
   428         }
       
   429     }
       
   430     if (debugWidgetDataBase)
       
   431         qDebug() << "WidgetDataBase::loadPlugins(): " << addedPlugins << " added, " << replacedPlugins << " replaced, " << removedPlugins << "deleted.";
       
   432 }
       
   433 
       
   434 void WidgetDataBase::remove(int index)
       
   435 {
       
   436     Q_ASSERT(index < m_items.size());
       
   437     delete m_items.takeAt(index);
       
   438 }
       
   439 
       
   440 QList<QVariant> WidgetDataBase::defaultPropertyValues(const QString &name)
       
   441 {
       
   442     WidgetFactory *factory = qobject_cast<WidgetFactory *>(m_core->widgetFactory());
       
   443     Q_ASSERT(factory);
       
   444     // Create non-widgets, widgets in order
       
   445     QObject* object = factory->createObject(name, 0);
       
   446     if (!object)
       
   447         object = factory->createWidget(name, 0);
       
   448     if (!object) {
       
   449         qDebug() << "** WARNING Factory failed to create " << name;
       
   450         return QList<QVariant>();
       
   451     }
       
   452     // Get properties from sheet.
       
   453     QList<QVariant> result;
       
   454     if (const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_core->extensionManager(), object)) {
       
   455         const int propertyCount = sheet->count();
       
   456         for (int i = 0; i < propertyCount; ++i) {
       
   457             result.append(sheet->property(i));
       
   458         }
       
   459     }
       
   460     delete object;
       
   461     return result;
       
   462 }
       
   463 
       
   464 void WidgetDataBase::grabDefaultPropertyValues()
       
   465 {
       
   466     const int itemCount = count();
       
   467     for (int i = 0; i < itemCount; ++i) {
       
   468         QDesignerWidgetDataBaseItemInterface *dbItem = item(i);
       
   469         const QList<QVariant> default_prop_values = defaultPropertyValues(dbItem->name());
       
   470         dbItem->setDefaultPropertyValues(default_prop_values);
       
   471     }
       
   472 }
       
   473 
       
   474 void WidgetDataBase::grabStandardWidgetBoxIcons()
       
   475 {
       
   476     // At this point, grab the default icons for the non-custom widgets from
       
   477     // the widget box. They will show up in the object inspector.
       
   478     if (const QDesignerWidgetBox *wb = qobject_cast<const QDesignerWidgetBox *>(m_core->widgetBox())) {
       
   479         const QString qWidgetClass = QLatin1String("QWidget");
       
   480         const int itemCount = count();
       
   481         for (int i = 0; i < itemCount; ++i) {
       
   482             QDesignerWidgetDataBaseItemInterface *dbItem = item(i);
       
   483             if (!dbItem->isCustom() && dbItem->icon().isNull()) {
       
   484                 // Careful not to catch the layout icons when looking for
       
   485                 // QWidget
       
   486                 const QString name = dbItem->name();
       
   487                 if (name == qWidgetClass) {
       
   488                     dbItem->setIcon(wb->iconForWidget(name, QLatin1String("Containers")));
       
   489                 } else {
       
   490                     dbItem->setIcon(wb->iconForWidget(name));
       
   491                 }
       
   492             }
       
   493         }
       
   494     }
       
   495 }
       
   496 
       
   497 // --------------------- Functions relevant generation of new forms based on widgets (apart from the standard templates)
       
   498 
       
   499 enum { NewFormWidth = 400, NewFormHeight = 300 };
       
   500 
       
   501 // Check if class is suitable to generate a form from
       
   502 static inline bool isExistingTemplate(const QString &className)
       
   503 {
       
   504     return className == QLatin1String("QWidget") || className == QLatin1String("QDialog") || className == QLatin1String("QMainWindow");
       
   505 }
       
   506 
       
   507 // Check if class is suitable to generate a form from
       
   508 static inline bool suitableForNewForm(const QString &className)
       
   509 {
       
   510     if (className.isEmpty()) // Missing custom widget information
       
   511         return false;
       
   512     if (className == QLatin1String("QWorkspace"))
       
   513          return false;
       
   514     if (className == QLatin1String("QSplitter"))
       
   515          return false;
       
   516     if (className.startsWith(QLatin1String("QDesigner")) || className.startsWith(QLatin1String("Q3")) ||  className.startsWith(QLatin1String("QLayout")))
       
   517         return false;
       
   518     return true;
       
   519 }
       
   520 
       
   521 // Return a list of widget classes from which new forms can be generated.
       
   522 // Suitable for 'New form' wizards in integrations.
       
   523 QStringList WidgetDataBase::formWidgetClasses(const QDesignerFormEditorInterface *core)
       
   524 {
       
   525     static QStringList rc;
       
   526     if (rc.empty()) {
       
   527         const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
       
   528         const int widgetCount = wdb->count();
       
   529         for (int i = 0; i < widgetCount; i++) {
       
   530             const QDesignerWidgetDataBaseItemInterface *item = wdb->item(i);
       
   531             if (item->isContainer() && !item->isCustom() && !item->isPromoted()) {
       
   532                 const QString name = item->name(); // Standard Widgets: no existing templates
       
   533                 if (!isExistingTemplate(name) && suitableForNewForm(name))
       
   534                     rc += name;
       
   535             }
       
   536         }
       
   537     }
       
   538     return rc;
       
   539 }
       
   540 
       
   541 // Return a list of custom widget classes from which new forms can be generated.
       
   542 // Suitable for 'New form' wizards in integrations.
       
   543 QStringList WidgetDataBase::customFormWidgetClasses(const QDesignerFormEditorInterface *core)
       
   544 {
       
   545     QStringList rc;
       
   546     const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
       
   547     const int widgetCount = wdb->count();
       
   548     for (int i = 0; i < widgetCount; i++) { // Custom widgets: check name and base class.
       
   549         const QDesignerWidgetDataBaseItemInterface *item = wdb->item(i);
       
   550         if (item->isContainer() && item->isCustom() && !item->isPromoted()) {
       
   551             if (suitableForNewForm(item->name()) && suitableForNewForm(item->extends()))
       
   552                 rc += item->name();
       
   553         }
       
   554     }
       
   555     return rc;
       
   556 }
       
   557 
       
   558 // Get XML for a new form from the widget box. Change objectName/geometry
       
   559 // properties to be suitable for new forms
       
   560 static QString xmlFromWidgetBox(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName)
       
   561 {
       
   562     typedef QList<DomProperty*> PropertyList;
       
   563 
       
   564     QDesignerWidgetBoxInterface::Widget widget;
       
   565     const bool found = QDesignerWidgetBox::findWidget(core->widgetBox(), className, QString(), &widget);
       
   566     if (!found)
       
   567         return QString();
       
   568     DomUI *domUI = QDesignerWidgetBox::xmlToUi(className, widget.domXml(), false);
       
   569     domUI->setAttributeVersion(QLatin1String("4.0"));
       
   570     if (!domUI)
       
   571         return QString();
       
   572     DomWidget *domWidget = domUI->elementWidget();
       
   573     if (!domWidget)
       
   574         return QString();
       
   575     // Properties: Remove the "objectName" property in favour of the name attribute and check geometry.
       
   576     domWidget->setAttributeName(objectName);
       
   577     const QString geometryProperty = QLatin1String("geometry");
       
   578     const QString objectNameProperty  = QLatin1String("objectName");
       
   579     PropertyList properties = domWidget->elementProperty();
       
   580     for (PropertyList::iterator it = properties.begin(); it != properties.end(); ) {
       
   581         DomProperty *property = *it;
       
   582         if (property->attributeName() == objectNameProperty) { // remove  "objectName"
       
   583             it = properties.erase(it);
       
   584             delete property;
       
   585         } else {
       
   586             if (property->attributeName() == geometryProperty) { // Make sure form is at least 400, 300
       
   587                 if (DomRect *geom = property->elementRect()) {
       
   588                     if (geom->elementWidth() < NewFormWidth)
       
   589                         geom->setElementWidth(NewFormWidth);
       
   590                     if (geom->elementHeight() < NewFormHeight)
       
   591                         geom->setElementHeight(NewFormHeight);
       
   592                 }
       
   593             }
       
   594             ++it;
       
   595         }
       
   596     }
       
   597     // Add a window title property
       
   598     DomString *windowTitleString = new DomString;
       
   599     windowTitleString->setText(objectName);
       
   600     DomProperty *windowTitleProperty = new DomProperty;
       
   601     windowTitleProperty->setAttributeName(QLatin1String("windowTitle"));
       
   602     windowTitleProperty->setElementString(windowTitleString);
       
   603     properties.push_back(windowTitleProperty);
       
   604     // ------
       
   605     domWidget->setElementProperty(properties);
       
   606     // Embed in in DomUI and get string. Omit the version number.
       
   607     domUI->setElementClass(objectName);
       
   608 
       
   609     QString rc;
       
   610     { // Serialize domUI
       
   611         QXmlStreamWriter writer(&rc);
       
   612         writer.setAutoFormatting(true);
       
   613         writer.setAutoFormattingIndent(1);
       
   614         writer.writeStartDocument();
       
   615         domUI->write(writer);
       
   616         writer.writeEndDocument();
       
   617     }
       
   618     delete domUI;
       
   619     return rc;
       
   620 }
       
   621 
       
   622 // Generate default standard ui new form xml based on the class passed on as similarClassName.
       
   623 static QString generateNewFormXML(const QString &className, const QString &similarClassName, const QString &name)
       
   624 {
       
   625     QString rc; {
       
   626         QTextStream str(&rc);
       
   627         str << QLatin1String("<ui version=\"4.0\" >\n<class>") << name << QLatin1String("</class>\n")
       
   628             <<  QLatin1String("<widget class=\"") << className << QLatin1String("\" name=\"") << name << QLatin1String("\" >\n")
       
   629             <<  QLatin1String("<property name=\"geometry\" >\n<rect><x>0</x><y>0</y><width>")
       
   630             << NewFormWidth << QLatin1String("</width><height>") << NewFormHeight << QLatin1String("</height></rect>\n</property>\n");
       
   631         str << QLatin1String("<property name=\"windowTitle\" >\n<string>") << name << QLatin1String("</string>\n</property>\n");
       
   632 
       
   633         if (similarClassName == QLatin1String("QMainWindow")) {
       
   634             str << QLatin1String("<widget class=\"QWidget\" name=\"centralwidget\" />\n");
       
   635         } else {
       
   636             if (similarClassName == QLatin1String("QWizard"))
       
   637                 str << QLatin1String("<widget class=\"QWizardPage\" name=\"wizardPage1\" /><widget class=\"QWizardPage\" name=\"wizardPage2\" />\n");
       
   638         }
       
   639         str << QLatin1String("</widget>\n</ui>\n");
       
   640     }
       
   641     return rc;
       
   642 }
       
   643 
       
   644 // Generate a form template using a class name obtained from formWidgetClasses(), customFormWidgetClasses().
       
   645 QString WidgetDataBase::formTemplate(const QDesignerFormEditorInterface *core, const QString &className, const QString &objectName)
       
   646 {
       
   647     // How to find suitable XML for a class:
       
   648     // 1) Look in widget box (as all the required centralwidgets, tab widget pages, etc. should be there).
       
   649     const QString widgetBoxXml = xmlFromWidgetBox(core, className, objectName);
       
   650     if (!widgetBoxXml.isEmpty())
       
   651         return widgetBoxXml;
       
   652     // 2) If that fails, only custom main windows, custom dialogs and unsupported Qt Widgets should
       
   653     //    be left over. Generate something that is similar to the default templates. Find a similar class.
       
   654     const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
       
   655     QString similarClass = QLatin1String("QWidget");
       
   656     const int index = wdb->indexOfClassName(className);
       
   657     if (index != -1) {
       
   658         const QDesignerWidgetDataBaseItemInterface *item = wdb->item(index);
       
   659         similarClass = item->isCustom() ? item->extends() : item->name();
       
   660     }
       
   661     // Generate standard ui based on the class passed on as baseClassName.
       
   662     const QString rc = generateNewFormXML(className, similarClass, objectName);
       
   663     return rc;
       
   664 }
       
   665 
       
   666 // Set a fixed size on a XML template
       
   667 QString WidgetDataBase::scaleFormTemplate(const QString &xml, const QSize &size, bool fixed)
       
   668 {
       
   669     typedef QList<DomProperty*> PropertyList;
       
   670     DomUI *domUI = QDesignerWidgetBox::xmlToUi(QLatin1String("Form"), xml, false);
       
   671     if (!domUI)
       
   672         return QString();
       
   673     DomWidget *domWidget = domUI->elementWidget();
       
   674     if (!domWidget)
       
   675         return QString();
       
   676     // Properties: Find/Ensure the geometry, minimum and maximum sizes properties
       
   677     const QString geometryPropertyName = QLatin1String("geometry");
       
   678     const QString minimumSizePropertyName = QLatin1String("minimumSize");
       
   679     const QString maximumSizePropertyName = QLatin1String("maximumSize");
       
   680     DomProperty *geomProperty = 0;
       
   681     DomProperty *minimumSizeProperty = 0;
       
   682     DomProperty *maximumSizeProperty = 0;
       
   683 
       
   684     PropertyList properties = domWidget->elementProperty();
       
   685     const PropertyList::const_iterator cend = properties.constEnd();
       
   686     for (PropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) {
       
   687         const QString name = (*it)->attributeName();
       
   688         if (name == geometryPropertyName) {
       
   689             geomProperty = *it;
       
   690         } else {
       
   691             if (name == minimumSizePropertyName) {
       
   692                 minimumSizeProperty = *it;
       
   693             } else {
       
   694                 if (name == maximumSizePropertyName)
       
   695                     maximumSizeProperty = *it;
       
   696             }
       
   697         }
       
   698     }
       
   699     if (!geomProperty) {
       
   700         geomProperty = new DomProperty;
       
   701         geomProperty->setAttributeName(geometryPropertyName);
       
   702         geomProperty->setElementRect(new DomRect);
       
   703         properties.push_front(geomProperty);
       
   704     }
       
   705     if (fixed) {
       
   706         if (!minimumSizeProperty) {
       
   707             minimumSizeProperty = new DomProperty;
       
   708             minimumSizeProperty->setAttributeName(minimumSizePropertyName);
       
   709             minimumSizeProperty->setElementSize(new DomSize);
       
   710             properties.push_back(minimumSizeProperty);
       
   711         }
       
   712         if (!maximumSizeProperty) {
       
   713             maximumSizeProperty = new DomProperty;
       
   714             maximumSizeProperty->setAttributeName(maximumSizePropertyName);
       
   715             maximumSizeProperty->setElementSize(new DomSize);
       
   716             properties.push_back(maximumSizeProperty);
       
   717         }
       
   718     }
       
   719     // Set values of geometry, minimum and maximum sizes properties
       
   720     const int width = size.width();
       
   721     const int height = size.height();
       
   722     if (DomRect *geom = geomProperty->elementRect()) {
       
   723         geom->setElementWidth(width);
       
   724         geom->setElementHeight(height);
       
   725     }
       
   726     if (fixed) {
       
   727         if (DomSize *s = minimumSizeProperty->elementSize()) {
       
   728             s->setElementWidth(width);
       
   729             s->setElementHeight(height);
       
   730         }
       
   731         if (DomSize *s = maximumSizeProperty->elementSize()) {
       
   732             s->setElementWidth(width);
       
   733             s->setElementHeight(height);
       
   734         }
       
   735     }
       
   736     // write back
       
   737     domWidget->setElementProperty(properties);
       
   738 
       
   739     QString rc;
       
   740     { // serialize domUI
       
   741         QXmlStreamWriter writer(&rc);
       
   742         writer.setAutoFormatting(true);
       
   743         writer.setAutoFormattingIndent(1);
       
   744         writer.writeStartDocument();
       
   745         domUI->write(writer);
       
   746         writer.writeEndDocument();
       
   747     }
       
   748 
       
   749     delete domUI;
       
   750     return rc;
       
   751 }
       
   752 
       
   753 // ---- free functions
       
   754 QDESIGNER_SHARED_EXPORT IncludeSpecification  includeSpecification(QString includeFile)
       
   755 {
       
   756     const bool global = !includeFile.isEmpty() &&
       
   757                         includeFile[0] == QLatin1Char('<') &&
       
   758                         includeFile[includeFile.size() - 1] ==  QLatin1Char('>');
       
   759     if (global) {
       
   760         includeFile.remove(includeFile.size() - 1, 1);
       
   761         includeFile.remove(0, 1);
       
   762     }
       
   763     return IncludeSpecification(includeFile, global ? IncludeGlobal : IncludeLocal);
       
   764 }
       
   765 
       
   766 QDESIGNER_SHARED_EXPORT QString buildIncludeFile(QString includeFile, IncludeType includeType) {
       
   767     if (includeType == IncludeGlobal && !includeFile.isEmpty()) {
       
   768         includeFile.append(QLatin1Char('>'));
       
   769         includeFile.insert(0, QLatin1Char('<'));
       
   770     }
       
   771     return includeFile;
       
   772 }
       
   773 
       
   774 
       
   775 /* Appends a derived class to the database inheriting the data of the base class. Used
       
   776    for custom and promoted widgets.
       
   777 
       
   778    Depending on whether an entry exists, the existing or a newly created entry is
       
   779    returned. A return value of 0 indicates that the base class could not be found. */
       
   780 
       
   781 QDESIGNER_SHARED_EXPORT QDesignerWidgetDataBaseItemInterface *
       
   782         appendDerived(QDesignerWidgetDataBaseInterface *db,
       
   783                       const QString &className, const QString &group,
       
   784                       const QString &baseClassName,
       
   785                       const QString &includeFile,
       
   786                       bool promoted, bool custom)
       
   787 {
       
   788     if (debugWidgetDataBase)
       
   789         qDebug() << "appendDerived " << className << " derived from " << baseClassName;
       
   790     // Check.
       
   791     if (className.isEmpty() || baseClassName.isEmpty()) {
       
   792         qWarning("** WARNING %s called with an empty class names: '%s' extends '%s'.",
       
   793                  Q_FUNC_INFO, className.toUtf8().constData(), baseClassName.toUtf8().constData());
       
   794         return 0;
       
   795     }
       
   796     // Check whether item already exists.
       
   797     QDesignerWidgetDataBaseItemInterface *derivedItem = 0;
       
   798     const int existingIndex = db->indexOfClassName(className);
       
   799     if ( existingIndex != -1)
       
   800         derivedItem =  db->item(existingIndex);
       
   801     if (derivedItem) {
       
   802         // Check the existing item for base class mismatch. This will likely
       
   803         // happen when loading a file written by an instance with missing plugins.
       
   804         // In that case, just warn and ignore the file properties.
       
   805         //
       
   806         // An empty base class indicates that it is not known (for example, for custom plugins).
       
   807         // In this case, the widget DB is later updated once the widget is created
       
   808         // by DOM (by querying the metaobject). Suppress the warning.
       
   809         const QString existingBaseClass = derivedItem->extends();
       
   810         if (existingBaseClass.isEmpty() || baseClassName ==  existingBaseClass)
       
   811             return derivedItem;
       
   812 
       
   813         // Warn about mismatches
       
   814         designerWarning(QCoreApplication::translate("WidgetDataBase",
       
   815           "The file contains a custom widget '%1' whose base class (%2)"
       
   816           " differs from the current entry in the widget database (%3)."
       
   817           " The widget database is left unchanged.").
       
   818                         arg(className, baseClassName, existingBaseClass));
       
   819         return derivedItem;
       
   820     }
       
   821     // Create this item, inheriting its base properties
       
   822     const int baseIndex = db->indexOfClassName(baseClassName);
       
   823     if (baseIndex == -1) {
       
   824         if (debugWidgetDataBase)
       
   825             qDebug() << "appendDerived failed due to missing base class";
       
   826         return 0;
       
   827     }
       
   828     const QDesignerWidgetDataBaseItemInterface *baseItem = db->item(baseIndex);
       
   829     derivedItem = WidgetDataBaseItem::clone(baseItem);
       
   830     // Sort of hack: If base class is QWidget, we most likely
       
   831     // do not want to inherit the container attribute.
       
   832     static const QString qWidgetName = QLatin1String("QWidget");
       
   833     if (baseItem->name() == qWidgetName)
       
   834         derivedItem->setContainer(false);
       
   835     // set new props
       
   836     derivedItem->setName(className);
       
   837     derivedItem->setGroup(group);
       
   838     derivedItem->setCustom(custom);
       
   839     derivedItem->setPromoted(promoted);
       
   840     derivedItem->setExtends(baseClassName);
       
   841     derivedItem->setIncludeFile(includeFile);
       
   842     db->append(derivedItem);
       
   843     return derivedItem;
       
   844 }
       
   845 
       
   846 /* Return a list of database items to which a class can be promoted to. */
       
   847 
       
   848 QDESIGNER_SHARED_EXPORT WidgetDataBaseItemList
       
   849         promotionCandidates(const QDesignerWidgetDataBaseInterface *db,
       
   850                             const QString &baseClassName)
       
   851 {
       
   852     WidgetDataBaseItemList rc;
       
   853     // find existing promoted widgets deriving from base.
       
   854     const int count = db->count();
       
   855     for (int i = 0; i < count; ++i) {
       
   856         QDesignerWidgetDataBaseItemInterface *item = db->item(i);
       
   857         if (item->isPromoted() && item->extends() == baseClassName) {
       
   858             rc.push_back(item);
       
   859         }
       
   860     }
       
   861     return rc;
       
   862 }
       
   863 } // namespace qdesigner_internal
       
   864 
       
   865 QT_END_NAMESPACE