diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer.cpp b/src/plugins/coreplugin/actionmanager/actioncontainer.cpp
index 060c89ea9f75b1c49847cb8ccb0b9bc301b34ff2..e8bf0bf5ce0b2380bbf5a913630f2c982101f946 100644
--- a/src/plugins/coreplugin/actionmanager/actioncontainer.cpp
+++ b/src/plugins/coreplugin/actionmanager/actioncontainer.cpp
@@ -268,10 +268,32 @@ void ActionContainerPrivate::addMenu(ActionContainer *menu, const QString &group
     QAction *beforeAction = insertLocation(groupIt);
     m_groups[groupIt-m_groups.constBegin()].items.append(menu);
 
+    connect(menu, SIGNAL(destroyed()), this, SLOT(itemDestroyed()));
     insertMenu(beforeAction, container->menu());
     scheduleUpdate();
 }
 
+void ActionContainerPrivate::clear()
+{
+    QMutableListIterator<Group> it(m_groups);
+    while (it.hasNext()) {
+        Group &group = it.next();
+        foreach (QObject *item, group.items) {
+            if (Command *command = qobject_cast<Command *>(item)) {
+                removeAction(command->action());
+                disconnect(command, SIGNAL(activeStateChanged()), this, SLOT(scheduleUpdate()));
+                disconnect(command, SIGNAL(destroyed()), this, SLOT(itemDestroyed()));
+            } else if (ActionContainer *container = qobject_cast<ActionContainer *>(item)) {
+                container->clear();
+                disconnect(container, SIGNAL(destroyed()), this, SLOT(itemDestroyed()));
+                removeMenu(container->menu());
+            }
+        }
+        group.items.clear();
+    }
+    scheduleUpdate();
+}
+
 void ActionContainerPrivate::itemDestroyed()
 {
     QObject *obj = sender();
@@ -350,6 +372,16 @@ void MenuActionContainer::insertMenu(QAction *before, QMenu *menu)
     m_menu->insertMenu(before, menu);
 }
 
+void MenuActionContainer::removeAction(QAction *action)
+{
+    m_menu->removeAction(action);
+}
+
+void MenuActionContainer::removeMenu(QMenu *menu)
+{
+    m_menu->removeAction(menu->menuAction());
+}
+
 bool MenuActionContainer::updateInternal()
 {
     if (onAllDisabledBehavior() == Show)
@@ -442,6 +474,16 @@ void MenuBarActionContainer::insertMenu(QAction *before, QMenu *menu)
     m_menuBar->insertMenu(before, menu);
 }
 
+void MenuBarActionContainer::removeAction(QAction *action)
+{
+    m_menuBar->removeAction(action);
+}
+
+void MenuBarActionContainer::removeMenu(QMenu *menu)
+{
+    m_menuBar->removeAction(menu->menuAction());
+}
+
 bool MenuBarActionContainer::updateInternal()
 {
     if (onAllDisabledBehavior() == Show)
diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer.h b/src/plugins/coreplugin/actionmanager/actioncontainer.h
index c8a4f03eb3470a8f04550c4c7b7bbffa14ac13e0..8aee27c7a7420e1e0b10b55c2b8a23638df4c803 100644
--- a/src/plugins/coreplugin/actionmanager/actioncontainer.h
+++ b/src/plugins/coreplugin/actionmanager/actioncontainer.h
@@ -70,6 +70,9 @@ public:
     virtual void addAction(Core::Command *action, const QString &group = QString()) = 0;
     virtual void addMenu(Core::ActionContainer *menu, const QString &group = QString()) = 0;
 
+    // clears this menu and submenus from all actions and submenus
+    // doesn't destroy the submenus and commands, just removes them from their parents
+    virtual void clear() = 0;
     virtual ~ActionContainer() {}
 };
 
diff --git a/src/plugins/coreplugin/actionmanager/actioncontainer_p.h b/src/plugins/coreplugin/actionmanager/actioncontainer_p.h
index 6aff0a8d08df2bba11e0c7861f4a31c920600e07..a0318a4acf6b89c247f45b6e221986000783f12f 100644
--- a/src/plugins/coreplugin/actionmanager/actioncontainer_p.h
+++ b/src/plugins/coreplugin/actionmanager/actioncontainer_p.h
@@ -63,6 +63,7 @@ public:
     void appendGroup(const QString &id);
     void addAction(Command *action, const QString &group = QString());
     void addMenu(ActionContainer *menu, const QString &group = QString());
+    virtual void clear();
 
     int id() const;
 
@@ -72,6 +73,9 @@ public:
     virtual void insertAction(QAction *before, QAction *action) = 0;
     virtual void insertMenu(QAction *before, QMenu *menu) = 0;
 
+    virtual void removeAction(QAction *action) = 0;
+    virtual void removeMenu(QMenu *menu) = 0;
+
     virtual bool updateInternal() = 0;
 
 protected:
@@ -107,6 +111,9 @@ public:
     void insertAction(QAction *before, QAction *action);
     void insertMenu(QAction *before, QMenu *menu);
 
+    void removeAction(QAction *action);
+    void removeMenu(QMenu *menu);
+
 protected:
     bool canBeAddedToMenu() const;
     bool updateInternal();
@@ -126,6 +133,9 @@ public:
     void insertAction(QAction *before, QAction *action);
     void insertMenu(QAction *before, QMenu *menu);
 
+    void removeAction(QAction *action);
+    void removeMenu(QMenu *menu);
+
 protected:
     bool canBeAddedToMenu() const;
     bool updateInternal();
diff --git a/src/plugins/coreplugin/actionmanager/actionmanager.cpp b/src/plugins/coreplugin/actionmanager/actionmanager.cpp
index c6ca7fb77eb6b88face49b1279a31d4521544ee1..854761d280bf0af474c8adc0e7455e9f75745a52 100644
--- a/src/plugins/coreplugin/actionmanager/actionmanager.cpp
+++ b/src/plugins/coreplugin/actionmanager/actionmanager.cpp
@@ -248,6 +248,8 @@ ActionManagerPrivate::ActionManagerPrivate(MainWindow *mainWnd)
 ActionManagerPrivate::~ActionManagerPrivate()
 {
     // first delete containers to avoid them reacting to command deletion
+    foreach (ActionContainerPrivate *container, m_idContainerMap)
+        disconnect(container, SIGNAL(destroyed()), this, SLOT(containerDestroyed()));
     qDeleteAll(m_idContainerMap.values());
     qDeleteAll(m_idCmdMap.values());
 }
@@ -314,6 +316,7 @@ ActionContainer *ActionManagerPrivate::createMenu(const Id &id)
     mc->setMenu(m);
 
     m_idContainerMap.insert(uid, mc);
+    connect(mc, SIGNAL(destroyed()), this, SLOT(containerDestroyed()));
 
     return mc;
 }
@@ -332,10 +335,17 @@ ActionContainer *ActionManagerPrivate::createMenuBar(const Id &id)
     mbc->setMenuBar(mb);
 
     m_idContainerMap.insert(uid, mbc);
+    connect(mbc, SIGNAL(destroyed()), this, SLOT(containerDestroyed()));
 
     return mbc;
 }
 
+void ActionManagerPrivate::containerDestroyed()
+{
+    ActionContainerPrivate *container = static_cast<ActionContainerPrivate *>(sender());
+    m_idContainerMap.remove(m_idContainerMap.key(container));
+}
+
 Command *ActionManagerPrivate::registerAction(QAction *action, const Id &id, const Context &context, bool scriptable)
 {
     Action *a = overridableAction(id);
diff --git a/src/plugins/coreplugin/actionmanager/actionmanager_p.h b/src/plugins/coreplugin/actionmanager/actionmanager_p.h
index f3e94abb426ea74124d13811a6b5dc3c46a77c62..ce8c8b00e7fdfe0bdc06be855aad4d33a1795c7c 100644
--- a/src/plugins/coreplugin/actionmanager/actionmanager_p.h
+++ b/src/plugins/coreplugin/actionmanager/actionmanager_p.h
@@ -93,6 +93,8 @@ public:
     void unregisterAction(QAction *action, const Id &id);
     void unregisterShortcut(const Id &id);
 
+private slots:
+    void containerDestroyed();
 private:
     bool hasContext(const Context &context) const;
     Action *overridableAction(const Id &id);
diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp
index f95b0d8e0f4fc687c347b9ee1d2ec0c26744820a..cc04b50c208ec2902d3a19cefbdb530bb9cc4bf6 100644
--- a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp
+++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp
@@ -34,6 +34,8 @@
 #include "externaltoolconfig.h"
 #include "ui_externaltoolconfig.h"
 
+#include <utils/qtcassert.h>
+
 #include <QtCore/QTextStream>
 
 using namespace Core::Internal;
@@ -43,13 +45,21 @@ ExternalToolConfig::ExternalToolConfig(QWidget *parent) :
     ui(new Ui::ExternalToolConfig)
 {
     ui->setupUi(this);
+    ui->toolTree->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
     connect(ui->toolTree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
             this, SLOT(showInfoForItem(QTreeWidgetItem*)));
+    connect(ui->toolTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
+            this, SLOT(updateItem(QTreeWidgetItem *)));
     showInfoForItem(0);
 }
 
 ExternalToolConfig::~ExternalToolConfig()
 {
+    QMapIterator<QString, QList<ExternalTool *> > it(m_tools);
+    while (it.hasNext()) {
+        it.next();
+        qDeleteAll(it.value());
+    }
     delete ui;
 }
 
@@ -69,19 +79,32 @@ QString ExternalToolConfig::searchKeywords() const
 
 void ExternalToolConfig::setTools(const QMap<QString, QList<ExternalTool *> > &tools)
 {
-    // TODO make copy of tools
+    QMapIterator<QString, QList<ExternalTool *> > it(tools);
+    while (it.hasNext()) {
+        it.next();
+        QList<ExternalTool *> itemCopy;
+        foreach (ExternalTool *tool, it.value())
+            itemCopy.append(new ExternalTool(tool));
+        m_tools.insert(it.key(), itemCopy);
+    }
 
-    QMapIterator<QString, QList<ExternalTool *> > categories(tools);
+    bool blocked = ui->toolTree->blockSignals(true); // block itemChanged
+    Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable;
+    QMapIterator<QString, QList<ExternalTool *> > categories(m_tools);
     while (categories.hasNext()) {
         categories.next();
         QString name = (categories.key().isEmpty() ? tr("External Tools Menu") : categories.key());
         QTreeWidgetItem *category = new QTreeWidgetItem(ui->toolTree, QStringList() << name);
+        category->setFlags(flags);
+        category->setData(0, Qt::UserRole, name); // save the name in case of category being renamed by user
         foreach (ExternalTool *tool, categories.value()) {
             QTreeWidgetItem *item = new QTreeWidgetItem(category, QStringList() << tool->displayName());
+            item->setFlags(flags);
             item->setData(0, Qt::UserRole, qVariantFromValue(tool));
         }
     }
     ui->toolTree->expandAll();
+    ui->toolTree->blockSignals(blocked); // unblock itemChanged
 }
 
 void ExternalToolConfig::showInfoForItem(QTreeWidgetItem *item)
@@ -110,3 +133,51 @@ void ExternalToolConfig::showInfoForItem(QTreeWidgetItem *item)
     ui->description->setCursorPosition(0);
     ui->arguments->setCursorPosition(0);
 }
+
+void ExternalToolConfig::updateItem(QTreeWidgetItem *item)
+{
+    ExternalTool *tool = 0;
+    if (item)
+        tool = item->data(0, Qt::UserRole).value<ExternalTool *>();
+    if (tool) {
+        // tool was renamed
+        const QString &newName = item->data(0, Qt::DisplayRole).toString();
+        if (newName == tool->displayName())
+            return;
+        if (newName.isEmpty()) {
+            // prevent empty names
+            bool blocked = ui->toolTree->blockSignals(true); // block itemChanged
+            item->setData(0, Qt::DisplayRole, tool->displayName());
+            ui->toolTree->blockSignals(blocked); // unblock itemChanged
+            return;
+        }
+        tool->setDisplayName(item->data(0, Qt::DisplayRole).toString());
+    } else {
+        // category was renamed
+        const QString &oldName = item->data(0, Qt::UserRole).toString();
+        const QString &newName = item->data(0, Qt::DisplayRole).toString();
+        if (oldName == newName)
+            return;
+        if (newName.isEmpty() && m_tools.contains(newName)) {
+            // prevent empty or duplicate names
+            bool blocked = ui->toolTree->blockSignals(true); // block itemChanged
+            item->setData(0, Qt::DisplayRole, oldName);
+            ui->toolTree->blockSignals(blocked); // unblock itemChanged
+            return;
+        }
+        QTC_ASSERT(m_tools.contains(oldName), return);
+        m_tools.insert(newName, m_tools.value(oldName));
+        m_tools.remove(oldName);
+
+        bool blocked = ui->toolTree->blockSignals(true); // block itemChanged
+        item->setData(0, Qt::UserRole, newName);
+        int currentIndex = ui->toolTree->indexOfTopLevelItem(item);
+        bool wasExpanded = ui->toolTree->isExpanded(ui->toolTree->model()->index(currentIndex, 0));
+        ui->toolTree->takeTopLevelItem(currentIndex);
+        int newIndex = m_tools.keys().indexOf(newName);
+        ui->toolTree->insertTopLevelItem(newIndex, item);
+        if (wasExpanded)
+            ui->toolTree->expand(ui->toolTree->model()->index(newIndex, 0));
+        ui->toolTree->blockSignals(blocked); // unblock itemChanged
+    }
+}
diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.h b/src/plugins/coreplugin/dialogs/externaltoolconfig.h
index a05eb4be7288dad07100b87029b539cb7455f6e3..fa642366bb5dad81933c829144eef9859f8a3875 100644
--- a/src/plugins/coreplugin/dialogs/externaltoolconfig.h
+++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.h
@@ -55,14 +55,17 @@ public:
     ~ExternalToolConfig();
 
     void setTools(const QMap<QString, QList<ExternalTool *> > &tools);
+    QMap<QString, QList<ExternalTool *> > tools() const { return m_tools; }
 
     QString searchKeywords() const;
 
 private slots:
     void showInfoForItem(QTreeWidgetItem *item);
+    void updateItem(QTreeWidgetItem *item);
 
 private:
     Ui::ExternalToolConfig *ui;
+    QMap<QString, QList<ExternalTool *> > m_tools;
 };
 
 } // Internal
diff --git a/src/plugins/coreplugin/externaltool.cpp b/src/plugins/coreplugin/externaltool.cpp
index c334362b7bb3eee72e257d3ba0ce9452ba95eaf3..8024746ecfac8b63cceafa244c179992bd6effb8 100644
--- a/src/plugins/coreplugin/externaltool.cpp
+++ b/src/plugins/coreplugin/externaltool.cpp
@@ -29,7 +29,6 @@
 
 #include "externaltool.h"
 #include "actionmanager/actionmanager.h"
-#include "actionmanager/actioncontainer.h"
 #include "coreconstants.h"
 #include "variablemanager.h"
 
@@ -80,7 +79,8 @@ namespace {
 ExternalTool::ExternalTool() :
     m_order(-1),
     m_outputHandling(ShowInPane),
-    m_errorHandling(ShowInPane)
+    m_errorHandling(ShowInPane),
+    m_isDisplayNameChanged(false)
 {
 }
 
@@ -95,7 +95,8 @@ ExternalTool::ExternalTool(const ExternalTool *other)
       m_input(other->m_input),
       m_workingDirectory(other->m_workingDirectory),
       m_outputHandling(other->m_outputHandling),
-      m_errorHandling(other->m_errorHandling)
+      m_errorHandling(other->m_errorHandling),
+      m_isDisplayNameChanged(other->m_isDisplayNameChanged)
 {
 }
 
@@ -118,6 +119,14 @@ QString ExternalTool::displayName() const
     return m_displayName;
 }
 
+void ExternalTool::setDisplayName(const QString &name)
+{
+    if (name == m_displayName)
+        return;
+    m_isDisplayNameChanged = true;
+    m_displayName = name;
+}
+
 QString ExternalTool::displayCategory() const
 {
     return m_displayCategory;
@@ -298,16 +307,37 @@ ExternalTool * ExternalTool::createFromXml(const QByteArray &xml, QString *error
     return tool;
 }
 
+bool ExternalTool::operator==(const ExternalTool &other)
+{
+    return m_id == other.m_id
+            && m_description == other.m_description
+            && m_displayName == other.m_displayName
+            && m_displayCategory == other.m_displayCategory
+            && m_order == other.m_order
+            && m_executables == other.m_executables
+            && m_arguments == other.m_arguments
+            && m_input == other.m_input
+            && m_workingDirectory == other.m_workingDirectory
+            && m_outputHandling == other.m_outputHandling
+            && m_errorHandling == other.m_errorHandling;
+}
+
 // #pragma mark -- ExternalToolRunner
 
 ExternalToolRunner::ExternalToolRunner(const ExternalTool *tool)
-    : m_tool(tool),
+    : m_tool(new ExternalTool(tool)),
       m_process(0),
       m_outputCodec(QTextCodec::codecForLocale())
 {
     run();
 }
 
+ExternalToolRunner::~ExternalToolRunner()
+{
+    if (m_tool)
+        delete m_tool;
+}
+
 bool ExternalToolRunner::resolve()
 {
     if (!m_tool)
@@ -450,60 +480,50 @@ ExternalToolManager::ExternalToolManager(Core::ICore *core)
 
 ExternalToolManager::~ExternalToolManager()
 {
+    writeSettings();
     // TODO kill running tools
     qDeleteAll(m_tools);
 }
 
 void ExternalToolManager::initialize()
 {
+    // add the external tools menu
     ActionManager *am = m_core->actionManager();
     ActionContainer *mexternaltools = am->createMenu(Id(Constants::M_TOOLS_EXTERNAL));
     mexternaltools->menu()->setTitle(tr("External"));
     ActionContainer *mtools = am->actionContainer(Constants::M_TOOLS);
-
     mtools->addMenu(mexternaltools, Constants::G_DEFAULT_THREE);
 
-    QMap<QString, QMultiMap<int, ExternalTool*> > categoryMap;
+    QMap<QString, QMultiMap<int, ExternalTool*> > categoryPriorityMap;
+    QMap<QString, ExternalTool *> tools;
     parseDirectory(m_core->userResourcePath() + QLatin1String("/externaltools"),
-                   &categoryMap);
+                   &categoryPriorityMap,
+                   &tools);
     parseDirectory(m_core->resourcePath() + QLatin1String("/externaltools"),
-                   &categoryMap, true);
+                   &categoryPriorityMap,
+                   &tools,
+                   true);
 
-    QMapIterator<QString, QMultiMap<int, ExternalTool*> > it(categoryMap);
-    while (it.hasNext()) {
-        it.next();
-        m_categoryMap.insert(it.key(), it.value().values());
-    }
+    // adapt overridden names and categories etc
+    readSettings(tools, &categoryPriorityMap);
 
-    // add all the category menus, QMap is nicely sorted
-    it.toFront();
+    QMap<QString, QList<Internal::ExternalTool *> > categoryMap;
+    QMapIterator<QString, QMultiMap<int, ExternalTool*> > it(categoryPriorityMap);
     while (it.hasNext()) {
         it.next();
-        ActionContainer *container = 0;
-        if (it.key() == QString()) { // no displayCategory, so put into external tools menu directly
-            container = mexternaltools;
-        } else {
-            container = am->createMenu(Id("Tools.External.Category." + it.key()));
-            mexternaltools->addMenu(container, Constants::G_DEFAULT_ONE);
-            container->menu()->setTitle(it.key());
-        }
-        foreach (ExternalTool *tool, it.value().values()) {
-            // tool action and command
-            QAction *action = new QAction(tool->displayName(), this);
-            action->setToolTip(tool->description());
-            action->setWhatsThis(tool->description());
-            action->setData(tool->id());
-            Command *cmd = am->registerAction(action, Id("Tools.External." + tool->id()), Context(Constants::C_GLOBAL));
-            connect(action, SIGNAL(triggered()), this, SLOT(menuActivated()));
-            container->addAction(cmd, Constants::G_DEFAULT_TWO);
-        }
+        categoryMap.insert(it.key(), it.value().values());
     }
+
+    setToolsByCategory(categoryMap);
 }
 
-void ExternalToolManager::parseDirectory(const QString &directory, QMap<QString, QMultiMap<int, ExternalTool*> > *categoryMenus,
+void ExternalToolManager::parseDirectory(const QString &directory,
+                                         QMap<QString, QMultiMap<int, Internal::ExternalTool*> > *categoryMenus,
+                                         QMap<QString, ExternalTool *> *tools,
                                          bool ignoreDuplicates)
 {
     QTC_ASSERT(categoryMenus, return);
+    QTC_ASSERT(tools, return);
     QDir dir(directory, QLatin1String("*.xml"), QDir::Unsorted, QDir::Files | QDir::Readable);
     foreach (const QFileInfo &info, dir.entryInfoList()) {
         QFile file(info.absoluteFilePath());
@@ -517,14 +537,14 @@ void ExternalToolManager::parseDirectory(const QString &directory, QMap<QString,
                 qDebug() << tr("Error while parsing external tool %1: %2").arg(file.fileName(), error);
                 continue;
             }
-            if (m_tools.contains(tool->id())) {
+            if (tools->contains(tool->id())) {
                 // TODO error handling
                 if (!ignoreDuplicates)
                     qDebug() << tr("Error: External tool in %1 has duplicate id").arg(file.fileName());
                 delete tool;
                 continue;
             }
-            m_tools.insert(tool->id(), tool);
+            tools->insert(tool->id(), tool);
             (*categoryMenus)[tool->displayCategory()].insert(tool->order(), tool);
         }
     }
@@ -539,8 +559,162 @@ void ExternalToolManager::menuActivated()
     new ExternalToolRunner(tool);
 }
 
-QMap<QString, QList<Internal::ExternalTool *> > ExternalToolManager::tools() const
+QMap<QString, QList<Internal::ExternalTool *> > ExternalToolManager::toolsByCategory() const
 {
     return m_categoryMap;
 }
 
+QMap<QString, ExternalTool *> ExternalToolManager::toolsById() const
+{
+    return m_tools;
+}
+
+void ExternalToolManager::setToolsByCategory(const QMap<QString, QList<Internal::ExternalTool *> > &tools)
+{
+    // clear menu
+    ActionManager *am = m_core->actionManager();
+    ActionContainer *mexternaltools = am->actionContainer(Id(Constants::M_TOOLS_EXTERNAL));
+    mexternaltools->clear();
+
+    // delete old tools and create list of new ones
+    QMap<QString, ExternalTool *> newTools;
+    QMap<QString, QAction *> newActions;
+    QMapIterator<QString, QList<ExternalTool *> > it(tools);
+    while (it.hasNext()) {
+        it.next();
+        foreach (ExternalTool *tool, it.value()) {
+            const QString &id = tool->id();
+            if (m_tools.value(id) == tool) {
+                newActions.insert(id, m_actions.value(id));
+                // remove from list to prevent deletion
+                m_tools.remove(id);
+                m_actions.remove(id);
+            }
+            newTools.insert(id, tool);
+        }
+    }
+    qDeleteAll(m_tools);
+    QMapIterator<QString, QAction *> remainingActions(m_actions);
+    while (remainingActions.hasNext()) {
+        remainingActions.next();
+        am->unregisterAction(remainingActions.value(), Id("Tools.External." + remainingActions.key()));
+        delete remainingActions.value();
+    }
+    m_actions.clear();
+    // assign the new stuff
+    m_tools = newTools;
+    m_actions = newActions;
+    m_categoryMap = tools;
+    // create menu structure and remove no-longer used containers
+    // add all the category menus, QMap is nicely sorted
+    QMap<QString, ActionContainer *> newContainers;
+    it.toFront();
+    while (it.hasNext()) {
+        it.next();
+        ActionContainer *container = 0;
+        const QString &containerName = it.key();
+        if (containerName == QString()) { // no displayCategory, so put into external tools menu directly
+            container = mexternaltools;
+        } else {
+            if (m_containers.contains(containerName)) {
+                container = m_containers.take(containerName); // remove to avoid deletion below
+            } else {
+                container = am->createMenu(Id("Tools.External.Category." + containerName));
+            }
+            newContainers.insert(containerName, container);
+            mexternaltools->addMenu(container, Constants::G_DEFAULT_ONE);
+            container->menu()->setTitle(containerName);
+        }
+        foreach (ExternalTool *tool, it.value()) {
+            const QString &toolId = tool->id();
+            // tool action and command
+            QAction *action = 0;
+            Command *command = 0;
+            if (m_actions.contains(toolId)) {
+                action = m_actions.value(toolId);
+                command = am->command(Id("Tools.External." + toolId));
+            } else {
+                action = new QAction(tool->displayName(), this);
+                action->setData(toolId);
+                m_actions.insert(toolId, action);
+                connect(action, SIGNAL(triggered()), this, SLOT(menuActivated()));
+                command = am->registerAction(action, Id("Tools.External." + toolId), Context(Constants::C_GLOBAL));
+                command->setAttribute(Command::CA_UpdateText);
+            }
+            action->setText(tool->displayName());
+            action->setToolTip(tool->description());
+            action->setWhatsThis(tool->description());
+            container->addAction(command, Constants::G_DEFAULT_TWO);
+        }
+    }
+
+    // delete the unused containers
+    qDeleteAll(m_containers);
+    // remember the new containers
+    m_containers = newContainers;
+}
+
+void ExternalToolManager::readSettings(const QMap<QString, ExternalTool *> &tools,
+                                       QMap<QString, QMultiMap<int, Internal::ExternalTool*> > *categoryPriorityMap)
+{
+    QSettings *settings = m_core->settings();
+    settings->beginGroup(QLatin1String("ExternalTools"));
+
+    settings->beginGroup(QLatin1String("OverrideDisplayNames"));
+    foreach (const QString &id, settings->allKeys()) {
+        if (tools.contains(id)) {
+            const QString &newName = settings->value(id).toString();
+            if (tools.value(id)->displayName() != newName)
+                tools.value(id)->setDisplayName(newName);
+        }
+    }
+    settings->endGroup();
+
+    if (categoryPriorityMap) {
+        settings->beginGroup(QLatin1String("OverrideCategories"));
+        foreach (const QString &id, settings->allKeys()) {
+            if (tools.contains(id)) {
+                const QString &newCategory = settings->value(id).toString();
+                ExternalTool *tool = tools.value(id);
+                if (tool->displayCategory() != newCategory) {
+                    (*categoryPriorityMap)[tool->displayCategory()].remove(tool->order(), tool);
+                    (*categoryPriorityMap)[newCategory].insert(tool->order(), tool);
+                    if (categoryPriorityMap->value(tool->displayCategory()).isEmpty())
+                        categoryPriorityMap->remove(tool->displayCategory());
+                }
+            }
+        }
+        settings->endGroup();
+    }
+
+    settings->endGroup();
+}
+
+void ExternalToolManager::writeSettings()
+{
+    QSettings *settings = m_core->settings();
+    settings->beginGroup(QLatin1String("ExternalTools"));
+    settings->remove(QLatin1String(""));
+
+    settings->beginGroup(QLatin1String("OverrideDisplayNames"));
+    foreach (ExternalTool *tool, m_tools) {
+        if (tool->isDisplayNameChanged()) {
+            settings->setValue(tool->id(), tool->displayName());
+        }
+    }
+    settings->endGroup();
+
+    settings->beginGroup(QLatin1String("OverrideCategories"));
+    QMapIterator<QString, QList<ExternalTool *> > it(m_categoryMap);
+    while (it.hasNext()) {
+        it.next();
+        const QString &category = it.key();
+        foreach (ExternalTool *tool, it.value()) {
+            if (tool->displayCategory() != category)
+                settings->setValue(tool->id(), category);
+        }
+    }
+    settings->endGroup();
+
+    settings->endGroup();
+}
diff --git a/src/plugins/coreplugin/externaltool.h b/src/plugins/coreplugin/externaltool.h
index c6b2fb390af6d44d1dd7273889072a9ca31e603b..05a118e9b88a570b6223ef6068dbd039c62ed834 100644
--- a/src/plugins/coreplugin/externaltool.h
+++ b/src/plugins/coreplugin/externaltool.h
@@ -33,6 +33,7 @@
 #include "icore.h"
 #include "core_global.h"
 #include "actionmanager/command.h"
+#include "actionmanager/actioncontainer.h"
 
 #include <utils/qtcprocess.h>
 
@@ -58,12 +59,13 @@ public:
     };
 
     ExternalTool();
-    ExternalTool(const ExternalTool *other);
+    explicit ExternalTool(const ExternalTool *other);
     ~ExternalTool();
 
     QString id() const;
     QString description() const;
     QString displayName() const;
+    void setDisplayName(const QString &name);
     QString displayCategory() const;
     int order() const;
     OutputHandling outputHandling() const;
@@ -76,6 +78,11 @@ public:
 
     static ExternalTool *createFromXml(const QByteArray &xml, QString *errorMessage = 0, const QString &locale = QString());
 
+    // if the display name is different from the one in the original xml
+    bool isDisplayNameChanged() const { return m_isDisplayNameChanged; }
+
+    // ignores changed state
+    bool operator==(const ExternalTool &other);
 private:
     QString m_id;
     QString m_description;
@@ -88,6 +95,7 @@ private:
     QString m_workingDirectory;
     OutputHandling m_outputHandling;
     OutputHandling m_errorHandling;
+    bool m_isDisplayNameChanged;
 };
 
 class ExternalToolRunner : public QObject
@@ -95,6 +103,7 @@ class ExternalToolRunner : public QObject
     Q_OBJECT
 public:
     ExternalToolRunner(const ExternalTool *tool);
+    ~ExternalToolRunner();
 
 private slots:
     void started();
@@ -107,7 +116,7 @@ private:
     void run();
     bool resolve();
 
-    const ExternalTool *m_tool;
+    const ExternalTool *m_tool; // is a copy of the tool that was passed in
     QString m_resolvedExecutable;
     QString m_resolvedArguments;
     QString m_resolvedInput;
@@ -132,7 +141,10 @@ public:
     ExternalToolManager(Core::ICore *core);
     ~ExternalToolManager();
 
-    QMap<QString, QList<Internal::ExternalTool *> > tools() const;
+    QMap<QString, QList<Internal::ExternalTool *> > toolsByCategory() const;
+    QMap<QString, Internal::ExternalTool *> toolsById() const;
+
+    void setToolsByCategory(const QMap<QString, QList<Internal::ExternalTool *> > &tools);
 
 signals:
     void replaceSelectionRequested(const QString &text);
@@ -142,13 +154,20 @@ private slots:
 
 private:
     void initialize();
-    void parseDirectory(const QString &directory, QMap<QString, QMultiMap<int, Internal::ExternalTool*> > *categoryMenus,
+    void parseDirectory(const QString &directory,
+                        QMap<QString, QMultiMap<int, Internal::ExternalTool*> > *categoryMenus,
+                        QMap<QString, Internal::ExternalTool *> *tools,
                         bool ignoreDuplicates = false);
+    void readSettings(const QMap<QString, Internal::ExternalTool *> &tools,
+                      QMap<QString, QMultiMap<int, Internal::ExternalTool*> > *categoryPriorityMap);
+    void writeSettings();
 
     static ExternalToolManager *m_instance;
     Core::ICore *m_core;
     QMap<QString, Internal::ExternalTool *> m_tools;
     QMap<QString, QList<Internal::ExternalTool *> > m_categoryMap;
+    QMap<QString, QAction *> m_actions;
+    QMap<QString, ActionContainer *> m_containers;
 
     // for sending the replaceSelectionRequested signal
     friend class Core::Internal::ExternalToolRunner;
diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp
index 075a8baf66268f49cfa21668e6812516fd128baf..e08b992a7b38f7d002aef7ece6a83630c1a747c1 100644
--- a/src/plugins/coreplugin/mainwindow.cpp
+++ b/src/plugins/coreplugin/mainwindow.cpp
@@ -134,6 +134,7 @@ MainWindow::MainWindow() :
     m_printer(0),
     m_actionManager(new ActionManagerPrivate(this)),
     m_editorManager(0),
+    m_externalToolManager(0),
     m_fileManager(new FileManager(this)),
     m_progressManager(new ProgressManagerPrivate()),
     m_scriptManager(new ScriptManagerPrivate(this)),
@@ -208,7 +209,7 @@ MainWindow::MainWindow() :
     m_messageManager = new MessageManager;
     m_editorManager = new EditorManager(m_coreImpl, this);
     m_editorManager->hide();
-    new ExternalToolManager(m_coreImpl);
+    m_externalToolManager = new ExternalToolManager(m_coreImpl);
     setCentralWidget(m_modeStack);
 
     connect(QApplication::instance(), SIGNAL(focusChanged(QWidget*,QWidget*)),
@@ -255,6 +256,8 @@ MainWindow::~MainWindow()
     pm->removeObject(m_generalSettings);
     pm->removeObject(m_toolSettings);
     pm->removeObject(m_systemEditor);
+    delete m_externalToolManager;
+    m_externalToolManager = 0;
     delete m_messageManager;
     m_messageManager = 0;
     delete m_shortcutSettings;
diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h
index 159cf35a74d799772f367d314583277bc8a834c1..1d72a35912b148b337ceb68deeb330f46134737d 100644
--- a/src/plugins/coreplugin/mainwindow.h
+++ b/src/plugins/coreplugin/mainwindow.h
@@ -53,6 +53,7 @@ namespace Core {
 class ActionManager;
 class StatusBarWidget;
 class EditorManager;
+class ExternalToolManager;
 class FileManager;
 class HelpManager;
 class IWizard;
@@ -189,6 +190,7 @@ private:
     mutable QPrinter *m_printer;
     ActionManagerPrivate *m_actionManager;
     EditorManager *m_editorManager;
+    ExternalToolManager *m_externalToolManager;
     FileManager *m_fileManager;
     MessageManager *m_messageManager;
     ProgressManagerPrivate *m_progressManager;
diff --git a/src/plugins/coreplugin/toolsettings.cpp b/src/plugins/coreplugin/toolsettings.cpp
index 019e46ad7fa5d6fc24ea16a3899c2161d8b6d183..67a0d245706c3fd28b87dfdf5e65795a8cfbd7b6 100644
--- a/src/plugins/coreplugin/toolsettings.cpp
+++ b/src/plugins/coreplugin/toolsettings.cpp
@@ -80,7 +80,7 @@ bool ToolSettings::matches(const QString & searchKeyWord) const
 QWidget *ToolSettings::createPage(QWidget *parent)
 {
     m_widget = new ExternalToolConfig(parent);
-    m_widget->setTools(ExternalToolManager::instance()->tools());
+    m_widget->setTools(ExternalToolManager::instance()->toolsByCategory());
     if (m_searchKeywords.isEmpty()) {
         m_searchKeywords = m_widget->searchKeywords();
     }
@@ -90,6 +90,30 @@ QWidget *ToolSettings::createPage(QWidget *parent)
 
 void ToolSettings::apply()
 {
+    if (!m_widget)
+        return;
+    QMap<QString, ExternalTool *> originalTools = ExternalToolManager::instance()->toolsById();
+    QMap<QString, QList<ExternalTool *> > newToolsMap = m_widget->tools();
+    QMap<QString, QList<ExternalTool *> > resultMap;
+    QMapIterator<QString, QList<ExternalTool *> > it(newToolsMap);
+    while (it.hasNext()) {
+        it.next();
+        QList<ExternalTool *> items;
+        foreach (ExternalTool *tool, it.value()) {
+            ExternalTool *toolToAdd = 0;
+            if (ExternalTool *originalTool = originalTools.take(tool->id())) {
+                // check if the tool has changed
+                if ((*originalTool) == (*tool)) {
+                    toolToAdd = originalTool;
+                } else {
+                    toolToAdd = new ExternalTool(tool);
+                }
+            }
+            items.append(toolToAdd);
+        }
+        resultMap.insert(it.key(), items);
+    }
+    ExternalToolManager::instance()->setToolsByCategory(resultMap);
 }