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); }