diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro
index e822521e6adb77d6c35cbb533481852a5c9128aa..8d43fb816b554adc2151b19dbe164fcc7d0bbefc 100644
--- a/src/plugins/coreplugin/coreplugin.pro
+++ b/src/plugins/coreplugin/coreplugin.pro
@@ -17,6 +17,7 @@ SOURCES += corejsextensions.cpp \
     fancytabwidget.cpp \
     generalsettings.cpp \
     themesettings.cpp \
+    themesettingswidget.cpp \
     id.cpp \
     icontext.cpp \
     jsexpander.cpp \
@@ -121,6 +122,7 @@ HEADERS += corejsextensions.h \
     fancytabwidget.h \
     generalsettings.h \
     themesettings.h \
+    themesettingswidget.h \
     id.h \
     jsexpander.h \
     messagemanager.h \
diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs
index 426377e95e2dad13d86cf651eceb26d34926684c..f056dd100a6f48da77ebb7a1d42165a06a7f183c 100644
--- a/src/plugins/coreplugin/coreplugin.qbs
+++ b/src/plugins/coreplugin/coreplugin.qbs
@@ -98,9 +98,8 @@ QtcPlugin {
             "styleanimator.cpp", "styleanimator.h",
             "tabpositionindicator.cpp", "tabpositionindicator.h",
             "textdocument.cpp", "textdocument.h",
-            "themesettings.cpp",
-            "themesettings.h",
-            "themesettings.ui",
+            "themesettings.cpp", "themesettings.h", "themesettings.ui",
+            "themesettingswidget.cpp", "themesettingswidget.h",
             "toolsettings.cpp", "toolsettings.h",
             "variablechooser.cpp", "variablechooser.h",
             "vcsmanager.cpp", "vcsmanager.h",
diff --git a/src/plugins/coreplugin/themesettings.cpp b/src/plugins/coreplugin/themesettings.cpp
index 1332e59d86168aa291414308ee6fc35260911bca..1e2a768b2dada4ccbe354e5147406f3be1f18c5f 100644
--- a/src/plugins/coreplugin/themesettings.cpp
+++ b/src/plugins/coreplugin/themesettings.cpp
@@ -29,436 +29,44 @@
 ****************************************************************************/
 
 #include "themesettings.h"
+#include "themesettingswidget.h"
 #include "coreconstants.h"
-#include "icore.h"
-#include "editormanager/editormanager_p.h"
-#include "themeeditor/themesettingstablemodel.h"
-
-#include <utils/qtcassert.h>
-
-#include <QDebug>
-#include <QDir>
-#include <QInputDialog>
-#include <QMessageBox>
-#include <QSettings>
-
-#include "ui_themesettings.h"
-
-using namespace Utils;
 
 namespace Core {
 namespace Internal {
 
-const char themeNameKey[] = "ThemeName";
-
-static QString customThemesPath()
-{
-    QString path = Core::ICore::userResourcePath();
-    path.append(QLatin1String("/themes/"));
-    return path;
-}
-
-static QString createThemeFileName(const QString &pattern)
-{
-    const QString stylesPath = customThemesPath();
-    QString baseFileName = stylesPath;
-    baseFileName += pattern;
-
-    // Find an available file name
-    int i = 1;
-    QString fileName;
-    do {
-        fileName = baseFileName.arg((i == 1) ? QString() : QString::number(i));
-        ++i;
-    } while (QFile::exists(fileName));
-
-    // Create the base directory when it doesn't exist
-    if (!QFile::exists(stylesPath) && !QDir().mkpath(stylesPath)) {
-        qWarning() << "Failed to create theme directory:" << stylesPath;
-        return QString();
-    }
-    return fileName;
-}
-
-
-struct ThemeEntry
-{
-    ThemeEntry() {}
-    ThemeEntry(const QString &fileName, bool readOnly):
-        m_fileName(fileName),
-        m_readOnly(readOnly)
-    { }
-
-    QString fileName() const { return m_fileName; }
-    QString name() const;
-    bool readOnly() const { return m_readOnly; }
-
-private:
-    QString m_fileName;
-    bool m_readOnly;
-};
-
-QString ThemeEntry::name() const
-{
-    QSettings settings(m_fileName, QSettings::IniFormat);
-    QString n = settings.value(QLatin1String(themeNameKey), QCoreApplication::tr("unnamed")).toString();
-    return m_readOnly ? QCoreApplication::tr("%1 (built-in)").arg(n) : n;
-}
-
-
-class ThemeListModel : public QAbstractListModel
-{
-public:
-    ThemeListModel(QObject *parent = 0):
-        QAbstractListModel(parent)
-    {
-    }
-
-    int rowCount(const QModelIndex &parent) const
-    {
-        return parent.isValid() ? 0 : m_themes.size();
-    }
-
-    QVariant data(const QModelIndex &index, int role) const
-    {
-        if (role == Qt::DisplayRole)
-            return m_themes.at(index.row()).name();
-        return QVariant();
-    }
-
-    void removeTheme(int index)
-    {
-        beginRemoveRows(QModelIndex(), index, index);
-        m_themes.removeAt(index);
-        endRemoveRows();
-    }
-
-    void setThemes(const QList<ThemeEntry> &themes)
-    {
-        beginResetModel();
-        m_themes = themes;
-        endResetModel();
-    }
-
-    const ThemeEntry &themeAt(int index) const
-    {
-        return m_themes.at(index);
-    }
-
-private:
-    QList<ThemeEntry> m_themes;
-};
-
-
-class ThemeSettingsPrivate
-{
-public:
-    ThemeSettingsPrivate();
-    ~ThemeSettingsPrivate();
-
-public:
-    ThemeListModel *m_themeListModel;
-    bool m_refreshingThemeList;
-    Ui::ThemeSettings *m_ui;
-    QPointer<QWidget> m_widget;
-    ThemeEntry m_currentTheme;
-};
-
-ThemeSettingsPrivate::ThemeSettingsPrivate()
-    : m_themeListModel(new ThemeListModel)
-    , m_refreshingThemeList(false)
-    , m_ui(0)
-{
-    m_currentTheme = ThemeEntry(creatorTheme()->fileName(), true);
-}
-
-ThemeSettingsPrivate::~ThemeSettingsPrivate()
-{
-    delete m_themeListModel;
-}
-
-ThemeSettings::ThemeSettings()
+ThemeSettings::ThemeSettings() :
+    m_widget(0)
 {
     setId(Core::Constants::SETTINGS_ID_ENVIRONMENT);
     setDisplayName(tr("Theme"));
     setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
     setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::SETTINGS_TR_CATEGORY_CORE));
     setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON));
-
-    d = new ThemeSettingsPrivate();
 }
 
 ThemeSettings::~ThemeSettings()
 {
-    delete d;
-}
-
-void ThemeSettings::refreshThemeList()
-{
-    QList<ThemeEntry> themes;
-
-    QString resourcePath = Core::ICore::resourcePath();
-    QDir themeDir(resourcePath + QLatin1String("/themes"));
-    themeDir.setNameFilters(QStringList() << QLatin1String("*.creatortheme"));
-    themeDir.setFilter(QDir::Files);
-
-    int selected = 0;
-
-    QStringList themeList = themeDir.entryList();
-    QString defaultTheme = QFileInfo(defaultThemeFileName()).fileName();
-    if (themeList.removeAll(defaultTheme))
-        themeList.prepend(defaultTheme);
-    foreach (const QString &file, themeList) {
-        const QString fileName = themeDir.absoluteFilePath(file);
-        if (d->m_currentTheme.fileName() == fileName)
-            selected = themes.size();
-        themes.append(ThemeEntry(fileName, true));
-    }
-
-    if (themes.isEmpty())
-        qWarning() << "Warning: no themes found in path:" << themeDir.path();
-
-    themeDir.setPath(customThemesPath());
-    foreach (const QString &file, themeDir.entryList()) {
-        const QString fileName = themeDir.absoluteFilePath(file);
-        if (d->m_currentTheme.fileName() == fileName)
-            selected = themes.size();
-        themes.append(ThemeEntry(fileName, false));
-    }
-
-    d->m_currentTheme = themes[selected];
-
-    d->m_refreshingThemeList = true;
-    d->m_themeListModel->setThemes(themes);
-    d->m_ui->themeComboBox->setCurrentIndex(selected);
-    d->m_refreshingThemeList = false;
-}
-
-QString ThemeSettings::defaultThemeFileName(const QString &fileName)
-{
-    QString defaultScheme = Core::ICore::resourcePath();
-    defaultScheme += QLatin1String("/themes/");
-
-    if (!fileName.isEmpty() && QFile::exists(defaultScheme + fileName))
-        defaultScheme += fileName;
-    else
-        defaultScheme += QLatin1String("default.creatortheme");
-
-    return defaultScheme;
-}
-
-void ThemeSettings::themeSelected(int index)
-{
-    bool readOnly = true;
-    if (index != -1) {
-        // Check whether we're switching away from a changed theme
-        if (!d->m_refreshingThemeList)
-            maybeSaveTheme();
-
-        const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
-        readOnly = entry.readOnly();
-        d->m_currentTheme = entry;
-
-        QSettings settings(entry.fileName(), QSettings::IniFormat);
-        Theme theme;
-        theme.readSettings(settings);
-        d->m_ui->editor->initFrom(&theme);
-    }
-    d->m_ui->copyButton->setEnabled(index != -1);
-    d->m_ui->deleteButton->setEnabled(!readOnly);
-    d->m_ui->renameButton->setEnabled(!readOnly);
-    d->m_ui->editor->setReadOnly(readOnly);
+    delete m_widget;
 }
 
 QWidget *ThemeSettings::widget()
 {
-    if (!d->m_widget) {
-        d->m_widget = new QWidget;
-        d->m_ui = new Ui::ThemeSettings();
-        d->m_ui->setupUi(d->m_widget);
-        d->m_ui->themeComboBox->setModel(d->m_themeListModel);
-
-        connect(d->m_ui->themeComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
-               this, &ThemeSettings::themeSelected);
-        connect(d->m_ui->copyButton, &QAbstractButton::clicked, this, &ThemeSettings::copyTheme);
-        connect(d->m_ui->renameButton, &QAbstractButton::clicked, this, &ThemeSettings::renameTheme);
-        connect(d->m_ui->deleteButton, &QAbstractButton::clicked, this, &ThemeSettings::confirmDeleteTheme);
-
-        refreshThemeList();
-    }
-    return d->m_widget;
-}
-
-void ThemeSettings::confirmDeleteTheme()
-{
-    const int index = d->m_ui->themeComboBox->currentIndex();
-    if (index == -1)
-        return;
-
-    const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
-    if (entry.readOnly())
-        return;
-
-    QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning,
-                                              tr("Delete Theme"),
-                                              tr("Are you sure you want to delete the theme '%1' permanently?").arg(entry.name()),
-                                              QMessageBox::Discard | QMessageBox::Cancel,
-                                              d->m_ui->deleteButton->window());
-
-    // Change the text and role of the discard button
-    QPushButton *deleteButton = static_cast<QPushButton*>(messageBox->button(QMessageBox::Discard));
-    deleteButton->setText(tr("Delete"));
-    messageBox->addButton(deleteButton, QMessageBox::AcceptRole);
-    messageBox->setDefaultButton(deleteButton);
-
-    connect(deleteButton, &QAbstractButton::clicked, messageBox, &QDialog::accept);
-    connect(messageBox, &QDialog::accepted, this, &ThemeSettings::deleteTheme);
-    messageBox->setAttribute(Qt::WA_DeleteOnClose);
-    messageBox->open();
-}
-
-void ThemeSettings::deleteTheme()
-{
-    const int index = d->m_ui->themeComboBox->currentIndex();
-    QTC_ASSERT(index != -1, return);
-
-    const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
-    QTC_ASSERT(!entry.readOnly(), return);
-
-    if (QFile::remove(entry.fileName()))
-        d->m_themeListModel->removeTheme(index);
-}
-
-void ThemeSettings::copyTheme()
-{
-    QInputDialog *dialog = new QInputDialog(d->m_ui->copyButton->window());
-    dialog->setAttribute(Qt::WA_DeleteOnClose);
-    dialog->setInputMode(QInputDialog::TextInput);
-    dialog->setWindowTitle(tr("Copy Theme"));
-    dialog->setLabelText(tr("Theme name:"));
-
-    //TODO
-    //dialog->setTextValue(tr("%1 (copy)").arg(d_ptr->m_value.colorScheme().displayName()));
-
-    connect(dialog, &QInputDialog::textValueSelected, this, &ThemeSettings::copyThemeByName);
-    dialog->open();
-}
-
-void ThemeSettings::maybeSaveTheme()
-{
-    if (!d->m_ui->editor->model()->hasChanges())
-        return;
-
-    QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning,
-                                              tr("Theme Changed"),
-                                              tr("The theme \"%1\" was modified, do you want to save the changes?")
-                                                  .arg(d->m_currentTheme.name()),
-                                              QMessageBox::Discard | QMessageBox::Save,
-                                              d->m_ui->themeComboBox->window());
-
-    // Change the text of the discard button
-    QPushButton *discardButton = static_cast<QPushButton*>(messageBox->button(QMessageBox::Discard));
-    discardButton->setText(tr("Discard"));
-    messageBox->addButton(discardButton, QMessageBox::DestructiveRole);
-    messageBox->setDefaultButton(QMessageBox::Save);
-
-    if (messageBox->exec() == QMessageBox::Save) {
-        Theme newTheme;
-        d->m_ui->editor->model()->toTheme(&newTheme);
-        newTheme.writeSettings(d->m_currentTheme.fileName());
-    }
-}
-
-void ThemeSettings::renameTheme()
-{
-    int index = d->m_ui->themeComboBox->currentIndex();
-    if (index == -1)
-        return;
-    const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
-
-    maybeSaveTheme();
-
-    QInputDialog *dialog = new QInputDialog(d->m_ui->renameButton->window());
-    dialog->setInputMode(QInputDialog::TextInput);
-    dialog->setWindowTitle(tr("Rename Theme"));
-    dialog->setLabelText(tr("Theme name:"));
-    dialog->setTextValue(d->m_ui->editor->model()->m_name);
-    int ret = dialog->exec();
-    QString newName = dialog->textValue();
-    delete dialog;
-
-    if (ret != QDialog::Accepted || newName.isEmpty())
-        return;
-
-    // overwrite file with new name
-    Theme newTheme;
-    d->m_ui->editor->model()->toTheme(&newTheme);
-    newTheme.setName(newName);
-    newTheme.writeSettings(entry.fileName());
-
-    refreshThemeList();
-}
-
-void ThemeSettings::copyThemeByName(const QString &name)
-{
-    int index = d->m_ui->themeComboBox->currentIndex();
-    if (index == -1)
-        return;
-
-    const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
-
-    QString baseFileName = QFileInfo(entry.fileName()).completeBaseName();
-    baseFileName += QLatin1String("_copy%1.creatortheme");
-    QString fileName = createThemeFileName(baseFileName);
-
-    if (fileName.isEmpty())
-        return;
-
-    // Ask about saving any existing modifactions
-    maybeSaveTheme();
-
-    Theme newTheme;
-    d->m_ui->editor->model()->toTheme(&newTheme);
-    newTheme.setName(name);
-    newTheme.writeSettings(fileName);
-
-    d->m_currentTheme = ThemeEntry(fileName, true);
-
-    refreshThemeList();
+    if (!m_widget)
+        m_widget = new ThemeSettingsWidget;
+    return m_widget;
 }
 
 void ThemeSettings::apply()
 {
-    if (!d->m_ui) // wasn't shown, can't be changed
-        return;
-
-    {
-        d->m_ui->editor->model()->toTheme(creatorTheme());
-        if (creatorTheme()->flag(Theme::ApplyThemePaletteGlobally))
-            QApplication::setPalette(creatorTheme()->palette(QApplication::palette()));
-        foreach (QWidget *w, QApplication::topLevelWidgets())
-            w->update();
-    }
-
-    // save definition of theme
-    if (!d->m_currentTheme.readOnly()) {
-        Theme newTheme;
-        d->m_ui->editor->model()->toTheme(&newTheme);
-        newTheme.writeSettings(d->m_currentTheme.fileName());
-    }
-
-    // save filename of selected theme in global config
-    QSettings *settings = Core::ICore::settings();
-    settings->setValue(QLatin1String(Core::Constants::SETTINGS_THEME), d->m_currentTheme.fileName());
+    if (m_widget)
+        m_widget->apply();
 }
 
 void ThemeSettings::finish()
 {
-    delete d->m_widget;
-    if (!d->m_ui) // page was never shown
-        return
-    delete d->m_ui;
-    d->m_ui = 0;
+    delete m_widget;
+    m_widget = 0;
 }
 
 } // namespace Internal
diff --git a/src/plugins/coreplugin/themesettings.h b/src/plugins/coreplugin/themesettings.h
index a204acd7a149377564214a5e6b450e0490125666..d5027711f71dab3c72d8de0f300ab7107be3a215 100644
--- a/src/plugins/coreplugin/themesettings.h
+++ b/src/plugins/coreplugin/themesettings.h
@@ -36,7 +36,7 @@
 namespace Core {
 namespace Internal {
 
-class ThemeSettingsPrivate;
+class ThemeSettingsWidget;
 
 class ThemeSettings : public IOptionsPage
 {
@@ -50,20 +50,7 @@ public:
     void apply();
     void finish();
 
-    static QString defaultThemeFileName(const QString &fileName = QString());
-
-private slots:
-    void themeSelected(int index);
-    void copyTheme();
-    void renameTheme();
-    void copyThemeByName(const QString &);
-    void confirmDeleteTheme();
-    void deleteTheme();
-    void maybeSaveTheme();
-
-private:
-    void refreshThemeList();
-    ThemeSettingsPrivate *d;
+    ThemeSettingsWidget *m_widget;
 };
 
 } // namespace Internal
diff --git a/src/plugins/coreplugin/themesettingswidget.cpp b/src/plugins/coreplugin/themesettingswidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ef6ef1a6f3894ecb8d73425a81a44b70ad3c9d9
--- /dev/null
+++ b/src/plugins/coreplugin/themesettingswidget.cpp
@@ -0,0 +1,438 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Thorben Kroeger <thorbenkroeger@gmail.com>.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://www.qt.io/licensing.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "themesettingswidget.h"
+#include "coreconstants.h"
+#include "icore.h"
+#include "themeeditor/themesettingstablemodel.h"
+
+#include <utils/theme/theme.h>
+#include <utils/qtcassert.h>
+
+#include <QDir>
+#include <QInputDialog>
+#include <QMessageBox>
+#include <QSettings>
+
+#include "ui_themesettings.h"
+
+using namespace Utils;
+
+namespace Core {
+namespace Internal {
+
+const char themeNameKey[] = "ThemeName";
+
+static QString customThemesPath()
+{
+    QString path = Core::ICore::userResourcePath();
+    path.append(QLatin1String("/themes/"));
+    return path;
+}
+
+static QString createThemeFileName(const QString &pattern)
+{
+    const QString stylesPath = customThemesPath();
+    QString baseFileName = stylesPath;
+    baseFileName += pattern;
+
+    // Find an available file name
+    int i = 1;
+    QString fileName;
+    do {
+        fileName = baseFileName.arg((i == 1) ? QString() : QString::number(i));
+        ++i;
+    } while (QFile::exists(fileName));
+
+    // Create the base directory when it doesn't exist
+    if (!QFile::exists(stylesPath) && !QDir().mkpath(stylesPath)) {
+        qWarning() << "Failed to create theme directory:" << stylesPath;
+        return QString();
+    }
+    return fileName;
+}
+
+
+struct ThemeEntry
+{
+    ThemeEntry() {}
+    ThemeEntry(const QString &fileName, bool readOnly):
+        m_fileName(fileName),
+        m_readOnly(readOnly)
+    { }
+
+    QString fileName() const { return m_fileName; }
+    QString name() const;
+    bool readOnly() const { return m_readOnly; }
+
+private:
+    QString m_fileName;
+    bool m_readOnly;
+};
+
+QString ThemeEntry::name() const
+{
+    QSettings settings(m_fileName, QSettings::IniFormat);
+    QString n = settings.value(QLatin1String(themeNameKey), QCoreApplication::tr("unnamed")).toString();
+    return m_readOnly ? QCoreApplication::tr("%1 (built-in)").arg(n) : n;
+}
+
+
+class ThemeListModel : public QAbstractListModel
+{
+public:
+    ThemeListModel(QObject *parent = 0):
+        QAbstractListModel(parent)
+    {
+    }
+
+    int rowCount(const QModelIndex &parent) const
+    {
+        return parent.isValid() ? 0 : m_themes.size();
+    }
+
+    QVariant data(const QModelIndex &index, int role) const
+    {
+        if (role == Qt::DisplayRole)
+            return m_themes.at(index.row()).name();
+        return QVariant();
+    }
+
+    void removeTheme(int index)
+    {
+        beginRemoveRows(QModelIndex(), index, index);
+        m_themes.removeAt(index);
+        endRemoveRows();
+    }
+
+    void setThemes(const QList<ThemeEntry> &themes)
+    {
+        beginResetModel();
+        m_themes = themes;
+        endResetModel();
+    }
+
+    const ThemeEntry &themeAt(int index) const
+    {
+        return m_themes.at(index);
+    }
+
+private:
+    QList<ThemeEntry> m_themes;
+};
+
+
+class ThemeSettingsPrivate
+{
+public:
+    ThemeSettingsPrivate(QWidget *widget);
+    ~ThemeSettingsPrivate();
+
+public:
+    ThemeListModel *m_themeListModel;
+    bool m_refreshingThemeList;
+    Ui::ThemeSettings *m_ui;
+    ThemeEntry m_currentTheme;
+};
+
+ThemeSettingsPrivate::ThemeSettingsPrivate(QWidget *widget)
+    : m_themeListModel(new ThemeListModel)
+    , m_refreshingThemeList(false)
+    , m_ui(new Ui::ThemeSettings)
+{
+    m_currentTheme = ThemeEntry(creatorTheme()->fileName(), true);
+    m_ui->setupUi(widget);
+    m_ui->themeComboBox->setModel(m_themeListModel);
+}
+
+ThemeSettingsPrivate::~ThemeSettingsPrivate()
+{
+    delete m_themeListModel;
+    delete m_ui;
+}
+
+ThemeSettingsWidget::ThemeSettingsWidget(QWidget *parent) :
+    QWidget(parent)
+{
+    d = new ThemeSettingsPrivate(this);
+
+    connect(d->m_ui->themeComboBox, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+           this, &ThemeSettingsWidget::themeSelected);
+    connect(d->m_ui->copyButton, &QAbstractButton::clicked, this, &ThemeSettingsWidget::copyTheme);
+    connect(d->m_ui->renameButton, &QAbstractButton::clicked, this, &ThemeSettingsWidget::renameTheme);
+    connect(d->m_ui->deleteButton, &QAbstractButton::clicked, this, &ThemeSettingsWidget::confirmDeleteTheme);
+
+    refreshThemeList();
+}
+
+ThemeSettingsWidget::~ThemeSettingsWidget()
+{
+    delete d;
+}
+
+void ThemeSettingsWidget::refreshThemeList()
+{
+    QList<ThemeEntry> themes;
+
+    QString resourcePath = Core::ICore::resourcePath();
+    QDir themeDir(resourcePath + QLatin1String("/themes"));
+    themeDir.setNameFilters(QStringList() << QLatin1String("*.creatortheme"));
+    themeDir.setFilter(QDir::Files);
+
+    int selected = 0;
+
+    QStringList themeList = themeDir.entryList();
+    QString defaultTheme = QFileInfo(defaultThemeFileName()).fileName();
+    if (themeList.removeAll(defaultTheme))
+        themeList.prepend(defaultTheme);
+    foreach (const QString &file, themeList) {
+        const QString fileName = themeDir.absoluteFilePath(file);
+        if (d->m_currentTheme.fileName() == fileName)
+            selected = themes.size();
+        themes.append(ThemeEntry(fileName, true));
+    }
+
+    if (themes.isEmpty())
+        qWarning() << "Warning: no themes found in path:" << themeDir.path();
+
+    themeDir.setPath(customThemesPath());
+    foreach (const QString &file, themeDir.entryList()) {
+        const QString fileName = themeDir.absoluteFilePath(file);
+        if (d->m_currentTheme.fileName() == fileName)
+            selected = themes.size();
+        themes.append(ThemeEntry(fileName, false));
+    }
+
+    d->m_currentTheme = themes[selected];
+
+    d->m_refreshingThemeList = true;
+    d->m_themeListModel->setThemes(themes);
+    d->m_ui->themeComboBox->setCurrentIndex(selected);
+    d->m_refreshingThemeList = false;
+}
+
+QString ThemeSettingsWidget::defaultThemeFileName(const QString &fileName)
+{
+    QString defaultScheme = Core::ICore::resourcePath();
+    defaultScheme += QLatin1String("/themes/");
+
+    if (!fileName.isEmpty() && QFile::exists(defaultScheme + fileName))
+        defaultScheme += fileName;
+    else
+        defaultScheme += QLatin1String("default.creatortheme");
+
+    return defaultScheme;
+}
+
+void ThemeSettingsWidget::themeSelected(int index)
+{
+    bool readOnly = true;
+    if (index != -1) {
+        // Check whether we're switching away from a changed theme
+        if (!d->m_refreshingThemeList)
+            maybeSaveTheme();
+
+        const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
+        readOnly = entry.readOnly();
+        d->m_currentTheme = entry;
+
+        QSettings settings(entry.fileName(), QSettings::IniFormat);
+        Theme theme;
+        theme.readSettings(settings);
+        d->m_ui->editor->initFrom(&theme);
+    }
+    d->m_ui->copyButton->setEnabled(index != -1);
+    d->m_ui->deleteButton->setEnabled(!readOnly);
+    d->m_ui->renameButton->setEnabled(!readOnly);
+    d->m_ui->editor->setReadOnly(readOnly);
+}
+
+void ThemeSettingsWidget::confirmDeleteTheme()
+{
+    const int index = d->m_ui->themeComboBox->currentIndex();
+    if (index == -1)
+        return;
+
+    const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
+    if (entry.readOnly())
+        return;
+
+    QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning,
+                                              tr("Delete Theme"),
+                                              tr("Are you sure you want to delete the theme '%1' permanently?").arg(entry.name()),
+                                              QMessageBox::Discard | QMessageBox::Cancel,
+                                              d->m_ui->deleteButton->window());
+
+    // Change the text and role of the discard button
+    QPushButton *deleteButton = static_cast<QPushButton*>(messageBox->button(QMessageBox::Discard));
+    deleteButton->setText(tr("Delete"));
+    messageBox->addButton(deleteButton, QMessageBox::AcceptRole);
+    messageBox->setDefaultButton(deleteButton);
+
+    connect(deleteButton, &QAbstractButton::clicked, messageBox, &QDialog::accept);
+    connect(messageBox, &QDialog::accepted, this, &ThemeSettingsWidget::deleteTheme);
+    messageBox->setAttribute(Qt::WA_DeleteOnClose);
+    messageBox->open();
+}
+
+void ThemeSettingsWidget::deleteTheme()
+{
+    const int index = d->m_ui->themeComboBox->currentIndex();
+    QTC_ASSERT(index != -1, return);
+
+    const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
+    QTC_ASSERT(!entry.readOnly(), return);
+
+    if (QFile::remove(entry.fileName()))
+        d->m_themeListModel->removeTheme(index);
+}
+
+void ThemeSettingsWidget::copyTheme()
+{
+    QInputDialog *dialog = new QInputDialog(d->m_ui->copyButton->window());
+    dialog->setAttribute(Qt::WA_DeleteOnClose);
+    dialog->setInputMode(QInputDialog::TextInput);
+    dialog->setWindowTitle(tr("Copy Theme"));
+    dialog->setLabelText(tr("Theme name:"));
+
+    //TODO
+    //dialog->setTextValue(tr("%1 (copy)").arg(d_ptr->m_value.colorScheme().displayName()));
+
+    connect(dialog, &QInputDialog::textValueSelected, this, &ThemeSettingsWidget::copyThemeByName);
+    dialog->open();
+}
+
+void ThemeSettingsWidget::maybeSaveTheme()
+{
+    if (!d->m_ui->editor->model()->hasChanges())
+        return;
+
+    QMessageBox *messageBox = new QMessageBox(QMessageBox::Warning,
+                                              tr("Theme Changed"),
+                                              tr("The theme \"%1\" was modified, do you want to save the changes?")
+                                                  .arg(d->m_currentTheme.name()),
+                                              QMessageBox::Discard | QMessageBox::Save,
+                                              d->m_ui->themeComboBox->window());
+
+    // Change the text of the discard button
+    QPushButton *discardButton = static_cast<QPushButton*>(messageBox->button(QMessageBox::Discard));
+    discardButton->setText(tr("Discard"));
+    messageBox->addButton(discardButton, QMessageBox::DestructiveRole);
+    messageBox->setDefaultButton(QMessageBox::Save);
+
+    if (messageBox->exec() == QMessageBox::Save) {
+        Theme newTheme;
+        d->m_ui->editor->model()->toTheme(&newTheme);
+        newTheme.writeSettings(d->m_currentTheme.fileName());
+    }
+}
+
+void ThemeSettingsWidget::renameTheme()
+{
+    int index = d->m_ui->themeComboBox->currentIndex();
+    if (index == -1)
+        return;
+    const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
+
+    maybeSaveTheme();
+
+    QInputDialog *dialog = new QInputDialog(d->m_ui->renameButton->window());
+    dialog->setInputMode(QInputDialog::TextInput);
+    dialog->setWindowTitle(tr("Rename Theme"));
+    dialog->setLabelText(tr("Theme name:"));
+    dialog->setTextValue(d->m_ui->editor->model()->m_name);
+    int ret = dialog->exec();
+    QString newName = dialog->textValue();
+    delete dialog;
+
+    if (ret != QDialog::Accepted || newName.isEmpty())
+        return;
+
+    // overwrite file with new name
+    Theme newTheme;
+    d->m_ui->editor->model()->toTheme(&newTheme);
+    newTheme.setName(newName);
+    newTheme.writeSettings(entry.fileName());
+
+    refreshThemeList();
+}
+
+void ThemeSettingsWidget::copyThemeByName(const QString &name)
+{
+    int index = d->m_ui->themeComboBox->currentIndex();
+    if (index == -1)
+        return;
+
+    const ThemeEntry &entry = d->m_themeListModel->themeAt(index);
+
+    QString baseFileName = QFileInfo(entry.fileName()).completeBaseName();
+    baseFileName += QLatin1String("_copy%1.creatortheme");
+    QString fileName = createThemeFileName(baseFileName);
+
+    if (fileName.isEmpty())
+        return;
+
+    // Ask about saving any existing modifactions
+    maybeSaveTheme();
+
+    Theme newTheme;
+    d->m_ui->editor->model()->toTheme(&newTheme);
+    newTheme.setName(name);
+    newTheme.writeSettings(fileName);
+
+    d->m_currentTheme = ThemeEntry(fileName, true);
+
+    refreshThemeList();
+}
+
+void ThemeSettingsWidget::apply()
+{
+    {
+        d->m_ui->editor->model()->toTheme(creatorTheme());
+        if (creatorTheme()->flag(Theme::ApplyThemePaletteGlobally))
+            QApplication::setPalette(creatorTheme()->palette(QApplication::palette()));
+        foreach (QWidget *w, QApplication::topLevelWidgets())
+            w->update();
+    }
+
+    // save definition of theme
+    if (!d->m_currentTheme.readOnly()) {
+        Theme newTheme;
+        d->m_ui->editor->model()->toTheme(&newTheme);
+        newTheme.writeSettings(d->m_currentTheme.fileName());
+    }
+
+    // save filename of selected theme in global config
+    QSettings *settings = Core::ICore::settings();
+    settings->setValue(QLatin1String(Core::Constants::SETTINGS_THEME), d->m_currentTheme.fileName());
+}
+
+} // namespace Internal
+} // namespace Core
diff --git a/src/plugins/coreplugin/themesettingswidget.h b/src/plugins/coreplugin/themesettingswidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..8ed5dd882d1d2dc19dfc573b6e16b6fceadb0cf7
--- /dev/null
+++ b/src/plugins/coreplugin/themesettingswidget.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Thorben Kroeger <thorbenkroeger@gmail.com>.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://www.qt.io/licensing.  For further information
+** use the contact form at http://www.qt.io/contact-us.
+**
+** 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 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef THEMESETTINGSWIDGET_H
+#define THEMESETTINGSWIDGET_H
+
+#include <QWidget>
+
+namespace Core {
+namespace Internal {
+
+class ThemeSettingsPrivate;
+
+class ThemeSettingsWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    ThemeSettingsWidget(QWidget *parent = 0);
+    ~ThemeSettingsWidget();
+
+    static QString defaultThemeFileName(const QString &fileName = QString());
+
+    void apply();
+
+private slots:
+    void themeSelected(int index);
+    void copyTheme();
+    void renameTheme();
+    void copyThemeByName(const QString &);
+    void confirmDeleteTheme();
+    void deleteTheme();
+    void maybeSaveTheme();
+
+private:
+    void refreshThemeList();
+    ThemeSettingsPrivate *d;
+};
+
+} // namespace Internal
+} // namespace Core
+
+#endif // THEMESETTINGSWIDGET_H