From 024b548e130b8503c2521090af76d50874005e36 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Mon, 29 Jun 2009 14:47:04 +0200
Subject: [PATCH] Added a wizard for Qt Designer custom widgets and
 collections.

Add the wizard. Modify basefilewizard to use be able to handle binary
data. Add some properties to path chooser (filters).

Task-number: 251982
Initial-patch-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
---
 src/libs/utils/pathchooser.cpp                |  24 +-
 src/libs/utils/pathchooser.h                  |   8 +
 src/plugins/coreplugin/basefilewizard.cpp     |  39 ++-
 src/plugins/coreplugin/basefilewizard.h       |   9 +-
 .../customwidgetwizard/classdefinition.cpp    | 152 ++++++++
 .../customwidgetwizard/classdefinition.h      |  72 ++++
 .../customwidgetwizard/classdefinition.ui     | 324 +++++++++++++++++
 .../customwidgetwizard/classlist.cpp          |  87 +++++
 .../customwidgetwizard/classlist.h            |  63 ++++
 .../customwidgetpluginwizardpage.cpp          | 156 +++++++++
 .../customwidgetpluginwizardpage.h            |  85 +++++
 .../customwidgetpluginwizardpage.ui           | 131 +++++++
 .../customwidgetwidgetswizardpage.cpp         | 117 +++++++
 .../customwidgetwidgetswizardpage.h           |  91 +++++
 .../customwidgetwidgetswizardpage.ui          |  61 ++++
 .../customwidgetwizard/customwidgetwizard.cpp |  72 ++++
 .../customwidgetwizard/customwidgetwizard.h   |  57 +++
 .../customwidgetwizard/customwidgetwizard.pri |  25 ++
 .../customwidgetwizarddialog.cpp              | 114 ++++++
 .../customwidgetwizarddialog.h                |  84 +++++
 .../customwidgetwizard/filenamingparameters.h |  86 +++++
 .../customwidgetwizard/plugingenerator.cpp    | 326 ++++++++++++++++++
 .../customwidgetwizard/plugingenerator.h      |  75 ++++
 .../customwidgetwizard/pluginoptions.h        |  74 ++++
 .../templates/templates.qrc                   |  14 +
 .../templates/tpl_collection.cpp              |  14 +
 .../templates/tpl_collection.h                |  21 ++
 .../templates/tpl_plugin.pro                  |  13 +
 .../templates/tpl_resources.qrc               |   5 +
 .../templates/tpl_single.cpp                  |  71 ++++
 .../customwidgetwizard/templates/tpl_single.h |  30 ++
 .../templates/tpl_widget.cpp                  |   6 +
 .../customwidgetwizard/templates/tpl_widget.h |  14 +
 .../templates/tpl_widget_include.pri          |   2 +
 .../templates/tpl_widget_lib.pro              |   4 +
 .../qt4projectmanager/qt4projectmanager.pro   |   1 +
 .../qt4projectmanagerplugin.cpp               |   2 +
 37 files changed, 2521 insertions(+), 8 deletions(-)
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.cpp
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.ui
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/classlist.cpp
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/classlist.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.cpp
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.ui
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.ui
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.cpp
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.pri
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizarddialog.cpp
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizarddialog.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/filenamingparameters.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/plugingenerator.cpp
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/plugingenerator.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/pluginoptions.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/templates.qrc
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_collection.cpp
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_collection.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_plugin.pro
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_resources.qrc
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_single.cpp
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_single.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget.cpp
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget.h
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget_include.pri
 create mode 100644 src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget_lib.pro

diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp
index a3535374a37..59e3222badd 100644
--- a/src/libs/utils/pathchooser.cpp
+++ b/src/libs/utils/pathchooser.cpp
@@ -88,6 +88,7 @@ struct PathChooserPrivate
     PathValidatingLineEdit *m_lineEdit;
     PathChooser::Kind m_acceptingKind;
     QString m_dialogTitleOverride;
+    QString m_dialogFilter;
     QString m_initialBrowsePathOverride;
 };
 
@@ -171,7 +172,8 @@ void PathChooser::slotBrowse()
     case PathChooser::File: // fall through
     case PathChooser::Command:
         newPath = QFileDialog::getOpenFileName(this,
-                makeDialogTitle(tr("Choose a file")), predefined);
+                makeDialogTitle(tr("Choose a file")), predefined,
+                m_d->m_dialogFilter);
         break;
 
     default:
@@ -278,11 +280,31 @@ void PathChooser::setExpectedKind(Kind expected)
     m_d->m_acceptingKind = expected;
 }
 
+PathChooser::Kind PathChooser::expectedKind() const
+{
+    return m_d->m_acceptingKind;
+}
+
 void PathChooser::setPromptDialogTitle(const QString &title)
 {
     m_d->m_dialogTitleOverride = title;
 }
 
+QString PathChooser::promptDialogTitle() const
+{
+    return m_d->m_dialogTitleOverride;
+}
+
+void PathChooser::setPromptDialogFilter(const QString &filter)
+{
+    m_d->m_dialogFilter = filter;
+}
+
+QString PathChooser::promptDialogFilter() const
+{
+    return m_d->m_dialogFilter;
+}
+
 void PathChooser::setInitialBrowsePathBackup(const QString &path)
 {
     m_d->m_initialBrowsePathOverride = path;
diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h
index 91f5c89a650..7222dc3aedb 100644
--- a/src/libs/utils/pathchooser.h
+++ b/src/libs/utils/pathchooser.h
@@ -47,7 +47,10 @@ class QTCREATOR_UTILS_EXPORT PathChooser : public QWidget
 {
     Q_DISABLE_COPY(PathChooser)
     Q_OBJECT
+    Q_ENUMS(Kind)
     Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true)
+    Q_PROPERTY(QString promptDialogTitle READ promptDialogTitle WRITE setPromptDialogTitle DESIGNABLE true)
+    Q_PROPERTY(Kind expectedKind READ expectedKind WRITE setExpectedKind DESIGNABLE true)
 
 public:
     static const char * const browseButtonLabel;
@@ -64,8 +67,13 @@ public:
 
     // Default is <Directory>
     void setExpectedKind(Kind expected);
+    Kind expectedKind() const;
 
     void setPromptDialogTitle(const QString &title);
+    QString promptDialogTitle() const;
+
+    void setPromptDialogFilter(const QString &filter);
+    QString promptDialogFilter() const;
 
     void setInitialBrowsePathBackup(const QString &path);
 
diff --git a/src/plugins/coreplugin/basefilewizard.cpp b/src/plugins/coreplugin/basefilewizard.cpp
index 1d1c4e0e418..245aa4e8175 100644
--- a/src/plugins/coreplugin/basefilewizard.cpp
+++ b/src/plugins/coreplugin/basefilewizard.cpp
@@ -58,15 +58,17 @@ namespace Core {
 class GeneratedFilePrivate : public QSharedData
 {
 public:
-    GeneratedFilePrivate() {}
+    GeneratedFilePrivate() : binary(false) {}
     explicit GeneratedFilePrivate(const QString &p);
     QString path;
-    QString contents;
+    QByteArray contents;
     QString editorKind;
+    bool binary;
 };
 
 GeneratedFilePrivate::GeneratedFilePrivate(const QString &p) :
-    path(p)
+    path(p),
+    binary(false)
 {
 }
 
@@ -108,14 +110,34 @@ void GeneratedFile::setPath(const QString &p)
 
 QString GeneratedFile::contents() const
 {
-    return m_d->contents;
+    return QString::fromUtf8(m_d->contents);
 }
 
 void GeneratedFile::setContents(const QString &c)
+{
+    m_d->contents = c.toUtf8();
+}
+
+QByteArray GeneratedFile::binaryContents() const
+{
+    return m_d->contents;
+}
+
+void GeneratedFile::setBinaryContents(const QByteArray &c)
 {
     m_d->contents = c;
 }
 
+bool GeneratedFile::isBinary() const
+{
+    return m_d->binary;
+}
+
+void GeneratedFile::setBinary(bool b)
+{
+    m_d->binary = b;
+}
+
 QString GeneratedFile::editorKind() const
 {
     return m_d->editorKind;
@@ -139,11 +161,16 @@ bool GeneratedFile::write(QString *errorMessage) const
     }
     // Write out
     QFile file(m_d->path);
-    if (!file.open(QIODevice::WriteOnly|QIODevice::Text)) {
+
+    QIODevice::OpenMode flags = QIODevice::WriteOnly|QIODevice::Truncate;
+    if (!isBinary())
+        flags |= QIODevice::Text;
+
+    if (!file.open(flags)) {
         *errorMessage = BaseFileWizard::tr("Unable to open %1 for writing: %2").arg(m_d->path, file.errorString());
         return false;
     }
-    if (file.write(m_d->contents.toUtf8()) == -1) {
+    if (file.write(m_d->contents) == -1) {
         *errorMessage =  BaseFileWizard::tr("Error while writing to %1: %2").arg(m_d->path, file.errorString());
         return false;
     }
diff --git a/src/plugins/coreplugin/basefilewizard.h b/src/plugins/coreplugin/basefilewizard.h
index 87f1c6f56f4..36ffb924982 100644
--- a/src/plugins/coreplugin/basefilewizard.h
+++ b/src/plugins/coreplugin/basefilewizard.h
@@ -71,10 +71,17 @@ public:
     QString path() const;
     void setPath(const QString &p);
 
-    // Contents of the file
+    // Contents of the file (UTF8)
     QString contents() const;
     void setContents(const QString &c);
 
+    QByteArray binaryContents() const;
+    void setBinaryContents(const QByteArray &c);
+
+    // Defaults to false (Text file).
+    bool isBinary() const;
+    void setBinary(bool b);
+
     // Kind of editor to open the file with
     QString editorKind() const;
     void setEditorKind(const QString &k);
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.cpp
new file mode 100644
index 00000000000..557c1ea1169
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.cpp
@@ -0,0 +1,152 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#include "classdefinition.h"
+
+#include <QtCore/QFileInfo>
+#include <QtGui/QFileDialog>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+ClassDefinition::ClassDefinition(QWidget *parent) :
+    QTabWidget(parent),
+    m_domXmlChanged(false)
+{
+    setupUi(this);
+    iconPathChooser->setExpectedKind(Core::Utils::PathChooser::File);
+    iconPathChooser->setPromptDialogTitle(tr("Select Icon"));
+    iconPathChooser->setPromptDialogFilter(tr("Icon files (*.png *.ico *.jpg *.xpm *.tif *.svg)"));
+}
+
+void ClassDefinition::on_libraryRadio_toggled()
+{
+    const bool enLib = libraryRadio->isChecked();
+    widgetLibraryLabel->setEnabled(enLib);
+    widgetLibraryEdit->setEnabled(enLib);
+
+    const bool enSrc = skeletonCheck->isChecked();
+    widgetSourceLabel->setEnabled(enSrc);
+    widgetSourceEdit->setEnabled(enSrc);
+    widgetBaseClassLabel->setEnabled(enSrc);
+    widgetBaseClassEdit->setEnabled(enSrc);
+
+    const bool enPrj = !enLib || enSrc;
+    widgetProjectLabel->setEnabled(enPrj);
+    widgetProjectEdit->setEnabled(enPrj);
+    widgetProjectEdit->setText(
+        QFileInfo(widgetProjectEdit->text()).completeBaseName() +
+        (libraryRadio->isChecked() ? QLatin1String(".pro") : QLatin1String(".pri")));
+}
+
+void ClassDefinition::on_skeletonCheck_toggled()
+{
+    on_libraryRadio_toggled();
+}
+
+static inline QString xmlFromClassName(const QString &name)
+{
+    QString rc = QLatin1String("<widget class=\"");
+    rc += name;
+    rc += QLatin1String("\" name=\"");
+    if (!name.isEmpty()) {
+        rc += name.left(1).toLower();
+        if (name.size() > 1)
+            rc += name.mid(1);
+    }
+    rc += QLatin1String("\">\n</widget>\n");
+    return rc;
+}
+
+void ClassDefinition::setClassName(const QString &name)
+{
+    widgetLibraryEdit->setText(name.toLower());
+    widgetHeaderEdit->setText(m_fileNamingParameters.headerFileName(name));
+    pluginClassEdit->setText(name + QLatin1String("Plugin"));
+    if (!m_domXmlChanged) {
+        domXmlEdit->setText(xmlFromClassName(name));
+        m_domXmlChanged = false;
+    }
+}
+
+void ClassDefinition::on_widgetLibraryEdit_textChanged()
+{
+    widgetProjectEdit->setText(
+        widgetLibraryEdit->text() +
+        (libraryRadio->isChecked() ? QLatin1String(".pro") : QLatin1String(".pri")));
+}
+
+void ClassDefinition::on_widgetHeaderEdit_textChanged()
+{
+    widgetSourceEdit->setText(m_fileNamingParameters.headerToSourceFileName(widgetHeaderEdit->text()));
+}
+
+void ClassDefinition::on_pluginClassEdit_textChanged()
+{
+    pluginHeaderEdit->setText(m_fileNamingParameters.headerFileName(pluginClassEdit->text()));
+}
+
+void ClassDefinition::on_pluginHeaderEdit_textChanged()
+{
+    pluginSourceEdit->setText(m_fileNamingParameters.headerToSourceFileName(pluginHeaderEdit->text()));
+}
+
+void ClassDefinition::on_domXmlEdit_textChanged()
+{
+    m_domXmlChanged = true;
+}
+
+PluginOptions::WidgetOptions ClassDefinition::widgetOptions(const QString &className) const
+{
+    PluginOptions::WidgetOptions wo;
+    wo.createSkeleton = skeletonCheck->isChecked();
+    wo.sourceType =
+            libraryRadio->isChecked() ?
+            PluginOptions::WidgetOptions::LinkLibrary :
+            PluginOptions::WidgetOptions::IncludeProject;
+    wo.widgetLibrary = widgetLibraryEdit->text();
+    wo.widgetProjectFile = widgetProjectEdit->text();
+    wo.widgetClassName = className;
+    wo.widgetHeaderFile = widgetHeaderEdit->text();
+    wo.widgetSourceFile = widgetSourceEdit->text();
+    wo.widgetBaseClassName = widgetBaseClassEdit->text();
+    wo.pluginClassName = pluginClassEdit->text();
+    wo.pluginHeaderFile = pluginHeaderEdit->text();
+    wo.pluginSourceFile = pluginSourceEdit->text();
+    wo.iconFile = iconPathChooser->path();
+    wo.group = groupEdit->text();
+    wo.toolTip = tooltipEdit->text();
+    wo.whatsThis = whatsthisEdit->toPlainText();
+    wo.isContainer = containerCheck->isChecked();
+    wo.domXml = domXmlEdit->toPlainText();
+    return wo;
+}
+
+}
+}
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.h b/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.h
new file mode 100644
index 00000000000..111bb45a862
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.h
@@ -0,0 +1,72 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#ifndef CLASSDEFINITION_H
+#define CLASSDEFINITION_H
+
+#include "ui_classdefinition.h"
+#include "filenamingparameters.h"
+#include "pluginoptions.h"
+
+#include <QtGui/QTabWidget>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ClassDefinition : public QTabWidget, private Ui::ClassDefinition
+{
+    Q_OBJECT
+
+public:
+    ClassDefinition(QWidget *parent);
+    void setClassName(const QString &name);
+
+    FileNamingParameters fileNamingParameters() const { return m_fileNamingParameters; }
+    void setFileNamingParameters(const FileNamingParameters &fnp) { m_fileNamingParameters = fnp; }
+
+    PluginOptions::WidgetOptions widgetOptions(const QString &className) const;
+
+public Q_SLOTS:
+    void on_libraryRadio_toggled();
+    void on_skeletonCheck_toggled();
+    void on_widgetLibraryEdit_textChanged();
+    void on_widgetHeaderEdit_textChanged();
+    void on_pluginClassEdit_textChanged();
+    void on_pluginHeaderEdit_textChanged();
+    void on_domXmlEdit_textChanged();
+
+private:
+    FileNamingParameters m_fileNamingParameters;
+    bool m_domXmlChanged;
+};
+
+}
+}
+
+#endif
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.ui b/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.ui
new file mode 100644
index 00000000000..6d390cffa45
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.ui
@@ -0,0 +1,324 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Qt4ProjectManager::Internal::ClassDefinition</class>
+ <widget class="QTabWidget" name="Qt4ProjectManager::Internal::ClassDefinition">
+  <property name="enabled">
+   <bool>true</bool>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>649</width>
+    <height>427</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <property name="whatsThis">
+   <string>The header file</string>
+  </property>
+  <property name="currentIndex">
+   <number>0</number>
+  </property>
+  <widget class="QWidget" name="sourceTab">
+   <attribute name="title">
+    <string>&amp;Sources</string>
+   </attribute>
+   <layout class="QVBoxLayout" name="verticalLayout">
+    <item>
+     <layout class="QFormLayout" name="formLayout">
+      <item row="1" column="0">
+       <widget class="QLabel" name="widgetLibraryLabel">
+        <property name="text">
+         <string>Widget librar&amp;y:</string>
+        </property>
+        <property name="buddy">
+         <cstring>widgetLibraryEdit</cstring>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLineEdit" name="widgetLibraryEdit"/>
+      </item>
+      <item row="2" column="0">
+       <widget class="QLabel" name="widgetProjectLabel">
+        <property name="text">
+         <string>Widget project &amp;file:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+        <property name="buddy">
+         <cstring>widgetProjectEdit</cstring>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1">
+       <widget class="QLineEdit" name="widgetProjectEdit"/>
+      </item>
+      <item row="3" column="0">
+       <widget class="QLabel" name="widgetHeaderLabel">
+        <property name="text">
+         <string>Widget h&amp;eader file:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+        <property name="buddy">
+         <cstring>widgetHeaderEdit</cstring>
+        </property>
+       </widget>
+      </item>
+      <item row="3" column="1">
+       <widget class="QLineEdit" name="widgetHeaderEdit">
+        <property name="whatsThis">
+         <string>The header file as to be specified i source code. </string>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="0">
+       <widget class="QLabel" name="widgetSourceLabel">
+        <property name="text">
+         <string>Widge&amp;t source file:</string>
+        </property>
+        <property name="buddy">
+         <cstring>widgetSourceEdit</cstring>
+        </property>
+       </widget>
+      </item>
+      <item row="4" column="1">
+       <widget class="QLineEdit" name="widgetSourceEdit"/>
+      </item>
+      <item row="5" column="0">
+       <widget class="QLabel" name="widgetBaseClassLabel">
+        <property name="text">
+         <string>Widget &amp;base class:</string>
+        </property>
+        <property name="buddy">
+         <cstring>widgetBaseClassEdit</cstring>
+        </property>
+       </widget>
+      </item>
+      <item row="5" column="1">
+       <widget class="QLineEdit" name="widgetBaseClassEdit">
+        <property name="text">
+         <string>QWidget</string>
+        </property>
+       </widget>
+      </item>
+      <item row="6" column="0">
+       <widget class="QLabel" name="pluginClassLabel">
+        <property name="text">
+         <string>Plugin class &amp;name:</string>
+        </property>
+        <property name="buddy">
+         <cstring>pluginClassEdit</cstring>
+        </property>
+       </widget>
+      </item>
+      <item row="6" column="1">
+       <widget class="QLineEdit" name="pluginClassEdit"/>
+      </item>
+      <item row="7" column="0">
+       <widget class="QLabel" name="pluginHeaderLabel">
+        <property name="text">
+         <string>Plugin &amp;header file:</string>
+        </property>
+        <property name="buddy">
+         <cstring>pluginHeaderEdit</cstring>
+        </property>
+       </widget>
+      </item>
+      <item row="7" column="1">
+       <widget class="QLineEdit" name="pluginHeaderEdit"/>
+      </item>
+      <item row="8" column="0">
+       <widget class="QLabel" name="pluginSourceLabel">
+        <property name="text">
+         <string>Plugin sou&amp;rce file:</string>
+        </property>
+        <property name="buddy">
+         <cstring>pluginSourceEdit</cstring>
+        </property>
+       </widget>
+      </item>
+      <item row="8" column="1">
+       <widget class="QLineEdit" name="pluginSourceEdit"/>
+      </item>
+      <item row="9" column="0">
+       <widget class="QLabel" name="iconLabel">
+        <property name="text">
+         <string>Icon file:</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item row="9" column="1">
+       <widget class="Core::Utils::PathChooser" name="iconPathChooser"/>
+      </item>
+      <item row="0" column="1">
+       <layout class="QGridLayout" name="gridLayout">
+        <item row="0" column="0">
+         <widget class="QRadioButton" name="libraryRadio">
+          <property name="text">
+           <string>&amp;Link library</string>
+          </property>
+          <property name="checked">
+           <bool>false</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1" rowspan="2">
+         <widget class="QCheckBox" name="skeletonCheck">
+          <property name="text">
+           <string>Create s&amp;keleton</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QRadioButton" name="includeRadio">
+          <property name="text">
+           <string>Include pro&amp;ject</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWidget" name="descriptionTab">
+   <attribute name="title">
+    <string>&amp;Description</string>
+   </attribute>
+   <layout class="QFormLayout" name="formLayout_2">
+    <property name="fieldGrowthPolicy">
+     <enum>QFormLayout::ExpandingFieldsGrow</enum>
+    </property>
+    <item row="0" column="0">
+     <widget class="QLabel" name="label_2">
+      <property name="text">
+       <string>G&amp;roup:</string>
+      </property>
+      <property name="buddy">
+       <cstring>groupEdit</cstring>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="1">
+     <widget class="QLineEdit" name="groupEdit"/>
+    </item>
+    <item row="1" column="0">
+     <widget class="QLabel" name="label_3">
+      <property name="text">
+       <string>&amp;Tooltip:</string>
+      </property>
+      <property name="buddy">
+       <cstring>tooltipEdit</cstring>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="1">
+     <widget class="QLineEdit" name="tooltipEdit"/>
+    </item>
+    <item row="2" column="0">
+     <widget class="QLabel" name="label_4">
+      <property name="text">
+       <string>W&amp;hat's this:</string>
+      </property>
+      <property name="buddy">
+       <cstring>whatsthisEdit</cstring>
+      </property>
+     </widget>
+    </item>
+    <item row="2" column="1">
+     <widget class="QTextEdit" name="whatsthisEdit">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>36</height>
+       </size>
+      </property>
+      <property name="maximumSize">
+       <size>
+        <width>16777215</width>
+        <height>100</height>
+       </size>
+      </property>
+     </widget>
+    </item>
+    <item row="3" column="1">
+     <widget class="QCheckBox" name="containerCheck">
+      <property name="text">
+       <string>The widget is a &amp;container</string>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWidget" name="propertyDefaults">
+   <attribute name="title">
+    <string>Property defa&amp;ults</string>
+   </attribute>
+   <layout class="QGridLayout" name="gridLayout_3">
+    <item row="1" column="0">
+     <widget class="QTextEdit" name="domXmlEdit"/>
+    </item>
+    <item row="0" column="0">
+     <widget class="QLabel" name="label_6">
+      <property name="text">
+       <string>dom&amp;XML:</string>
+      </property>
+      <property name="buddy">
+       <cstring>domXmlEdit</cstring>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>Core::Utils::PathChooser</class>
+   <extends>QWidget</extends>
+   <header location="global">utils/pathchooser.h</header>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>libraryRadio</tabstop>
+  <tabstop>includeRadio</tabstop>
+  <tabstop>skeletonCheck</tabstop>
+  <tabstop>widgetLibraryEdit</tabstop>
+  <tabstop>widgetProjectEdit</tabstop>
+  <tabstop>widgetHeaderEdit</tabstop>
+  <tabstop>widgetSourceEdit</tabstop>
+  <tabstop>widgetBaseClassEdit</tabstop>
+  <tabstop>pluginClassEdit</tabstop>
+  <tabstop>pluginHeaderEdit</tabstop>
+  <tabstop>pluginSourceEdit</tabstop>
+  <tabstop>groupEdit</tabstop>
+  <tabstop>tooltipEdit</tabstop>
+  <tabstop>whatsthisEdit</tabstop>
+  <tabstop>containerCheck</tabstop>
+  <tabstop>domXmlEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/classlist.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/classlist.cpp
new file mode 100644
index 00000000000..ef150349d5d
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/classlist.cpp
@@ -0,0 +1,87 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#include "classlist.h"
+
+#include <QtGui/QKeyEvent>
+#include <QtGui/QMessageBox>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+ClassList::ClassList(QWidget *parent) :
+    QListWidget(parent)
+{
+    connect(itemDelegate(), SIGNAL(closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint)), SLOT(classEdited()));
+    insertNewItem();
+}
+
+void ClassList::classEdited()
+{
+    if (currentRow() == count() - 1) {
+        if (currentItem()->text() != tr("<New class>")) {
+            emit classAdded(currentItem()->text());
+            insertNewItem();
+        }
+    } else {
+        emit classRenamed(currentRow(), currentItem()->text());
+    }
+}
+
+void ClassList::insertNewItem()
+{
+    QListWidgetItem *itm = new QListWidgetItem(tr("<New class>"), this);
+    itm->setFlags(Qt::ItemIsEnabled|Qt::ItemIsEditable);
+}
+
+void ClassList::keyPressEvent(QKeyEvent *event)
+{
+    if (event->key() == Qt::Key_Delete) {
+        const int row = currentRow();
+        if (row != count() - 1) {
+            if (QMessageBox::question(this,
+                tr("Confirm Delete"),
+                tr("Delete class %1 from list?").arg(currentItem()->text()),
+                QMessageBox::Ok|QMessageBox::Cancel) == QMessageBox::Ok)
+            {
+                delete currentItem();
+                emit classDeleted(row);
+                setCurrentRow(row);
+            }
+        }
+    } else if (event->key() == Qt::Key_Insert) {
+        setCurrentRow(count() - 1);
+        editItem(currentItem());
+    } else {
+        QListWidget::keyPressEvent(event);
+    }
+}
+
+}
+}
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/classlist.h b/src/plugins/qt4projectmanager/customwidgetwizard/classlist.h
new file mode 100644
index 00000000000..ac9919545f0
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/classlist.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#ifndef CLASSLIST_H
+#define CLASSLIST_H
+
+#include <QtGui/QListWidget>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ClassList : public QListWidget
+{
+    Q_OBJECT
+
+public:
+    ClassList(QWidget *parent);
+
+public slots:
+    void classEdited();
+
+signals:
+    void classAdded(const QString &name);
+    void classRenamed(int index, const QString &newName);
+    void classDeleted(int index);
+
+protected:
+    void keyPressEvent(QKeyEvent *event);
+
+private:
+    void insertNewItem();
+};
+
+}
+}
+
+#endif
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.cpp
new file mode 100644
index 00000000000..c4bc6f0cb4d
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.cpp
@@ -0,0 +1,156 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#include "customwidgetpluginwizardpage.h"
+#include "customwidgetwidgetswizardpage.h"
+#include "pluginoptions.h"
+#include "ui_customwidgetpluginwizardpage.h"
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+CustomWidgetPluginWizardPage::CustomWidgetPluginWizardPage(QWidget *parent) :
+    QWizardPage(parent),
+    m_ui(new Ui::CustomWidgetPluginWizardPage),
+    m_classCount(-1),
+    m_complete(false)
+{
+    m_ui->setupUi(this);
+    connect(m_ui->collectionClassEdit, SIGNAL(textEdited(QString)), this, SLOT(slotCheckCompleteness()));
+    connect(m_ui->pluginNameEdit, SIGNAL(textEdited(QString)), this, SLOT(slotCheckCompleteness()));
+}
+
+CustomWidgetPluginWizardPage::~CustomWidgetPluginWizardPage()
+{
+    delete m_ui;
+}
+
+QString CustomWidgetPluginWizardPage::collectionClassName() const
+{
+    return m_ui->collectionClassEdit->text();
+}
+
+QString CustomWidgetPluginWizardPage::pluginName() const
+{
+    return m_ui->pluginNameEdit->text();
+}
+
+// Determine name for Q_EXPORT_PLUGIN
+static inline QString createPluginName(const QString &prefix)
+{
+    return prefix.toLower() + QLatin1String("plugin");
+}
+
+void CustomWidgetPluginWizardPage::init(const CustomWidgetWidgetsWizardPage *widgetsPage)
+{
+    m_classCount = widgetsPage->classCount();
+    const QString empty;
+    if (m_classCount == 1) {
+        m_ui->pluginNameEdit->setText(createPluginName(widgetsPage->classNameAt(0)));
+        setCollectionEnabled(false);
+    } else {
+        m_ui->pluginNameEdit->setText(empty);
+        setCollectionEnabled(true);
+    }
+    m_ui->collectionClassEdit->setText(empty);
+    m_ui->collectionHeaderEdit->setText(empty);
+    m_ui->collectionSourceEdit->setText(empty);
+
+    slotCheckCompleteness();
+}
+
+void CustomWidgetPluginWizardPage::setCollectionEnabled(bool enColl)
+{
+    m_ui->collectionClassLabel->setEnabled(enColl);
+    m_ui->collectionClassEdit->setEnabled(enColl);
+    m_ui->collectionHeaderLabel->setEnabled(enColl);
+    m_ui->collectionHeaderEdit->setEnabled(enColl);
+    m_ui->collectionSourceLabel->setEnabled(enColl);
+    m_ui->collectionSourceEdit->setEnabled(enColl);
+}
+
+void CustomWidgetPluginWizardPage::on_collectionClassEdit_textChanged()
+{
+    const QString collectionClass = collectionClassName();
+    m_ui->collectionHeaderEdit->setText(m_fileNamingParameters.headerFileName(collectionClass));
+    m_ui->pluginNameEdit->setText(createPluginName(collectionClass));
+}
+
+void CustomWidgetPluginWizardPage::on_collectionHeaderEdit_textChanged()
+{
+    m_ui->collectionSourceEdit->setText(m_fileNamingParameters.headerToSourceFileName(m_ui->collectionHeaderEdit->text()));
+}
+
+QSharedPointer<PluginOptions> CustomWidgetPluginWizardPage::basicPluginOptions() const
+{
+    QSharedPointer<PluginOptions> po(new PluginOptions);
+    po->pluginName = pluginName();
+    po->resourceFile = m_ui->resourceFileEdit->text();
+    po->collectionClassName = collectionClassName();
+    po->collectionHeaderFile = m_ui->collectionHeaderEdit->text();
+    po->collectionSourceFile = m_ui->collectionSourceEdit->text();
+    return po;
+}
+
+void CustomWidgetPluginWizardPage::slotCheckCompleteness()
+{
+    // A collection is complete only with class name
+    bool completeNow = false;
+    if (!pluginName().isEmpty()) {
+        if (m_classCount > 1) {
+            completeNow = !collectionClassName().isEmpty();
+        } else {
+            completeNow = true;
+        }
+    }
+    if (completeNow != m_complete) {
+        m_complete = completeNow;
+        emit completeChanged();
+    }
+}
+
+bool CustomWidgetPluginWizardPage::isComplete() const
+{
+    return m_complete;
+}
+
+void CustomWidgetPluginWizardPage::changeEvent(QEvent *e)
+{
+    QWizardPage::changeEvent(e);
+    switch (e->type()) {
+            case QEvent::LanguageChange:
+        m_ui->retranslateUi(this);
+        break;
+            default:
+        break;
+    }
+}
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.h b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.h
new file mode 100644
index 00000000000..0a3d825320a
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.h
@@ -0,0 +1,85 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#ifndef CUSTOMWIDGETPLUGINWIZARDPAGE_H
+#define CUSTOMWIDGETPLUGINWIZARDPAGE_H
+
+#include "filenamingparameters.h"
+
+#include <QtGui/QWizardPage>
+#include <QtCore/QSharedPointer>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+struct PluginOptions;
+class CustomWidgetWidgetsWizardPage;
+
+namespace Ui {
+    class CustomWidgetPluginWizardPage;
+}
+
+class CustomWidgetPluginWizardPage : public QWizardPage {
+    Q_OBJECT
+public:
+    CustomWidgetPluginWizardPage(QWidget *parent = 0);
+    ~CustomWidgetPluginWizardPage();
+
+    void init(const CustomWidgetWidgetsWizardPage *widgetsPage);
+
+    virtual bool isComplete() const;
+
+    FileNamingParameters fileNamingParameters() const { return m_fileNamingParameters; }
+    void setFileNamingParameters(const FileNamingParameters &fnp) {m_fileNamingParameters = fnp; }
+
+    // Fills the plugin fields, excluding widget list.
+    QSharedPointer<PluginOptions> basicPluginOptions() const;
+
+protected:
+    void changeEvent(QEvent *e);
+
+private slots:
+    void on_collectionClassEdit_textChanged();
+    void on_collectionHeaderEdit_textChanged();
+    void slotCheckCompleteness();
+
+private:
+    inline QString collectionClassName() const;
+    inline QString pluginName() const;
+    void setCollectionEnabled(bool enColl);
+
+    Ui::CustomWidgetPluginWizardPage *m_ui;
+    FileNamingParameters m_fileNamingParameters;
+    int m_classCount;
+    bool m_complete;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+#endif // CUSTOMWIDGETPLUGINWIZARDPAGE_H
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.ui b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.ui
new file mode 100644
index 00000000000..ce9d886b1f8
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.ui
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Qt4ProjectManager::Internal::CustomWidgetPluginWizardPage</class>
+ <widget class="QWizardPage" name="Qt4ProjectManager::Internal::CustomWidgetPluginWizardPage">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>591</width>
+    <height>446</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>WizardPage</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <layout class="QFormLayout" name="formLayout">
+       <property name="fieldGrowthPolicy">
+        <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+       </property>
+       <item row="0" column="0">
+        <widget class="QLabel" name="collectionClassLabel">
+         <property name="text">
+          <string>Collection class:</string>
+         </property>
+         <property name="buddy">
+          <cstring>collectionClassEdit</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="0" column="1">
+        <widget class="QLineEdit" name="collectionClassEdit">
+         <property name="text">
+          <string/>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="0">
+        <widget class="QLabel" name="collectionHeaderLabel">
+         <property name="text">
+          <string>Collection header file:</string>
+         </property>
+         <property name="buddy">
+          <cstring>collectionHeaderEdit</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QLineEdit" name="collectionHeaderEdit"/>
+       </item>
+       <item row="2" column="0">
+        <widget class="QLabel" name="collectionSourceLabel">
+         <property name="text">
+          <string>Collection source file:</string>
+         </property>
+         <property name="buddy">
+          <cstring>collectionSourceEdit</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="2" column="1">
+        <widget class="QLineEdit" name="collectionSourceEdit"/>
+       </item>
+       <item row="3" column="0">
+        <widget class="QLabel" name="pluginNameLabel">
+         <property name="text">
+          <string>Plugin name:</string>
+         </property>
+         <property name="buddy">
+          <cstring>pluginNameEdit</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="3" column="1">
+        <widget class="QLineEdit" name="pluginNameEdit"/>
+       </item>
+       <item row="4" column="0">
+        <widget class="QLabel" name="resourceFileLabel">
+         <property name="text">
+          <string>Resource file:</string>
+         </property>
+         <property name="buddy">
+          <cstring>resourceFileEdit</cstring>
+         </property>
+        </widget>
+       </item>
+       <item row="4" column="1">
+        <widget class="QLineEdit" name="resourceFileEdit">
+         <property name="text">
+          <string>icons.qrc</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp
new file mode 100644
index 00000000000..41fded6d797
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp
@@ -0,0 +1,117 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#include "customwidgetwidgetswizardpage.h"
+#include "ui_customwidgetwidgetswizardpage.h"
+#include "plugingenerator.h"
+#include "classdefinition.h"
+
+#include <QtCore/QFileInfo>
+
+#include <QtGui/QStackedLayout>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+CustomWidgetWidgetsWizardPage::CustomWidgetWidgetsWizardPage(QWidget *parent) :
+    QWizardPage(parent),
+    m_ui(new Ui::CustomWidgetWidgetsWizardPage),
+    m_complete(false)
+{
+    m_ui->setupUi(this);
+    m_tabStack = new QStackedLayout(m_ui->tabStackWidget);
+    m_dummyTab = new QWidget(m_ui->tabStackWidget);
+    m_tabStack->addWidget(m_dummyTab);
+    connect(m_ui->classList, SIGNAL(currentRowChanged(int)), m_tabStack, SLOT(setCurrentIndex(int)));
+}
+
+CustomWidgetWidgetsWizardPage::~CustomWidgetWidgetsWizardPage()
+{
+    delete m_ui;
+}
+
+bool CustomWidgetWidgetsWizardPage::isComplete() const
+{
+    return m_complete;
+}
+
+void CustomWidgetWidgetsWizardPage::on_classList_classAdded(const QString &name)
+{
+    ClassDefinition *cdef = new ClassDefinition(m_ui->tabStackWidget);
+    cdef->setFileNamingParameters(m_fileNamingParameters);
+    const int index = m_uiClassDefs.count();
+    m_tabStack->insertWidget(index, cdef);
+    m_tabStack->setCurrentIndex(index);
+    m_uiClassDefs.append(cdef);
+    cdef->on_libraryRadio_toggled();
+    on_classList_classRenamed(index, name);
+    // First class or collection class, re-check.
+    slotCheckCompleteness();
+}
+
+void CustomWidgetWidgetsWizardPage::on_classList_classDeleted(int index)
+{
+    delete m_tabStack->widget(index);
+    m_uiClassDefs.removeAt(index);
+    if (m_uiClassDefs.empty())
+        slotCheckCompleteness();
+}
+
+void CustomWidgetWidgetsWizardPage::on_classList_classRenamed(int index, const QString &name)
+{
+    m_uiClassDefs[index]->setClassName(name);
+}
+
+QString CustomWidgetWidgetsWizardPage::classNameAt(int i) const
+{
+    return m_ui->classList->item(i)->text();
+}
+
+QList<PluginOptions::WidgetOptions> CustomWidgetWidgetsWizardPage::widgetOptions() const
+{
+    QList<PluginOptions::WidgetOptions> rc;
+    for (int i = 0; i < m_uiClassDefs.count(); i++) {
+        const ClassDefinition *cdef = m_uiClassDefs[i];
+        rc.push_back(cdef->widgetOptions(classNameAt(i)));
+    }
+    return rc;
+}
+
+void CustomWidgetWidgetsWizardPage::slotCheckCompleteness()
+{
+    // Complete if either a single custom widget or a collection
+    // with a collection class name specified.
+    bool completeNow = !m_uiClassDefs.isEmpty();
+    if (completeNow != m_complete) {
+        m_complete = completeNow;
+        emit completeChanged();
+    }
+}
+}
+}
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.h b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.h
new file mode 100644
index 00000000000..fc32d9579c9
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.h
@@ -0,0 +1,91 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#ifndef CUSTOMWIDGETWIDGETSWIZARDPAGE_H
+#define CUSTOMWIDGETWIDGETSWIZARDPAGE_H
+
+#include "pluginoptions.h"
+#include "filenamingparameters.h"
+
+#include <QtCore/QList>
+#include <QtGui/QWizardPage>
+
+QT_BEGIN_NAMESPACE
+class QStackedLayout;
+QT_END_NAMESPACE
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class ClassDefinition;
+struct PluginOptions;
+
+namespace Ui {
+    class CustomWidgetWidgetsWizardPage;
+}
+
+class CustomWidgetWidgetsWizardPage : public QWizardPage
+{
+    Q_OBJECT
+
+public:
+    explicit CustomWidgetWidgetsWizardPage(QWidget *parent = 0);
+    virtual ~CustomWidgetWidgetsWizardPage();
+
+    QList<PluginOptions::WidgetOptions> widgetOptions() const;
+
+    virtual bool isComplete() const;
+
+    FileNamingParameters fileNamingParameters() const { return m_fileNamingParameters; }
+    void setFileNamingParameters(const FileNamingParameters &fnp) {m_fileNamingParameters = fnp; }
+
+    int classCount() const { return m_uiClassDefs.size(); }
+    QString classNameAt(int i) const;
+
+private Q_SLOTS:
+    void on_classList_classAdded(const QString &name);
+    void on_classList_classDeleted(int index);
+    void on_classList_classRenamed(int index, const QString &newName);
+    void slotCheckCompleteness();
+
+private:
+    void updatePluginTab();
+
+    Ui::CustomWidgetWidgetsWizardPage *m_ui;
+    QList<ClassDefinition *> m_uiClassDefs;
+    QStackedLayout *m_tabStack;
+    QWidget *m_dummyTab;
+    FileNamingParameters m_fileNamingParameters;
+    bool m_complete;
+};
+
+}
+}
+
+#endif // CUSTOMWIDGETWIDGETSWIZARDPAGE_H
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.ui b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.ui
new file mode 100644
index 00000000000..f96c6303c7d
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.ui
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Qt4ProjectManager::Internal::CustomWidgetWidgetsWizardPage</class>
+ <widget class="QWizardPage" name="Qt4ProjectManager::Internal::CustomWidgetWidgetsWizardPage">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>668</width>
+    <height>430</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Custom Qt Widget Wizard</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>Widget &amp;Classes:</string>
+     </property>
+     <property name="buddy">
+      <cstring>classList</cstring>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1" rowspan="2">
+    <widget class="QWidget" name="tabStackWidget" native="true">
+     <property name="minimumSize">
+      <size>
+       <width>400</width>
+       <height>200</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="Qt4ProjectManager::Internal::ClassList" name="classList">
+     <property name="minimumSize">
+      <size>
+       <width>0</width>
+       <height>400</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>Qt4ProjectManager::Internal::ClassList</class>
+   <extends>QListWidget</extends>
+   <header>classlist.h</header>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>classList</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.cpp
new file mode 100644
index 00000000000..0617d145123
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.cpp
@@ -0,0 +1,72 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#include "customwidgetwizard.h"
+#include "customwidgetwizarddialog.h"
+#include "plugingenerator.h"
+#include "pluginoptions.h"
+#include "filenamingparameters.h"
+
+#include <cpptools/cppmodelmanagerinterface.h>
+#include <utils/pathchooser.h>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+CustomWidgetWizard::CustomWidgetWizard() :
+    QtWizard(tr("Qt4 Designer Custom Widget"),
+             tr("Creates a Qt4 Designer Custom Widget or a Custom Widget Collection."),
+             QIcon(":/wizards/images/gui.png"))
+{
+}
+
+QWizard *CustomWidgetWizard::createWizardDialog(QWidget *parent,
+                                                const QString &defaultPath,
+                                                const WizardPageList &extensionPages) const
+{
+    CustomWidgetWizardDialog *rc = new CustomWidgetWizardDialog(name(), icon(), extensionPages, parent);
+    rc->setPath(defaultPath.isEmpty() ? Core::Utils::PathChooser::homePath() : defaultPath);
+    rc->setFileNamingParameters(FileNamingParameters(headerSuffix(), sourceSuffix(), QtWizard::lowerCaseFiles()));
+    return rc;
+}
+
+Core::GeneratedFiles CustomWidgetWizard::generateFiles(const QWizard *w,
+                                                       QString *errorMessage) const
+{
+    const CustomWidgetWizardDialog *cw = qobject_cast<const CustomWidgetWizardDialog *>(w);
+    Q_ASSERT(w);
+    GenerationParameters p;
+    p.name = cw->name();
+    p.path = cw->path();
+    p.license = CppTools::AbstractEditorSupport::licenseTemplate();
+    return PluginGenerator::generatePlugin(p, *(cw->pluginOptions()), errorMessage);
+}
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.h b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.h
new file mode 100644
index 00000000000..e9c310e1e2f
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.h
@@ -0,0 +1,57 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#ifndef CUSTOMWIDGETWIZARD_H
+#define CUSTOMWIDGETWIZARD_H
+
+#include "../wizards/qtwizard.h"
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class CustomWidgetWizard : public QtWizard
+{
+    Q_DISABLE_COPY(CustomWidgetWizard)
+    Q_OBJECT
+public:
+    CustomWidgetWizard();
+
+protected:
+    virtual QWizard *createWizardDialog(QWidget *parent,
+                                        const QString &defaultPath,
+                                        const WizardPageList &extensionPages) const;
+
+    virtual Core::GeneratedFiles generateFiles(const QWizard *w,
+                                               QString *errorMessage) const;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // CUSTOMWIDGETWIZARD_H
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.pri b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.pri
new file mode 100644
index 00000000000..a52a62848a3
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.pri
@@ -0,0 +1,25 @@
+INCLUDEPATH *= $$PWD
+SOURCES += \
+ $$PWD/plugingenerator.cpp \
+ $$PWD/classlist.cpp \
+ $$PWD/classdefinition.cpp \
+ $$PWD/customwidgetwidgetswizardpage.cpp \
+ $$PWD/customwidgetpluginwizardpage.cpp \
+ $$PWD/customwidgetwizarddialog.cpp \
+ $$PWD/customwidgetwizard.cpp
+HEADERS += \
+ $$PWD/classlist.h \
+ $$PWD/plugingenerator.h \
+ $$PWD/pluginoptions.h \
+ $$PWD/classdefinition.h \
+ $$PWD/customwidgetwizarddialog.h \
+ $$PWD/customwidgetwidgetswizardpage.h \
+ $$PWD/customwidgetpluginwizardpage.h \
+ $$PWD/customwidgetwizard.h \
+ $$PWD/filenamingparameters.h
+
+FORMS += \
+ $$PWD/classdefinition.ui \
+ $$PWD/customwidgetwidgetswizardpage.ui \
+ $$PWD/customwidgetpluginwizardpage.ui
+RESOURCES +=  $$PWD/templates/templates.qrc
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizarddialog.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizarddialog.cpp
new file mode 100644
index 00000000000..48f7ef96d53
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizarddialog.cpp
@@ -0,0 +1,114 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#include "customwidgetwizarddialog.h"
+#include "customwidgetwidgetswizardpage.h"
+#include "customwidgetpluginwizardpage.h"
+#include "customwidgetwizard.h"
+
+#include <utils/projectintropage.h>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+enum { IntroPageId, WidgetsPageId, PluginPageId };
+
+CustomWidgetWizardDialog::CustomWidgetWizardDialog(const QString &templateName,
+                                                   const QIcon &icon,
+                                                   const QList<QWizardPage*> &extensionPages,
+                                                   QWidget *parent) :
+    QWizard(parent),
+    m_introPage(new Core::Utils::ProjectIntroPage),
+    m_widgetsPage(new CustomWidgetWidgetsWizardPage),
+    m_pluginPage(new CustomWidgetPluginWizardPage)
+
+{
+    setWindowIcon(icon);
+    setWindowTitle(templateName);
+    Core::BaseFileWizard::setupWizard(this);
+
+    m_introPage->setDescription(tr("This wizard generates a Qt4 Designer Custom Widget "
+                          "or a Qt4 Designer Custom Widget Collection project."));
+
+    setPage(IntroPageId, m_introPage);
+    setPage(WidgetsPageId, m_widgetsPage);
+    setPage(PluginPageId, m_pluginPage);
+
+    foreach (QWizardPage *p, extensionPages)
+        addPage(p);
+    connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(slotCurrentIdChanged(int)));
+}
+
+void CustomWidgetWizardDialog::setPath(const QString &path)
+{
+    m_introPage->setPath(path);
+}
+
+QString CustomWidgetWizardDialog::path() const
+{
+    return m_introPage->path();
+}
+
+QString CustomWidgetWizardDialog::name() const
+{
+    return m_introPage->name();
+}
+
+FileNamingParameters CustomWidgetWizardDialog::fileNamingParameters() const
+{
+    return m_widgetsPage->fileNamingParameters();
+}
+
+void CustomWidgetWizardDialog::setFileNamingParameters(const FileNamingParameters &fnp)
+{
+    m_widgetsPage->setFileNamingParameters(fnp);
+    m_pluginPage->setFileNamingParameters(fnp);
+}
+
+void CustomWidgetWizardDialog::slotCurrentIdChanged(int id)
+{
+    switch (id) {
+    case IntroPageId:
+    case WidgetsPageId:
+        break;
+    case PluginPageId:
+        m_pluginPage->init(m_widgetsPage);
+        break;
+    }
+}
+
+QSharedPointer<PluginOptions> CustomWidgetWizardDialog::pluginOptions() const
+{
+    QSharedPointer<PluginOptions> rc = m_pluginPage->basicPluginOptions();
+    rc->widgetOptions = m_widgetsPage->widgetOptions();
+    return rc;
+}
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizarddialog.h b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizarddialog.h
new file mode 100644
index 00000000000..b3f56c072a2
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizarddialog.h
@@ -0,0 +1,84 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#ifndef CUSTOMWIDGETWIZARDDIALOG_H
+#define CUSTOMWIDGETWIZARDDIALOG_H
+
+#include <QtCore/QSharedPointer>
+
+#include <QtGui/QWizard>
+#include <QtGui/QWizardPage>
+
+namespace Core {
+    namespace Utils {
+        class ProjectIntroPage;
+    }
+}
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+class CustomWidgetWidgetsWizardPage;
+class CustomWidgetPluginWizardPage;
+struct PluginOptions;
+struct FileNamingParameters;
+
+class CustomWidgetWizardDialog : public QWizard
+{
+    Q_OBJECT
+public:
+    explicit CustomWidgetWizardDialog(const QString &templateName,
+                                      const QIcon &icon,
+                                      const QList<QWizardPage*> &extensionPages,
+                                      QWidget *parent);
+
+    QSharedPointer<PluginOptions> pluginOptions() const;
+
+    QString path() const;
+    QString name() const;
+
+    FileNamingParameters fileNamingParameters() const;
+    void setFileNamingParameters(const FileNamingParameters &fnp);
+
+public slots:
+    void setPath(const QString &path);
+
+private slots:
+    void slotCurrentIdChanged (int id);
+
+private:
+    Core::Utils::ProjectIntroPage *m_introPage;
+    CustomWidgetWidgetsWizardPage *m_widgetsPage;
+    CustomWidgetPluginWizardPage *m_pluginPage;
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // CUSTOMWIDGETWIZARDDIALOG_H
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/filenamingparameters.h b/src/plugins/qt4projectmanager/customwidgetwizard/filenamingparameters.h
new file mode 100644
index 00000000000..c83079c2706
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/filenamingparameters.h
@@ -0,0 +1,86 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#ifndef FILENAMINGPARAMETERS_H
+#define FILENAMINGPARAMETERS_H
+
+#include <QtCore/QString>
+#include <QtCore/QFileInfo>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+/* Helper struct specifying how to generate file names
+ * from class names according to the CppTools settings. */
+
+struct FileNamingParameters
+{
+    FileNamingParameters(const QString &headerSuffixIn = QString(QLatin1Char('h')),
+                         const QString &sourceSuffixIn = QLatin1String("cpp"),
+                         bool lowerCaseIn = true) :
+        headerSuffix(headerSuffixIn),
+        sourceSuffix(sourceSuffixIn),
+        lowerCase(lowerCaseIn) {}
+
+    inline QString sourceFileName(const QString &className) const {
+        QString rc = lowerCase ? className.toLower() : className;
+        rc += QLatin1Char('.');
+        rc += sourceSuffix;
+        return rc;
+    }
+
+    inline QString headerFileName(const QString &className) const {
+        QString rc = lowerCase ? className.toLower() : className;
+        rc += QLatin1Char('.');
+        rc += headerSuffix;
+        return rc;
+    }
+
+    inline QString sourceToHeaderFileName(const QString &source) const {
+        QString rc = QFileInfo(source).completeBaseName();
+        rc += QLatin1Char('.');
+        rc += headerSuffix;
+        return rc;
+    }
+
+    inline QString headerToSourceFileName(const QString &header) const {
+        QString rc = QFileInfo(header).completeBaseName();
+        rc += QLatin1Char('.');
+        rc += sourceSuffix;
+        return rc;
+    }
+
+    QString headerSuffix;
+    QString sourceSuffix;
+    bool lowerCase;
+};
+
+}
+}
+#endif // FILENAMINGPARAMETERS_H
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/plugingenerator.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/plugingenerator.cpp
new file mode 100644
index 00000000000..b2b67808921
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/plugingenerator.cpp
@@ -0,0 +1,326 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#include "plugingenerator.h"
+#include "pluginoptions.h"
+
+#include <coreplugin/basefilewizard.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QSet>
+
+static QString headerGuard(const QString &header)
+{
+    return header.toUpper().replace(QRegExp(QLatin1String("[^A-Z0-9]+")), QLatin1String("_"));
+}
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+struct ProjectContents {
+    QString tmpl;
+    QString library;
+    QString headers;
+    QString sources;
+};
+
+// Create a binary icon file
+static inline Core::GeneratedFile  generateIconFile(const QString &source, const QString &target, QString *errorMessage)
+{
+    // Read out source
+    QFile iconFile(source);
+    if (!iconFile.open(QIODevice::ReadOnly)) {
+        *errorMessage = PluginGenerator::tr("Cannot open icon file %1.").arg(source);
+        return Core::GeneratedFile();
+    }
+    const QByteArray iconData = iconFile.readAll();
+    Core::GeneratedFile rc(target);
+    rc.setBinaryContents(iconData);
+    rc.setBinary(true);
+    return rc;
+}
+
+QList<Core::GeneratedFile>  PluginGenerator::generatePlugin(const GenerationParameters& p, const PluginOptions &options,
+                                                            QString *errorMessage)
+{
+    const QChar slash = QLatin1Char('/');
+    const QChar blank = QLatin1Char(' ');
+    QList<Core::GeneratedFile> rc;
+
+    QString baseDir = p.path;
+    baseDir += slash;
+    baseDir += p.name;
+    const QString slashLessBaseDir = baseDir;
+    baseDir += slash;
+
+    QSet<QString> widgetLibraries;
+    QSet<QString> widgetProjects;
+    QMap<QString,ProjectContents> widgetProjectContents;
+    QString pluginIncludes;
+    QString pluginAdditions;
+    QString pluginHeaders;
+    QString pluginSources;
+    QSet<QString> pluginIcons;
+
+    SubstitutionMap sm;
+
+    // First create the widget wrappers (plugins) and - if requested - skeletons
+    // for the widgets.
+    foreach (const PluginOptions::WidgetOptions &wo, options.widgetOptions) {
+        sm.clear();
+        sm.insert(QLatin1String("SINGLE_INCLUDE_GUARD"), headerGuard(wo.pluginHeaderFile));
+        sm.insert(QLatin1String("PLUGIN_CLASS"), wo.pluginClassName);
+        const QString pluginHeaderContents = processTemplate(QLatin1String(":/tpl_single.h"), sm, errorMessage);
+        if (pluginHeaderContents.isEmpty())
+            return QList<Core::GeneratedFile>();
+        Core::GeneratedFile pluginHeader(baseDir + wo.pluginHeaderFile);
+        pluginHeader.setContents(p.license + pluginHeaderContents);
+        rc.push_back(pluginHeader);
+
+        sm.remove(QLatin1String("SINGLE_INCLUDE_GUARD"));
+        sm.insert(QLatin1String("PLUGIN_HEADER"), wo.pluginHeaderFile);
+        sm.insert(QLatin1String("WIDGET_CLASS"), wo.widgetClassName);
+        sm.insert(QLatin1String("WIDGET_HEADER"), wo.widgetHeaderFile);
+        sm.insert(QLatin1String("WIDGET_GROUP"), wo.group);
+        QString iconResource;
+        if (!wo.iconFile.isEmpty()) {
+            iconResource = QLatin1String("QLatin1String(\":/");
+            iconResource += QFileInfo(wo.iconFile).fileName();
+            iconResource += QLatin1String("\")");
+        }
+        sm.insert(QLatin1String("WIDGET_ICON"),iconResource);
+        sm.insert(QLatin1String("WIDGET_TOOLTIP"), cStringQuote(wo.toolTip));
+        sm.insert(QLatin1String("WIDGET_WHATSTHIS"), cStringQuote(wo.whatsThis));
+        sm.insert(QLatin1String("WIDGET_ISCONTAINER"), wo.isContainer ? QLatin1String("true") : QLatin1String("false"));
+        sm.insert(QLatin1String("WIDGET_DOMXML"), cStringQuote(wo.domXml));
+        sm.insert(QLatin1String("SINGLE_PLUGIN_EXPORT"),
+            options.widgetOptions.count() == 1 ?
+                QLatin1String("\nQ_EXPORT_PLUGIN2(") +
+                    options.pluginName +
+                    QLatin1String(", ") +
+                    wo.pluginClassName +
+                    QLatin1Char(')') :
+                QLatin1String(""));
+        const QString pluginSourceContents = processTemplate(QLatin1String(":/tpl_single.cpp"), sm, errorMessage);
+        if (pluginSourceContents.isEmpty())
+            return QList<Core::GeneratedFile>();
+        Core::GeneratedFile pluginSource(baseDir + wo.pluginSourceFile);
+        pluginSource.setContents(p.license + pluginSourceContents);
+        rc.push_back(pluginSource);
+
+        if (wo.sourceType == PluginOptions::WidgetOptions::LinkLibrary)
+            widgetLibraries.insert(QLatin1String("-l") + wo.widgetLibrary);
+        else
+            widgetProjects.insert(QLatin1String("include(") + wo.widgetProjectFile + QLatin1String(")"));
+        pluginIncludes += QLatin1String("#include \"") + wo.pluginHeaderFile + QLatin1String("\"\n");
+        pluginAdditions +=
+            QLatin1String("    m_widgets.append(new ") + wo.pluginClassName + QLatin1String("(this));\n");
+        pluginHeaders += QLatin1Char(' ') + wo.pluginHeaderFile;
+        pluginSources += QLatin1Char(' ') + wo.pluginSourceFile;
+        if (!wo.iconFile.isEmpty())
+            pluginIcons.insert(wo.iconFile);
+
+        if (wo.createSkeleton) {
+            ProjectContents &pc = widgetProjectContents[wo.widgetProjectFile];
+            if (pc.headers.isEmpty()) {
+                if (wo.sourceType == PluginOptions::WidgetOptions::LinkLibrary) {
+                    pc.library = wo.widgetLibrary;
+                    pc.tmpl = QLatin1String(":/tpl_widget_lib.pro");
+                } else {
+                    pc.tmpl = QLatin1String(":/tpl_widget_include.pri");
+                }
+                widgetProjectContents.insert(wo.widgetProjectFile, pc);
+            } else {
+                if (pc.library != wo.widgetLibrary) {
+                    *errorMessage = tr("Creating multiple widget libraries (%1, %2) in one project (%3) is not supported.")
+                        .arg(pc.library, wo.widgetLibrary, wo.widgetProjectFile);
+                    return QList<Core::GeneratedFile>();
+                }
+            }
+            pc.headers += blank + wo.widgetHeaderFile;
+            pc.sources += blank + wo.widgetSourceFile;
+
+            sm.clear();
+            sm.insert(QLatin1String("WIDGET_INCLUDE_GUARD"), headerGuard(wo.widgetHeaderFile));
+            sm.insert(QLatin1String("WIDGET_BASE_CLASS"), wo.widgetBaseClassName);
+            sm.insert(QLatin1String("WIDGET_CLASS"), wo.widgetClassName);
+            const QString widgetHeaderContents = processTemplate(QLatin1String(":/tpl_widget.h"), sm, errorMessage);
+            if (widgetHeaderContents.isEmpty())
+                return QList<Core::GeneratedFile>();
+            Core::GeneratedFile widgetHeader(baseDir + wo.widgetHeaderFile);
+            widgetHeader.setContents(p.license + widgetHeaderContents);
+            rc.push_back(widgetHeader);
+
+            sm.remove(QLatin1String("WIDGET_INCLUDE_GUARD"));
+            sm.insert(QLatin1String("WIDGET_HEADER"), wo.widgetHeaderFile);
+            const QString widgetSourceContents = processTemplate(QLatin1String(":/tpl_widget.cpp"), sm, errorMessage);
+            if (widgetSourceContents.isEmpty())
+                return QList<Core::GeneratedFile>();
+            Core::GeneratedFile widgetSource(baseDir + wo.widgetSourceFile);
+            widgetSource.setContents(p.license + widgetSourceContents);
+            rc.push_back(widgetSource);
+        }
+    }
+
+    // Then create the project files for the widget skeletons.
+    // These might create widgetLibraries or be included into the plugin's project.
+    QMap<QString,ProjectContents>::const_iterator it = widgetProjectContents.constBegin();
+    const QMap<QString,ProjectContents>::const_iterator end = widgetProjectContents.constEnd();
+    for (; it != end; ++it) {
+        const ProjectContents &pc = it.value();
+        sm.clear();
+        sm.insert(QLatin1String("WIDGET_HEADERS"), pc.headers);
+        sm.insert(QLatin1String("WIDGET_SOURCES"), pc.sources);
+        if (!pc.library.isEmpty())
+            sm.insert(QLatin1String("WIDGET_LIBRARY"), pc.library);
+        const QString widgetPriContents = processTemplate(pc.tmpl, sm, errorMessage);
+        if (widgetPriContents.isEmpty())
+            return QList<Core::GeneratedFile>();
+        Core::GeneratedFile widgetPri(baseDir + it.key());
+        widgetPri.setContents(widgetPriContents);
+        rc.push_back(widgetPri);
+    }
+
+    // Create the sources for the collection if necessary.
+    if (options.widgetOptions.count() > 1) {
+        sm.clear();
+        sm.insert(QLatin1String("COLLECTION_INCLUDE_GUARD"), headerGuard(options.collectionHeaderFile));
+        sm.insert(QLatin1String("COLLECTION_PLUGIN_CLASS"), options.collectionClassName);
+        const QString collectionHeaderContents = processTemplate(QLatin1String(":/tpl_collection.h"), sm, errorMessage);
+        if (collectionHeaderContents.isEmpty())
+            return QList<Core::GeneratedFile>();
+        Core::GeneratedFile collectionHeader(baseDir + options.collectionHeaderFile);
+        collectionHeader.setContents(p.license + collectionHeaderContents);
+        rc.push_back(collectionHeader);
+
+        sm.remove(QLatin1String("COLLECTION_INCLUDE_GUARD"));
+        sm.insert(QLatin1String("PLUGIN_INCLUDES"),
+            pluginIncludes +
+            QLatin1String("#include \"") +
+                options.collectionHeaderFile +
+                QLatin1String("\""));
+        sm.insert(QLatin1String("PLUGIN_ADDITIONS"), pluginAdditions);
+        sm.insert(QLatin1String("COLLECTION_PLUGIN_EXPORT"),
+            QLatin1String("Q_EXPORT_PLUGIN2(") +
+                options.pluginName +
+                QLatin1String(", ") +
+                options.collectionClassName +
+                QLatin1Char(')'));
+        const QString collectionSourceFileContents = processTemplate(QLatin1String(":/tpl_collection.cpp"), sm, errorMessage);
+        if (collectionSourceFileContents.isEmpty())
+            return QList<Core::GeneratedFile>();
+        Core::GeneratedFile collectionSource(baseDir + options.collectionSourceFile);
+        collectionSource.setContents(p.license + collectionSourceFileContents);
+        rc.push_back(collectionSource);
+
+        pluginHeaders += blank + options.collectionHeaderFile;
+        pluginSources += blank + options.collectionSourceFile;
+    }
+
+    // Copy icons that are not in the plugin source base directory yet (that is,
+    // probably all), add them to the resource file
+    QString iconFiles;
+    foreach (QString icon, pluginIcons) {
+        const QFileInfo qfi(icon);
+        if (qfi.dir() != slashLessBaseDir) {
+            const QString newIcon = baseDir + qfi.fileName();
+            const Core::GeneratedFile iconFile = generateIconFile(icon, newIcon, errorMessage);
+            if (iconFile.path().isEmpty())
+                return QList<Core::GeneratedFile>();
+            rc.push_back(iconFile);
+            icon = qfi.fileName();
+        }
+        iconFiles += QLatin1String("        <file>") + icon + QLatin1String("</file>\n");
+    }
+    // Create the resource file with the icons.
+    sm.clear();
+    sm.insert(QLatin1String("ICON_FILES"), iconFiles);
+    const QString resourceFileContents = processTemplate(QLatin1String(":/tpl_resources.qrc"), sm, errorMessage);
+    if (resourceFileContents.isEmpty())
+        return QList<Core::GeneratedFile>();
+    Core::GeneratedFile resourceFile(baseDir + options.resourceFile);
+    resourceFile.setContents(resourceFileContents);
+    rc.push_back(resourceFile);
+
+    // Finally create the project for the plugin itself.
+    sm.clear();
+    sm.insert(QLatin1String("PLUGIN_NAME"), options.pluginName);
+    sm.insert(QLatin1String("PLUGIN_HEADERS"), pluginHeaders);
+    sm.insert(QLatin1String("PLUGIN_SOURCES"), pluginSources);
+    sm.insert(QLatin1String("PLUGIN_RESOURCES"), options.resourceFile);
+    sm.insert(QLatin1String("WIDGET_LIBS"), QStringList(widgetLibraries.toList()).join(QString(blank)));
+    sm.insert(QLatin1String("INCLUSIONS"), QStringList(widgetProjects.toList()).join(QLatin1String("\n")));
+    const QString proFileContents = processTemplate(QLatin1String(":/tpl_plugin.pro"), sm, errorMessage);
+    if (proFileContents.isEmpty())
+        return QList<Core::GeneratedFile>();
+    Core::GeneratedFile proFile(baseDir + p.name + QLatin1String(".pro"));
+    proFile.setContents(proFileContents);
+    rc.push_back(proFile);
+    return rc;
+}
+
+QString PluginGenerator::processTemplate(const QString &tmpl,
+                                         const SubstitutionMap &substMap,
+                                         QString *errorMessage)
+{
+    QFile tpl(tmpl);
+    if (!tpl.open(QIODevice::ReadOnly|QIODevice::Text)) {
+        *errorMessage = tr("Cannot open %1: %2").arg(tmpl, tpl.errorString());
+        return QString();
+    }
+
+    QString cont = QString::fromUtf8(tpl.readAll());
+    const QChar atChar = QLatin1Char('@');
+    int offset = 0;
+    for (;;) {
+        const int start = cont.indexOf(atChar, offset);
+        if (start < 0)
+            break;
+        const int end = cont.indexOf(atChar, start + 1);
+        Q_ASSERT(end);
+        const QString keyword = cont.mid(start + 1, end - start - 1);
+        const QString replacement = substMap.value(keyword);
+        cont.replace(start, end - start + 1, replacement);
+        offset = start + replacement.length();
+    }
+    return cont;
+}
+
+QString PluginGenerator::cStringQuote(QString s)
+{
+    s.replace(QLatin1Char('\\'), QLatin1String("\\\\"));
+    s.replace(QLatin1Char('"'), QLatin1String("\\\""));
+    s.replace(QLatin1Char('\t'), QLatin1String("\\t"));
+    s.replace(QLatin1Char('\n'), QLatin1String("\\n"));
+    return s;
+}
+
+}
+}
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/plugingenerator.h b/src/plugins/qt4projectmanager/customwidgetwizard/plugingenerator.h
new file mode 100644
index 00000000000..5d89ca648b7
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/plugingenerator.h
@@ -0,0 +1,75 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#ifndef PLUGINGENERATOR_H
+#define PLUGINGENERATOR_H
+
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Core {
+    class GeneratedFile;
+}
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+struct PluginOptions;
+
+struct GenerationParameters {
+    QString path;
+    QString name;
+    QString license;
+};
+
+class PluginGenerator : public QObject
+{
+    Q_OBJECT
+
+public:
+    static QList<Core::GeneratedFile> generatePlugin(const GenerationParameters& p,
+                                                     const PluginOptions &options,
+                                                     QString *errorMessage);
+
+private:
+    typedef QMap<QString,QString> SubstitutionMap;
+    static QString processTemplate(const QString &tmpl, const SubstitutionMap &substMap, QString *errorMessage);
+    static QString cStringQuote(QString s);
+};
+
+}
+}
+
+#endif
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/pluginoptions.h b/src/plugins/qt4projectmanager/customwidgetwizard/pluginoptions.h
new file mode 100644
index 00000000000..69ed1e6b1a3
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/pluginoptions.h
@@ -0,0 +1,74 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+**
+**************************************************************************/
+
+#ifndef PLUGINOPTIONS_H
+#define PLUGINOPTIONS_H
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+struct PluginOptions {
+    QString pluginName;
+    QString resourceFile;
+    QString collectionClassName;
+    QString collectionHeaderFile;
+    QString collectionSourceFile;
+
+    struct WidgetOptions {
+        enum { LinkLibrary, IncludeProject } sourceType;
+        QString widgetLibrary;
+        QString widgetProjectFile;
+        QString widgetClassName;
+        QString widgetHeaderFile;
+        QString widgetSourceFile;
+        QString widgetBaseClassName;
+        QString pluginClassName;
+        QString pluginHeaderFile;
+        QString pluginSourceFile;
+        QString iconFile;
+        bool createSkeleton;
+
+        QString group;
+        QString toolTip;
+        QString whatsThis;
+        bool isContainer;
+
+        QString domXml;
+    };
+
+    QList<WidgetOptions> widgetOptions;
+};
+
+}
+}
+
+#endif
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/templates.qrc b/src/plugins/qt4projectmanager/customwidgetwizard/templates/templates.qrc
new file mode 100644
index 00000000000..804d271dae4
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/templates.qrc
@@ -0,0 +1,14 @@
+<RCC>
+    <qresource prefix="/" >
+        <file>tpl_widget.h</file>
+        <file>tpl_widget.cpp</file>
+        <file>tpl_widget_include.pri</file>
+        <file>tpl_widget_lib.pro</file>
+        <file>tpl_single.h</file>
+        <file>tpl_single.cpp</file>
+        <file>tpl_collection.h</file>
+        <file>tpl_collection.cpp</file>
+        <file>tpl_plugin.pro</file>
+        <file>tpl_resources.qrc</file>
+    </qresource>
+</RCC>
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_collection.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_collection.cpp
new file mode 100644
index 00000000000..7e64374bab7
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_collection.cpp
@@ -0,0 +1,14 @@
+@PLUGIN_INCLUDES@
+
+@COLLECTION_PLUGIN_CLASS@::@COLLECTION_PLUGIN_CLASS@(QObject *parent)
+        : QObject(parent)
+{
+@PLUGIN_ADDITIONS@
+}
+
+QList<QDesignerCustomWidgetInterface*> @COLLECTION_PLUGIN_CLASS@::customWidgets() const
+{
+    return m_widgets;
+}
+
+@COLLECTION_PLUGIN_EXPORT@
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_collection.h b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_collection.h
new file mode 100644
index 00000000000..7a080510036
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_collection.h
@@ -0,0 +1,21 @@
+#ifndef @COLLECTION_INCLUDE_GUARD@
+#define @COLLECTION_INCLUDE_GUARD@
+
+#include <QtDesigner/QtDesigner>
+#include <QtCore/qplugin.h>
+
+class @COLLECTION_PLUGIN_CLASS@ : public QObject, public QDesignerCustomWidgetCollectionInterface
+{
+    Q_OBJECT
+    Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
+
+public:
+    explicit @COLLECTION_PLUGIN_CLASS@(QObject *parent = 0);
+
+    virtual QList<QDesignerCustomWidgetInterface*> customWidgets() const;
+
+private:
+    QList<QDesignerCustomWidgetInterface*> m_widgets;
+};
+
+#endif
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_plugin.pro b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_plugin.pro
new file mode 100644
index 00000000000..885e37c5394
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_plugin.pro
@@ -0,0 +1,13 @@
+CONFIG      += designer plugin debug_and_release
+TARGET      = $$qtLibraryTarget(@PLUGIN_NAME@)
+TEMPLATE    = lib
+
+HEADERS     =@PLUGIN_HEADERS@
+SOURCES     =@PLUGIN_SOURCES@
+RESOURCES   = @PLUGIN_RESOURCES@
+LIBS        += -L. @WIDGET_LIBS@
+
+target.path = $$[QT_INSTALL_PLUGINS]/designer
+INSTALLS    += target
+
+@INCLUSIONS@
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_resources.qrc b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_resources.qrc
new file mode 100644
index 00000000000..14462a0642d
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_resources.qrc
@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/" >
+@ICON_FILES@
+    </qresource>
+</RCC>
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_single.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_single.cpp
new file mode 100644
index 00000000000..e88f719ace6
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_single.cpp
@@ -0,0 +1,71 @@
+#include "@WIDGET_HEADER@"
+#include "@PLUGIN_HEADER@"
+
+#include <QtCore/QtPlugin>
+
+@PLUGIN_CLASS@::@PLUGIN_CLASS@(QObject *parent)
+    : QObject(parent)
+{
+    m_initialized = false;
+}
+
+void @PLUGIN_CLASS@::initialize(QDesignerFormEditorInterface * /* core */)
+{
+    if (m_initialized)
+        return;
+
+    // Add extension registrations, etc. here
+
+    m_initialized = true;
+}
+
+bool @PLUGIN_CLASS@::isInitialized() const
+{
+    return m_initialized;
+}
+
+QWidget *@PLUGIN_CLASS@::createWidget(QWidget *parent)
+{
+    return new @WIDGET_CLASS@(parent);
+}
+
+QString @PLUGIN_CLASS@::name() const
+{
+    return QLatin1String("@WIDGET_CLASS@");
+}
+
+QString @PLUGIN_CLASS@::group() const
+{
+    return QLatin1String("@WIDGET_GROUP@");
+}
+
+QIcon @PLUGIN_CLASS@::icon() const
+{
+    return QIcon(@WIDGET_ICON@);
+}
+
+QString @PLUGIN_CLASS@::toolTip() const
+{
+    return QLatin1String("@WIDGET_TOOLTIP@");
+}
+
+QString @PLUGIN_CLASS@::whatsThis() const
+{
+    return QLatin1String("@WIDGET_WHATSTHIS@");
+}
+
+bool @PLUGIN_CLASS@::isContainer() const
+{
+    return @WIDGET_ISCONTAINER@;
+}
+
+QString @PLUGIN_CLASS@::domXml() const
+{
+    return QLatin1String("@WIDGET_DOMXML@");
+}
+
+QString @PLUGIN_CLASS@::includeFile() const
+{
+    return QLatin1String("@WIDGET_HEADER@");
+}
+@SINGLE_PLUGIN_EXPORT@
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_single.h b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_single.h
new file mode 100644
index 00000000000..45a2781e2f2
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_single.h
@@ -0,0 +1,30 @@
+#ifndef @SINGLE_INCLUDE_GUARD@
+#define @SINGLE_INCLUDE_GUARD@
+
+#include <QDesignerCustomWidgetInterface>
+
+class @PLUGIN_CLASS@ : public QObject, public QDesignerCustomWidgetInterface
+{
+    Q_OBJECT
+    Q_INTERFACES(QDesignerCustomWidgetInterface)
+
+public:
+    @PLUGIN_CLASS@(QObject *parent = 0);
+
+    bool isContainer() const;
+    bool isInitialized() const;
+    QIcon icon() const;
+    QString domXml() const;
+    QString group() const;
+    QString includeFile() const;
+    QString name() const;
+    QString toolTip() const;
+    QString whatsThis() const;
+    QWidget *createWidget(QWidget *parent);
+    void initialize(QDesignerFormEditorInterface *core);
+
+private:
+    bool m_initialized;
+};
+
+#endif
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget.cpp
new file mode 100644
index 00000000000..cb6ff4dd39a
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget.cpp
@@ -0,0 +1,6 @@
+#include "@WIDGET_HEADER@"
+
+@WIDGET_CLASS@::@WIDGET_CLASS@(QWidget *parent) :
+    @WIDGET_BASE_CLASS@(parent)
+{
+}
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget.h b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget.h
new file mode 100644
index 00000000000..d80b154a129
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget.h
@@ -0,0 +1,14 @@
+#ifndef @WIDGET_INCLUDE_GUARD@
+#define @WIDGET_INCLUDE_GUARD@
+
+#include <QtGui/@WIDGET_BASE_CLASS@>
+
+class @WIDGET_CLASS@ : public @WIDGET_BASE_CLASS@
+{
+    Q_OBJECT
+
+public:
+    @WIDGET_CLASS@(QWidget *parent = 0);
+};
+
+#endif
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget_include.pri b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget_include.pri
new file mode 100644
index 00000000000..4281b79a54b
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget_include.pri
@@ -0,0 +1,2 @@
+HEADERS +=@WIDGET_HEADERS@
+SOURCES +=@WIDGET_SOURCES@
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget_lib.pro b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget_lib.pro
new file mode 100644
index 00000000000..971cde33419
--- /dev/null
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/templates/tpl_widget_lib.pro
@@ -0,0 +1,4 @@
+TEMPLATE = lib
+HEADERS =@WIDGET_HEADERS@
+SOURCES =@WIDGET_SOURCES@
+TARGET = @WIDGET_LIBRARY@
diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.pro b/src/plugins/qt4projectmanager/qt4projectmanager.pro
index 3b2341749d7..6b691397ac3 100644
--- a/src/plugins/qt4projectmanager/qt4projectmanager.pro
+++ b/src/plugins/qt4projectmanager/qt4projectmanager.pro
@@ -85,6 +85,7 @@ RESOURCES += qt4projectmanager.qrc \
 
 include(../../shared/proparser/proparser.pri)
 include(qt-s60/qt-s60.pri)
+include(customwidgetwizard/customwidgetwizard.pri)
 
 DEFINES += QT_NO_CAST_TO_ASCII
 OTHER_FILES += Qt4ProjectManager.pluginspec
diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp
index cf97a51ff6c..d4e8b96e9d2 100644
--- a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp
+++ b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp
@@ -34,6 +34,7 @@
 #include "wizards/guiappwizard.h"
 #include "wizards/librarywizard.h"
 #include "wizards/emptyprojectwizard.h"
+#include "customwidgetwizard/customwidgetwizard.h"
 #include "profileeditorfactory.h"
 #include "qt4projectmanagerconstants.h"
 #include "qt4project.h"
@@ -129,6 +130,7 @@ bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString *
 
     LibraryWizard *libWizard = new LibraryWizard;
     addAutoReleasedObject(libWizard);
+    addAutoReleasedObject(new CustomWidgetWizard);
 
     addAutoReleasedObject(new QMakeStepFactory);
     addAutoReleasedObject(new MakeStepFactory);
-- 
GitLab