diff --git a/src/plugins/coreplugin/externaltool.cpp b/src/plugins/coreplugin/externaltool.cpp index bbea103821b7520d6c61d98e750aa6508cce5dc3..dac798e2210305890b84d730d1138584b804a8c0 100644 --- a/src/plugins/coreplugin/externaltool.cpp +++ b/src/plugins/coreplugin/externaltool.cpp @@ -42,8 +42,10 @@ #include <utils/environment.h> #include <QtCore/QXmlStreamReader> +#include <QtCore/QXmlStreamWriter> #include <QtCore/QDir> #include <QtCore/QFile> +#include <QtCore/QDateTime> #include <QtGui/QMenu> #include <QtGui/QMenuItem> #include <QtGui/QAction> @@ -55,6 +57,7 @@ using namespace Core::Internal; namespace { const char * const kExternalTool = "externaltool"; + const char * const kId = "id"; const char * const kDescription = "description"; const char * const kDisplayName = "displayname"; const char * const kCategory = "category"; @@ -84,8 +87,7 @@ ExternalTool::ExternalTool() : m_order(-1), m_outputHandling(ShowInPane), m_errorHandling(ShowInPane), - m_modifiesCurrentDocument(false), - m_isDisplayNameChanged(false) + m_modifiesCurrentDocument(false) { } @@ -102,7 +104,8 @@ ExternalTool::ExternalTool(const ExternalTool *other) m_outputHandling(other->m_outputHandling), m_errorHandling(other->m_errorHandling), m_modifiesCurrentDocument(other->m_modifiesCurrentDocument), - m_isDisplayNameChanged(other->m_isDisplayNameChanged) + m_fileName(other->m_fileName), + m_presetFileName(other->m_presetFileName) { } @@ -170,82 +173,75 @@ bool ExternalTool::modifiesCurrentDocument() const return m_modifiesCurrentDocument; } +void ExternalTool::setFileName(const QString &fileName) +{ + m_fileName = fileName; +} + +void ExternalTool::setPresetFileName(const QString &fileName) +{ + m_presetFileName = fileName; +} + +QString ExternalTool::fileName() const +{ + return m_fileName; +} + +QString ExternalTool::presetFileName() const +{ + return m_presetFileName; +} + void ExternalTool::setDisplayName(const QString &name) { - if (name == m_displayName) - return; - m_isDisplayNameChanged = true; m_displayName = name; } void ExternalTool::setDescription(const QString &description) { - if (description == m_description) - return; - m_isChanged = true; m_description = description; } void ExternalTool::setOutputHandling(OutputHandling handling) { - if (handling == m_outputHandling) - return; - m_isChanged = true; m_outputHandling = handling; } void ExternalTool::setErrorHandling(OutputHandling handling) { - if (handling == m_errorHandling) - return; - m_isChanged = true; m_errorHandling = handling; } void ExternalTool::setModifiesCurrentDocument(bool modifies) { - if (modifies == m_modifiesCurrentDocument) - return; - m_isChanged = true; m_modifiesCurrentDocument = modifies; } void ExternalTool::setExecutables(const QStringList &executables) { - if (executables == m_executables) - return; - m_isChanged = true; m_executables = executables; } void ExternalTool::setArguments(const QString &arguments) { - if (arguments == m_arguments) - return; - m_isChanged = true; m_arguments = arguments; } void ExternalTool::setInput(const QString &input) { - if (input == m_input) - return; - m_isChanged = true; m_input = input; } void ExternalTool::setWorkingDirectory(const QString &workingDirectory) { - if (workingDirectory == m_workingDirectory) - return; - m_isChanged = true; m_workingDirectory = workingDirectory; } @@ -319,7 +315,7 @@ ExternalTool * ExternalTool::createFromXml(const QByteArray &xml, QString *error if (!reader.readNextStartElement() || reader.name() != QLatin1String(kExternalTool)) reader.raiseError(QLatin1String("Missing start element <externaltool>")); - tool->m_id = reader.attributes().value(QLatin1String("id")).toString(); + tool->m_id = reader.attributes().value(QLatin1String(kId)).toString(); if (tool->m_id.isEmpty()) reader.raiseError(QLatin1String("Missing or empty id attribute for <externaltool>")); while (reader.readNextStartElement()) { @@ -398,6 +394,82 @@ ExternalTool * ExternalTool::createFromXml(const QByteArray &xml, QString *error return tool; } +ExternalTool * ExternalTool::createFromFile(const QString &fileName, QString *errorMessage, const QString &locale, bool isPreset) +{ + QFileInfo info(fileName); + QFile file(info.absoluteFilePath()); + if (!file.open(QIODevice::ReadOnly)) { + if (errorMessage) + *errorMessage = tr("Could not open tool specification %1 for reading").arg(fileName); + return 0; + } + const QByteArray &bytes = file.readAll(); + file.close(); + ExternalTool *tool = ExternalTool::createFromXml(bytes, errorMessage, locale); + if (!tool) { + return 0; + } + tool->m_fileName = file.fileName(); + if (isPreset) { + tool->setPresetFileName(file.fileName()); + } + return tool; +} + +static QLatin1String stringForOutputHandling(ExternalTool::OutputHandling handling) +{ + switch (handling) { + case Core::Internal::ExternalTool::Ignore: + return QLatin1String(kOutputIgnore); + case Core::Internal::ExternalTool::ShowInPane: + return QLatin1String(kOutputShowInPane); + case Core::Internal::ExternalTool::ReplaceSelection: + return QLatin1String(kOutputReplaceSelection); + } + return QLatin1String(""); +} + +bool ExternalTool::save(QString *errorMessage) const +{ + if (m_fileName.isEmpty()) + return false; + QFile file(m_fileName); + if (!file.open(QIODevice::WriteOnly)) { + if (errorMessage) + *errorMessage = tr("Could not write tool specification %1").arg(m_fileName); + return false; + } + QXmlStreamWriter out(&file); + out.setAutoFormatting(true); + out.writeStartDocument(QLatin1String("1.0")); + out.writeComment(QString::fromLatin1("Written on %1 by Qt Creator %2") + .arg(QDateTime::currentDateTime().toString(), QLatin1String(Constants::IDE_VERSION_LONG))); + out.writeStartElement(QLatin1String(kExternalTool)); + out.writeAttribute(QLatin1String(kId), m_id); + out.writeTextElement(QLatin1String(kDescription), m_description); + out.writeTextElement(QLatin1String(kDisplayName), m_displayName); + out.writeTextElement(QLatin1String(kCategory), m_displayCategory); + if (m_order != -1) + out.writeTextElement(QLatin1String(kOrder), QString::number(m_order)); + + out.writeStartElement(QLatin1String(kExecutable)); + out.writeAttribute(QLatin1String(kOutput), stringForOutputHandling(m_outputHandling)); + out.writeAttribute(QLatin1String(kError), stringForOutputHandling(m_errorHandling)); + out.writeAttribute(QLatin1String(kModifiesDocument), m_modifiesCurrentDocument ? QLatin1String(kYes) : QLatin1String(kNo)); + foreach (const QString &executable, m_executables) + out.writeTextElement(QLatin1String(kPath), executable); + if (!m_arguments.isEmpty()) + out.writeTextElement(QLatin1String(kArguments), m_arguments); + if (!m_input.isEmpty()) + out.writeTextElement(QLatin1String(kInput), m_input); + if (!m_workingDirectory.isEmpty()) + out.writeTextElement(QLatin1String(kWorkingDirectory), m_workingDirectory); + out.writeEndElement(); + + out.writeEndDocument(); + file.close(); +} + bool ExternalTool::operator==(const ExternalTool &other) { return m_id == other.m_id @@ -610,33 +682,31 @@ void ExternalToolManager::initialize() void ExternalToolManager::parseDirectory(const QString &directory, QMap<QString, QMultiMap<int, Internal::ExternalTool*> > *categoryMenus, QMap<QString, ExternalTool *> *tools, - bool ignoreDuplicates) + bool isPreset) { 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()); - if (file.open(QIODevice::ReadOnly)) { - const QByteArray &bytes = file.readAll(); - file.close(); - QString error; - ExternalTool *tool = ExternalTool::createFromXml(bytes, &error, m_core->userInterfaceLanguage()); - if (!tool) { - // TODO error handling - qDebug() << tr("Error while parsing external tool %1: %2").arg(file.fileName(), error); - continue; - } - 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; + const QString &fileName = info.absoluteFilePath(); + QString error; + ExternalTool *tool = ExternalTool::createFromFile(fileName, &error, m_core->userInterfaceLanguage(), isPreset); + if (!tool) { + qWarning() << tr("Error while parsing external tool %1: %2").arg(fileName, error); + continue; + } + if (tools->contains(tool->id())) { + if (isPreset) { + ExternalTool *other = tools->value(tool->id()); + other->setPresetFileName(fileName); + } else { + qWarning() << tr("Error: External tool in %1 has duplicate id").arg(fileName); } - tools->insert(tool->id(), tool); - (*categoryMenus)[tool->displayCategory()].insert(tool->order(), tool); + delete tool; + continue; } + tools->insert(tool->id(), tool); + (*categoryMenus)[tool->displayCategory()].insert(tool->order(), tool); } } @@ -750,16 +820,6 @@ void ExternalToolManager::readSettings(const QMap<QString, ExternalTool *> &tool 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()) { @@ -786,14 +846,6 @@ void ExternalToolManager::writeSettings() 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()) { diff --git a/src/plugins/coreplugin/externaltool.h b/src/plugins/coreplugin/externaltool.h index 445426ebf55058c853017963ebb75022ec3a5d60..a51fe2ba319c35b027dfd665904735a5c2dbe04f 100644 --- a/src/plugins/coreplugin/externaltool.h +++ b/src/plugins/coreplugin/externaltool.h @@ -75,11 +75,21 @@ public: QString input() const; QString workingDirectory() const; + void setFileName(const QString &fileName); + void setPresetFileName(const QString &fileName); + QString fileName() const; + QString presetFileName() const; + static ExternalTool *createFromXml(const QByteArray &xml, QString *errorMessage = 0, const QString &locale = QString()); + static ExternalTool *createFromFile(const QString &fileName, QString *errorMessage = 0, + const QString &locale = QString(), bool isPreset = false); + + bool save(QString *errorMessage = 0) const; // ignores changed state bool operator==(const ExternalTool &other); + // display category and order are handled specially void setDisplayName(const QString &name); void setDescription(const QString &description); void setOutputHandling(OutputHandling handling); @@ -89,9 +99,7 @@ public: void setArguments(const QString &arguments); void setInput(const QString &input); void setWorkingDirectory(const QString &workingDirectory); - // if the display name is different from the one in the original xml - bool isDisplayNameChanged() const { return m_isDisplayNameChanged; } - bool isChanged() const { return m_isChanged; } + private: QString m_id; QString m_description; @@ -106,8 +114,10 @@ private: OutputHandling m_errorHandling; bool m_modifiesCurrentDocument; - bool m_isDisplayNameChanged; - bool m_isChanged; + QString m_fileName; + QString m_presetFileName; + + mutable bool m_isChanged; }; class ExternalToolRunner : public QObject @@ -169,7 +179,7 @@ private: void parseDirectory(const QString &directory, QMap<QString, QMultiMap<int, Internal::ExternalTool*> > *categoryMenus, QMap<QString, Internal::ExternalTool *> *tools, - bool ignoreDuplicates = false); + bool isPreset = false); void readSettings(const QMap<QString, Internal::ExternalTool *> &tools, QMap<QString, QMultiMap<int, Internal::ExternalTool*> > *categoryPriorityMap); void writeSettings(); diff --git a/src/plugins/coreplugin/toolsettings.cpp b/src/plugins/coreplugin/toolsettings.cpp index 3e6a0c0007681e5ebca6986ff4aadf3b8e949a61..d38a3352898d320f581942f26619f8dcf5e8ffc8 100644 --- a/src/plugins/coreplugin/toolsettings.cpp +++ b/src/plugins/coreplugin/toolsettings.cpp @@ -33,6 +33,8 @@ #include "coreconstants.h" #include <QtCore/QCoreApplication> +#include <QtCore/QFileInfo> +#include <QtCore/QDir> using namespace Core; using namespace Core::Internal; @@ -107,6 +109,20 @@ void ToolSettings::apply() if ((*originalTool) == (*tool)) { toolToAdd = originalTool; } else { + // save the new tool description and make it be added + if (!tool->presetFileName().isEmpty() && tool->fileName() == tool->presetFileName()) { + // we don't overwrite the preset, so give it a new file name in user resources + // TODO avoid overwriting a tool xml file of another existing tool? + const QString &fileName = QFileInfo(tool->presetFileName()).fileName(); + QDir resourceDir(ICore::instance()->userResourcePath()); + if (!resourceDir.exists(QLatin1String("externaltools"))) + resourceDir.mkpath(QLatin1String("externaltools")); + const QString &newFilePath = ICore::instance()->userResourcePath() + + QLatin1String("/externaltools/") + fileName; + tool->setFileName(newFilePath); + } + // TODO error handling + tool->save(); toolToAdd = new ExternalTool(tool); } } diff --git a/src/share/qtcreator/externaltools/vi_mac.xml b/src/share/qtcreator/externaltools/vi_mac.xml index eca14163c4e356bc7636191b2f9033e02748516a..e2f5fd6d172d89fd8cb983a73821ccb06aa1ef86 100644 --- a/src/share/qtcreator/externaltools/vi_mac.xml +++ b/src/share/qtcreator/externaltools/vi_mac.xml @@ -41,13 +41,13 @@ <input> --Terminal opens a window by default when it is not running, so check on applicationIsRunning(applicationName) - tell application "System Events" to count (every process whose name is applicationName) + tell application "System Events" to count (every process whose name is applicationName) return result is greater than 0 end applicationIsRunning - set terminalWasRunning to applicationIsRunning("Terminal") + set terminalWasRunning to applicationIsRunning("Terminal") - set editorScript to "vi \"%{CurrentDocument:FilePath}\" +%{CurrentDocument:Row} +\"normal %{CurrentDocument:Column}|\"; exit" - tell application "Terminal" + set editorScript to "vi \"%{CurrentDocument:FilePath}\" +%{CurrentDocument:Row} +\"normal %{CurrentDocument:Column}|\"; exit" + tell application "Terminal" --do script will open a new window if none given, but terminal already opens one if not running if terminalWasRunning then do script editorScript