From 44ce228a6a5b397c80cffbc12bf54db8c9856e8b Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Tue, 13 Apr 2010 16:13:06 +0200
Subject: [PATCH] Polish the Qt Designer custom widget wizard

Start editing the class name when wizard page
is initialized. Show a disabled widget page
for the dummy widget item (least surprise).
Add +/- buttons. Refuse invalid class names
(by introducing an item model with setData()
validation. Code polishing, explicitness, etc.
Task-number: QTCREATORBUG-1123
---
 .../customwidgetwizard/classdefinition.cpp    |  91 +++++------
 .../customwidgetwizard/classdefinition.h      |   9 +-
 .../customwidgetwizard/classlist.cpp          | 145 ++++++++++++++----
 .../customwidgetwizard/classlist.h            |  30 ++--
 .../customwidgetpluginwizardpage.h            |   4 +-
 .../customwidgetwidgetswizardpage.cpp         |  49 ++++--
 .../customwidgetwidgetswizardpage.h           |   6 +-
 .../customwidgetwidgetswizardpage.ui          |  40 +++--
 8 files changed, 265 insertions(+), 109 deletions(-)

diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.cpp
index 19ffe40f2cd..968a5237179 100644
--- a/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.cpp
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.cpp
@@ -39,30 +39,35 @@ ClassDefinition::ClassDefinition(QWidget *parent) :
     QTabWidget(parent),
     m_domXmlChanged(false)
 {
-    setupUi(this);
-    iconPathChooser->setExpectedKind(Utils::PathChooser::File);
-    iconPathChooser->setPromptDialogTitle(tr("Select Icon"));
-    iconPathChooser->setPromptDialogFilter(tr("Icon files (*.png *.ico *.jpg *.xpm *.tif *.svg)"));
+    m_ui.setupUi(this);
+    m_ui.iconPathChooser->setExpectedKind(Utils::PathChooser::File);
+    m_ui.iconPathChooser->setPromptDialogTitle(tr("Select Icon"));
+    m_ui.iconPathChooser->setPromptDialogFilter(tr("Icon files (*.png *.ico *.jpg *.xpm *.tif *.svg)"));
+}
+
+void ClassDefinition::enableButtons()
+{
+    on_libraryRadio_toggled();
 }
 
 void ClassDefinition::on_libraryRadio_toggled()
 {
-    const bool enLib = libraryRadio->isChecked();
-    widgetLibraryLabel->setEnabled(enLib);
-    widgetLibraryEdit->setEnabled(enLib);
+    const bool enLib = m_ui.libraryRadio->isChecked();
+    m_ui.widgetLibraryLabel->setEnabled(enLib);
+    m_ui.widgetLibraryEdit->setEnabled(enLib);
 
-    const bool enSrc = skeletonCheck->isChecked();
-    widgetSourceLabel->setEnabled(enSrc);
-    widgetSourceEdit->setEnabled(enSrc);
-    widgetBaseClassLabel->setEnabled(enSrc);
-    widgetBaseClassEdit->setEnabled(enSrc);
+    const bool enSrc = m_ui.skeletonCheck->isChecked();
+    m_ui.widgetSourceLabel->setEnabled(enSrc);
+    m_ui.widgetSourceEdit->setEnabled(enSrc);
+    m_ui.widgetBaseClassLabel->setEnabled(enSrc);
+    m_ui.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")));
+    m_ui.widgetProjectLabel->setEnabled(enPrj);
+    m_ui.widgetProjectEdit->setEnabled(enPrj);
+    m_ui.widgetProjectEdit->setText(
+        QFileInfo(m_ui.widgetProjectEdit->text()).completeBaseName() +
+        (m_ui.libraryRadio->isChecked() ? QLatin1String(".pro") : QLatin1String(".pri")));
 }
 
 void ClassDefinition::on_skeletonCheck_toggled()
@@ -86,35 +91,35 @@ static inline QString xmlFromClassName(const QString &name)
 
 void ClassDefinition::setClassName(const QString &name)
 {
-    widgetLibraryEdit->setText(name.toLower());
-    widgetHeaderEdit->setText(m_fileNamingParameters.headerFileName(name));
-    pluginClassEdit->setText(name + QLatin1String("Plugin"));
+    m_ui.widgetLibraryEdit->setText(name.toLower());
+    m_ui.widgetHeaderEdit->setText(m_fileNamingParameters.headerFileName(name));
+    m_ui.pluginClassEdit->setText(name + QLatin1String("Plugin"));
     if (!m_domXmlChanged) {
-        domXmlEdit->setText(xmlFromClassName(name));
+        m_ui.domXmlEdit->setText(xmlFromClassName(name));
         m_domXmlChanged = false;
     }
 }
 
 void ClassDefinition::on_widgetLibraryEdit_textChanged()
 {
-    widgetProjectEdit->setText(
-        widgetLibraryEdit->text() +
-        (libraryRadio->isChecked() ? QLatin1String(".pro") : QLatin1String(".pri")));
+    m_ui.widgetProjectEdit->setText(
+        m_ui.widgetLibraryEdit->text() +
+        (m_ui.libraryRadio->isChecked() ? QLatin1String(".pro") : QLatin1String(".pri")));
 }
 
 void ClassDefinition::on_widgetHeaderEdit_textChanged()
 {
-    widgetSourceEdit->setText(m_fileNamingParameters.headerToSourceFileName(widgetHeaderEdit->text()));
+    m_ui.widgetSourceEdit->setText(m_fileNamingParameters.headerToSourceFileName(m_ui.widgetHeaderEdit->text()));
 }
 
 void ClassDefinition::on_pluginClassEdit_textChanged()
 {
-    pluginHeaderEdit->setText(m_fileNamingParameters.headerFileName(pluginClassEdit->text()));
+    m_ui.pluginHeaderEdit->setText(m_fileNamingParameters.headerFileName(m_ui.pluginClassEdit->text()));
 }
 
 void ClassDefinition::on_pluginHeaderEdit_textChanged()
 {
-    pluginSourceEdit->setText(m_fileNamingParameters.headerToSourceFileName(pluginHeaderEdit->text()));
+    m_ui.pluginSourceEdit->setText(m_fileNamingParameters.headerToSourceFileName(m_ui.pluginHeaderEdit->text()));
 }
 
 void ClassDefinition::on_domXmlEdit_textChanged()
@@ -125,26 +130,26 @@ void ClassDefinition::on_domXmlEdit_textChanged()
 PluginOptions::WidgetOptions ClassDefinition::widgetOptions(const QString &className) const
 {
     PluginOptions::WidgetOptions wo;
-    wo.createSkeleton = skeletonCheck->isChecked();
+    wo.createSkeleton = m_ui.skeletonCheck->isChecked();
     wo.sourceType =
-            libraryRadio->isChecked() ?
+            m_ui.libraryRadio->isChecked() ?
             PluginOptions::WidgetOptions::LinkLibrary :
             PluginOptions::WidgetOptions::IncludeProject;
-    wo.widgetLibrary = widgetLibraryEdit->text();
-    wo.widgetProjectFile = widgetProjectEdit->text();
+    wo.widgetLibrary = m_ui.widgetLibraryEdit->text();
+    wo.widgetProjectFile = m_ui.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();
+    wo.widgetHeaderFile = m_ui.widgetHeaderEdit->text();
+    wo.widgetSourceFile = m_ui.widgetSourceEdit->text();
+    wo.widgetBaseClassName = m_ui.widgetBaseClassEdit->text();
+    wo.pluginClassName = m_ui.pluginClassEdit->text();
+    wo.pluginHeaderFile = m_ui.pluginHeaderEdit->text();
+    wo.pluginSourceFile = m_ui.pluginSourceEdit->text();
+    wo.iconFile = m_ui.iconPathChooser->path();
+    wo.group = m_ui.groupEdit->text();
+    wo.toolTip = m_ui.tooltipEdit->text();
+    wo.whatsThis = m_ui.whatsthisEdit->toPlainText();
+    wo.isContainer = m_ui.containerCheck->isChecked();
+    wo.domXml = m_ui.domXmlEdit->toPlainText();
     return wo;
 }
 
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.h b/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.h
index 6b31c38c813..0cde494a9c8 100644
--- a/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.h
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/classdefinition.h
@@ -39,12 +39,12 @@
 namespace Qt4ProjectManager {
 namespace Internal {
 
-class ClassDefinition : public QTabWidget, private Ui::ClassDefinition
+class ClassDefinition : public QTabWidget
 {
     Q_OBJECT
 
 public:
-    ClassDefinition(QWidget *parent);
+    explicit ClassDefinition(QWidget *parent = 0);
     void setClassName(const QString &name);
 
     FileNamingParameters fileNamingParameters() const { return m_fileNamingParameters; }
@@ -52,7 +52,9 @@ public:
 
     PluginOptions::WidgetOptions widgetOptions(const QString &className) const;
 
-public Q_SLOTS:
+    void enableButtons();
+
+private Q_SLOTS:
     void on_libraryRadio_toggled();
     void on_skeletonCheck_toggled();
     void on_widgetLibraryEdit_textChanged();
@@ -62,6 +64,7 @@ public Q_SLOTS:
     void on_domXmlEdit_textChanged();
 
 private:
+    Ui::ClassDefinition m_ui;
     FileNamingParameters m_fileNamingParameters;
     bool m_domXmlChanged;
 };
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/classlist.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/classlist.cpp
index 99cd58d71de..bf1ebfb8b45 100644
--- a/src/plugins/qt4projectmanager/customwidgetwizard/classlist.cpp
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/classlist.cpp
@@ -29,59 +29,146 @@
 
 #include "classlist.h"
 
+#include <utils/qtcassert.h>
+
 #include <QtGui/QKeyEvent>
 #include <QtGui/QMessageBox>
+#include <QtGui/QStandardItemModel>
+#include <QtGui/QStandardItem>
+#include <QtGui/QLabel>
+#include <QtGui/QToolButton>
+
+#include <QtCore/QDebug>
+#include <QtCore/QRegExp>
 
 namespace Qt4ProjectManager {
 namespace Internal {
 
+// ClassModel: Validates the class name in setData() and
+// refuses placeholders and invalid characters.
+class ClassModel : public QStandardItemModel {
+public:
+    explicit ClassModel(QObject *parent = 0);
+    virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+    void appendPlaceHolder() { appendClass(m_newClassPlaceHolder); }
+
+    QModelIndex placeHolderIndex() const;
+    QString newClassPlaceHolder() const { return m_newClassPlaceHolder; }
+
+private:
+    void appendClass(const QString &);
+
+    const QRegExp m_validator;
+    const QString m_newClassPlaceHolder;
+};
+
+ClassModel::ClassModel(QObject *parent) :
+    QStandardItemModel(0, 1, parent),
+    m_validator(QLatin1String("^[a-zA-Z][a-zA-Z0-9_]*$")),
+    m_newClassPlaceHolder(ClassList::tr("<New class>"))
+{
+    QTC_ASSERT(m_validator.isValid(), return)
+    appendPlaceHolder();
+}
+
+void ClassModel::appendClass(const QString &c)
+{
+    QStandardItem *item = new QStandardItem(c);
+    item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsEditable);
+    appendRow(item);
+}
+
+bool ClassModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+    if (role == Qt::EditRole && !m_validator.exactMatch(value.toString()))
+        return false;
+    return QStandardItemModel::setData(index, value, role);
+}
+
+QModelIndex ClassModel::placeHolderIndex() const
+{
+    return index(rowCount() - 1, 0);
+}
+
+// --------------- ClassList
 ClassList::ClassList(QWidget *parent) :
-    QListWidget(parent)
+    QListView(parent),
+    m_model(new ClassModel)
 {
+    setModel(m_model);
     connect(itemDelegate(), SIGNAL(closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint)), SLOT(classEdited()));
-    insertNewItem();
+    connect(selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
+            this, SLOT(slotCurrentRowChanged(QModelIndex,QModelIndex)));
+}
+
+void ClassList::startEditingNewClassItem()
+{
+    // Start editing the 'new class' item.
+    setFocus();
+
+    const QModelIndex index = m_model->placeHolderIndex();
+    setCurrentIndex(index);
+    edit(index);
+}
+
+QString ClassList::className(int row) const
+{
+    return m_model->item(row, 0)->text();
 }
 
 void ClassList::classEdited()
 {
-    if (currentRow() == count() - 1) {
-        if (currentItem()->text() != tr("<New class>")) {
-            emit classAdded(currentItem()->text());
-            insertNewItem();
+    const QModelIndex index = currentIndex();
+    QTC_ASSERT(index.isValid(), return)
+
+    const QString name = className(index.row());
+    if (index == m_model->placeHolderIndex()) {
+        // Real name class entered.
+        if (name != m_model->newClassPlaceHolder()) {
+            emit classAdded(name);
+            m_model->appendPlaceHolder();
         }
     } else {
-        emit classRenamed(currentRow(), currentItem()->text());
+        emit classRenamed(index.row(), name);
     }
 }
 
-void ClassList::insertNewItem()
+void ClassList::removeCurrentClass()
 {
-    QListWidgetItem *itm = new QListWidgetItem(tr("<New class>"), this);
-    itm->setFlags(Qt::ItemIsEnabled|Qt::ItemIsEditable);
+    const QModelIndex index = currentIndex();
+    if (!index.isValid() || index == m_model->placeHolderIndex())
+        return;
+    if (QMessageBox::question(this,
+                              tr("Confirm Delete"),
+                              tr("Delete class %1 from list?").arg(className(index.row())),
+                              QMessageBox::Ok|QMessageBox::Cancel) != QMessageBox::Ok)
+        return;
+    // Delete row and set current on same item.
+    m_model->removeRows(index.row(), 1);
+    emit classDeleted(index.row());
+    setCurrentIndex(m_model->indexFromItem(m_model->item(index.row(), 0)));
 }
 
 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);
+    switch (event->key()) {
+    case Qt::Key_Delete:
+        removeCurrentClass();
+        break;
+    case Qt::Key_Insert:
+        startEditingNewClassItem();
+        break;
+    default:
+        QListView::keyPressEvent(event);
+        break;
     }
 }
 
+void ClassList::slotCurrentRowChanged(const QModelIndex &current, const QModelIndex &)
+{
+    emit currentRowChanged(current.row());
 }
-}
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/classlist.h b/src/plugins/qt4projectmanager/customwidgetwizard/classlist.h
index 3fa9ecb4f90..631d07d6d38 100644
--- a/src/plugins/qt4projectmanager/customwidgetwizard/classlist.h
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/classlist.h
@@ -30,34 +30,46 @@
 #ifndef CLASSLIST_H
 #define CLASSLIST_H
 
-#include <QtGui/QListWidget>
+#include <QtGui/QListView>
+
+QT_FORWARD_DECLARE_CLASS(QModelIndex)
 
 namespace Qt4ProjectManager {
 namespace Internal {
+class ClassModel;
 
-class ClassList : public QListWidget
+// Class list for new Custom widget classes. Provides
+// editable '<new class>' field and Delete/Insert key handling.
+class ClassList : public QListView
 {
     Q_OBJECT
 
 public:
-    ClassList(QWidget *parent);
+    explicit ClassList(QWidget *parent = 0);
 
-public slots:
-    void classEdited();
+    QString className(int row) const;
 
 signals:
     void classAdded(const QString &name);
     void classRenamed(int index, const QString &newName);
     void classDeleted(int index);
+    void currentRowChanged(int);
+
+public slots:
+    void removeCurrentClass();
+    void startEditingNewClassItem();
+
+private slots:
+    void classEdited();
+    void slotCurrentRowChanged(const QModelIndex &,const QModelIndex &);
 
 protected:
     void keyPressEvent(QKeyEvent *event);
 
 private:
-    void insertNewItem();
+    ClassModel *m_model;
 };
 
-}
-}
-
+} // namespace Internal
+} // namespace Qt4ProjectManager
 #endif
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.h b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.h
index 59c2300f347..6e06484ba2f 100644
--- a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.h
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetpluginwizardpage.h
@@ -48,8 +48,8 @@ namespace Ui {
 class CustomWidgetPluginWizardPage : public QWizardPage {
     Q_OBJECT
 public:
-    CustomWidgetPluginWizardPage(QWidget *parent = 0);
-    ~CustomWidgetPluginWizardPage();
+    explicit CustomWidgetPluginWizardPage(QWidget *parent = 0);
+    virtual ~CustomWidgetPluginWizardPage();
 
     void init(const CustomWidgetWidgetsWizardPage *widgetsPage);
 
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp
index 56ee0eb0489..39322a8e3e1 100644
--- a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.cpp
@@ -32,9 +32,13 @@
 #include "plugingenerator.h"
 #include "classdefinition.h"
 
+#include <coreplugin/coreconstants.h>
+
 #include <QtCore/QFileInfo>
+#include <QtCore/QTimer>
 
 #include <QtGui/QStackedLayout>
+#include <QtGui/QIcon>
 
 namespace Qt4ProjectManager {
 namespace Internal {
@@ -42,13 +46,25 @@ namespace Internal {
 CustomWidgetWidgetsWizardPage::CustomWidgetWidgetsWizardPage(QWidget *parent) :
     QWizardPage(parent),
     m_ui(new Ui::CustomWidgetWidgetsWizardPage),
+    m_tabStackLayout(new QStackedLayout),
     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)));
+    m_ui->tabStackWidget->setLayout(m_tabStackLayout);
+    m_ui->addButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_PLUS)));
+    connect(m_ui->addButton, SIGNAL(clicked()), m_ui->classList, SLOT(startEditingNewClassItem()));
+    m_ui->deleteButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_MINUS)));
+    connect(m_ui->deleteButton, SIGNAL(clicked()), m_ui->classList, SLOT(removeCurrentClass()));
+    m_ui->deleteButton->setEnabled(false);
+
+    // Disabled dummy for <new class> column>.
+    ClassDefinition *dummy = new ClassDefinition;
+    dummy->setFileNamingParameters(m_fileNamingParameters);
+    dummy->setEnabled(false);
+    m_tabStackLayout->addWidget(dummy);
+
+    connect(m_ui->classList, SIGNAL(currentRowChanged(int)),
+            this, SLOT(slotCurrentRowChanged(int)));
 }
 
 CustomWidgetWidgetsWizardPage::~CustomWidgetWidgetsWizardPage()
@@ -61,15 +77,28 @@ bool CustomWidgetWidgetsWizardPage::isComplete() const
     return m_complete;
 }
 
+void CustomWidgetWidgetsWizardPage::initializePage()
+{
+    // Takes effect only if visible.
+    QTimer::singleShot(0, m_ui->classList, SLOT(startEditingNewClassItem()));
+}
+
+void CustomWidgetWidgetsWizardPage::slotCurrentRowChanged(int row)
+{
+    const bool onDummyItem = row == m_tabStackLayout->count() - 1;
+    m_ui->deleteButton->setEnabled(!onDummyItem);
+    m_tabStackLayout->setCurrentIndex(row);
+}
+
 void CustomWidgetWidgetsWizardPage::on_classList_classAdded(const QString &name)
 {
-    ClassDefinition *cdef = new ClassDefinition(m_ui->tabStackWidget);
+    ClassDefinition *cdef = new ClassDefinition;
     cdef->setFileNamingParameters(m_fileNamingParameters);
     const int index = m_uiClassDefs.count();
-    m_tabStack->insertWidget(index, cdef);
-    m_tabStack->setCurrentIndex(index);
+    m_tabStackLayout->insertWidget(index, cdef);
+    m_tabStackLayout->setCurrentIndex(index);
     m_uiClassDefs.append(cdef);
-    cdef->on_libraryRadio_toggled();
+    cdef->enableButtons();
     on_classList_classRenamed(index, name);
     // First class or collection class, re-check.
     slotCheckCompleteness();
@@ -77,7 +106,7 @@ void CustomWidgetWidgetsWizardPage::on_classList_classAdded(const QString &name)
 
 void CustomWidgetWidgetsWizardPage::on_classList_classDeleted(int index)
 {
-    delete m_tabStack->widget(index);
+    delete m_tabStackLayout->widget(index);
     m_uiClassDefs.removeAt(index);
     if (m_uiClassDefs.empty())
         slotCheckCompleteness();
@@ -90,7 +119,7 @@ void CustomWidgetWidgetsWizardPage::on_classList_classRenamed(int index, const Q
 
 QString CustomWidgetWidgetsWizardPage::classNameAt(int i) const
 {
-    return m_ui->classList->item(i)->text();
+    return m_ui->classList->className(i);
 }
 
 QList<PluginOptions::WidgetOptions> CustomWidgetWidgetsWizardPage::widgetOptions() const
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.h b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.h
index 85c4444c0a1..12520bad6d7 100644
--- a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.h
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.h
@@ -68,19 +68,21 @@ public:
     int classCount() const { return m_uiClassDefs.size(); }
     QString classNameAt(int i) const;
 
+    virtual void initializePage();
+
 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();
+    void slotCurrentRowChanged(int);
 
 private:
     void updatePluginTab();
 
     Ui::CustomWidgetWidgetsWizardPage *m_ui;
     QList<ClassDefinition *> m_uiClassDefs;
-    QStackedLayout *m_tabStack;
-    QWidget *m_dummyTab;
+    QStackedLayout *m_tabStackLayout;
     FileNamingParameters m_fileNamingParameters;
     bool m_complete;
 };
diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.ui b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.ui
index adf2b942f1c..7f48f5e36a4 100644
--- a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.ui
+++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwidgetswizardpage.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>668</width>
-    <height>454</height>
+    <height>475</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -17,16 +17,6 @@
    <string>Custom Widget List</string>
   </property>
   <layout class="QGridLayout" name="gridLayout">
-   <item row="2" 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="2" column="1" rowspan="2">
     <widget class="QWidget" name="tabStackWidget" native="true">
      <property name="minimumSize">
@@ -70,6 +60,34 @@
      </property>
     </spacer>
    </item>
+   <item row="2" column="0">
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>Widget &amp;Classes:</string>
+       </property>
+       <property name="buddy">
+        <cstring>classList</cstring>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="addButton">
+       <property name="text">
+        <string>...</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="deleteButton">
+       <property name="text">
+        <string>...</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
   </layout>
  </widget>
  <customwidgets>
-- 
GitLab