diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp new file mode 100644 index 00000000000..1a5537ef52a --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** 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://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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 "jsonwizard.h" + +#include "jsonwizardexpander.h" +#include "jsonwizardgeneratorfactory.h" + +#include +#include + +#include +#include +#include + +namespace ProjectExplorer { + +JsonWizard::JsonWizard(QWidget *parent) : + Utils::Wizard(parent), + m_expander(new Internal::JsonWizardExpander(this)) +{ } + +JsonWizard::~JsonWizard() +{ + qDeleteAll(m_generators); + delete m_expander; +} + +void JsonWizard::addGenerator(JsonWizardGenerator *gen) +{ + QTC_ASSERT(gen, return); + QTC_ASSERT(!m_generators.contains(gen), return); + + m_generators.append(gen); +} + +Utils::AbstractMacroExpander *JsonWizard::expander() const +{ + return m_expander; +} + +JsonWizard::GeneratorFiles JsonWizard::fileList() +{ + QString errorMessage; + GeneratorFiles list; + + QString targetPath = value(QLatin1String("TargetPath")).toString(); + if (targetPath.isEmpty()) { + errorMessage = tr("Could not determine target path. \"TargetPath\", \"Path\", or " + "\"ProjectName\" were not set on any page."); + return list; + } + + if (m_files.isEmpty()) { + emit preGenerateFiles(); + foreach (JsonWizardGenerator *gen, m_generators) { + Core::GeneratedFiles tmp = gen->fileList(m_expander, value(QStringLiteral("WizardDir")).toString(), + targetPath, &errorMessage); + if (!errorMessage.isEmpty()) + break; + list.append(Utils::transform(tmp, [&gen](const Core::GeneratedFile &f) + { return GeneratorFile(f, gen); })); + } + + if (errorMessage.isEmpty()) + m_files = list; + emit postGenerateFiles(m_files); + } + + if (!errorMessage.isEmpty()) { + QMessageBox::critical(this, tr("File Generation Failed"), + tr("The wizard failed to generate files.
" + "The error message was: \"%1\".").arg(errorMessage)); + reject(); + return GeneratorFiles(); + } + + return m_files; +} + +QVariant JsonWizard::value(const QString &n) const +{ + QVariant v = property(n.toUtf8()); + if (v.isValid()) { + if (v.type() == QVariant::String) + return Utils::expandMacros(v.toString(), m_expander); + else + return v; + } + if (hasField(n)) + return field(n); // Can not contain macros! + return QVariant(); +} + +void JsonWizard::setValue(const QString &key, const QVariant &value) +{ + setProperty(key.toUtf8(), value); +} + +bool JsonWizard::boolFromVariant(const QVariant &v, Utils::AbstractMacroExpander *expander) +{ + if (v.type() == QVariant::String) + return !Utils::expandMacros(v.toString(), expander).isEmpty(); + return v.toBool(); +} + +void JsonWizard::accept() +{ + + Utils::Wizard::accept(); + + QString errorMessage; + GeneratorFiles list = fileList(); + + if (list.isEmpty()) + return; + + emit prePromptForOverwrite(m_files); + JsonWizardGenerator::OverwriteResult overwrite = + JsonWizardGenerator::promptForOverwrite(&list, &errorMessage); + if (overwrite == JsonWizardGenerator::OverwriteError) { + if (!errorMessage.isEmpty()) + QMessageBox::warning(this, tr("Failed to Overwrite Files"), errorMessage); + return; + } + + emit preFormatFiles(m_files); + if (!JsonWizardGenerator::formatFiles(this, &list, &errorMessage)) { + if (!errorMessage.isEmpty()) + QMessageBox::warning(this, tr("Failed to Format Files"), errorMessage); + return; + } + + emit preWriteFiles(m_files); + if (!JsonWizardGenerator::writeFiles(this, &list, &errorMessage)) { + if (!errorMessage.isEmpty()) + QMessageBox::warning(this, tr("Failed to Write Files"), errorMessage); + return; + } + + emit postProcessFiles(m_files); + if (!JsonWizardGenerator::postWrite(this, &list, &errorMessage)) { + if (!errorMessage.isEmpty()) + QMessageBox::warning(this, tr("Failed to Post-Process Files"), errorMessage); + return; + } + emit filesReady(m_files); +} + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.h b/src/plugins/projectexplorer/jsonwizard/jsonwizard.h new file mode 100644 index 00000000000..ad967489eb1 --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** 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://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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 JSONWIZARD_H +#define JSONWIZARD_H + +#include "../projectexplorer_export.h" + +#include + +#include + +namespace Utils { class AbstractMacroExpander; } + +namespace ProjectExplorer { + +namespace Internal { class JsonWizardExpander; } + +class JsonWizardGenerator; + +// Documentation inside. +class PROJECTEXPLORER_EXPORT JsonWizard : public Utils::Wizard +{ + Q_OBJECT + +public: + class GeneratorFile { + public: + GeneratorFile() : generator(0) { } + GeneratorFile(const Core::GeneratedFile &f, JsonWizardGenerator *g) : + file(f), generator(g) + { } + + bool isValid() const { return generator; } + + Core::GeneratedFile file; + JsonWizardGenerator *generator; + }; + typedef QList GeneratorFiles; + Q_PROPERTY(GeneratorFiles fileList READ fileList) + + explicit JsonWizard(QWidget *parent = 0); + ~JsonWizard(); + + void addGenerator(JsonWizardGenerator *gen); + + Utils::AbstractMacroExpander *expander() const; + + GeneratorFiles fileList(); + + QVariant value(const QString &n) const; + void setValue(const QString &key, const QVariant &value); + + static bool boolFromVariant(const QVariant &v, Utils::AbstractMacroExpander *expander); + +signals: + void preGenerateFiles(); // emitted before files are generated. + void postGenerateFiles(const JsonWizard::GeneratorFiles &files); // emitted after files are generated. + void prePromptForOverwrite(const JsonWizard::GeneratorFiles &files); // emitted before overwriting checks are done. + void preFormatFiles(const JsonWizard::GeneratorFiles &files); // emitted before files are formatted. + void preWriteFiles(const JsonWizard::GeneratorFiles &files); // emitted before files are written to disk. + void postProcessFiles(const JsonWizard::GeneratorFiles &files); // emitted before files are post-processed. + void filesReady(const JsonWizard::GeneratorFiles &files); // emitted just after files are in final state on disk. + +public slots: + void accept(); + +private: + QList m_generators; + + GeneratorFiles m_files; + Internal::JsonWizardExpander *m_expander; +}; + +} // namespace ProjectExplorer + +#endif // JSONWIZARD_H diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.pri b/src/plugins/projectexplorer/jsonwizard/jsonwizard.pri new file mode 100644 index 00000000000..78b6b7dee44 --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.pri @@ -0,0 +1,11 @@ +HEADERS += $$PWD/jsonwizard.h \ + $$PWD/jsonwizardexpander.h \ + $$PWD/jsonwizardfactory.h \ + $$PWD/jsonwizardgeneratorfactory.h \ + $$PWD/jsonwizardpagefactory.h + +SOURCES += $$PWD/jsonwizard.cpp \ + $$PWD/jsonwizardexpander.cpp \ + $$PWD/jsonwizardfactory.cpp \ + $$PWD/jsonwizardgeneratorfactory.cpp \ + $$PWD/jsonwizardpagefactory.cpp diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardexpander.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardexpander.cpp new file mode 100644 index 00000000000..05423e03a6b --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardexpander.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** 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://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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 "jsonwizardexpander.h" + +#include "jsonwizard.h" + +#include + +#include + +#include + +namespace ProjectExplorer { +namespace Internal { + +// -------------------------------------------------------------------- +// JsonWizardExpander: +// -------------------------------------------------------------------- + +JsonWizardExpander::JsonWizardExpander(JsonWizard *wizard) : + m_wizard(wizard) +{ + QTC_CHECK(m_wizard); +} + +bool JsonWizardExpander::resolveMacro(const QString &name, QString *ret) +{ + QVariant v = m_wizard->value(name); + if (v.isValid()) { + *ret = v.toString(); + return true; + } + + return Core::VariableManager::macroExpander()->resolveMacro(name, ret); +} + +} // namespace Internal +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardexpander.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardexpander.h new file mode 100644 index 00000000000..7fd20d6b106 --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardexpander.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** 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://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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 JSONWIZARDEXPANDER_H +#define JSONWIZARDEXPANDER_H + +#include + +#include + +namespace ProjectExplorer { + +class JsonWizard; + +namespace Internal { + +// Documentation inside. +class JsonWizardExpander : public Utils::AbstractMacroExpander +{ +public: + explicit JsonWizardExpander(JsonWizard *wizard); + + bool resolveMacro(const QString &name, QString *ret); + +public: + JsonWizard *m_wizard; +}; + +} // namespace Internal +} // namespace ProjectExplorer + +#endif // JSONWIZARDEXPANDER_H diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp new file mode 100644 index 00000000000..a9fb7f17d96 --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -0,0 +1,604 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** 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://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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 "jsonwizardfactory.h" + +#include "jsonwizard.h" +#include "jsonwizardgeneratorfactory.h" +#include "jsonwizardpagefactory.h" + +#include "../projectexplorerconstants.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace ProjectExplorer { + +static QList s_pageFactories; +static QList s_generatorFactories; + +static const char WIZARD_PATH[] = "templates/wizards"; +static const char WIZARD_FILE[] = "wizard.json"; + +static const char VERSION_KEY[] = "version"; +static const char DISABLED_KEY[] = "disabled"; + +static const char KIND_KEY[] = "kind"; +static const char ID_KEY[] = "id"; +static const char CATEGORY_KEY[] = "category"; +static const char CATEGORY_NAME_KEY[] = "trDisplayCategory"; +static const char DISPLAY_NAME_KEY[] = "trDisplayName"; +static const char ICON_KEY[] = "icon"; +static const char DESCRIPTION_KEY[] = "trDescription"; +static const char REQUIRED_FEATURES_KEY[] = "featuresRequired"; +static const char SUGGESTED_FEATURES_KEY[] = "featuresSuggested"; +static const char GENERATOR_KEY[] = "generators"; +static const char PAGES_KEY[] = "pages"; +static const char TYPE_ID_KEY[] = "typeId"; +static const char DATA_KEY[] = "data"; +static const char PAGE_SUB_TITLE_KEY[] = "trSubTitle"; +static const char PAGE_SHORT_TITLE_KEY[] = "trShortTitle"; +static const char PAGE_INDEX_KEY[] = "index"; +static const char OPTIONS_KEY[] = "options"; +static const char PLATFORM_INDEPENDENT_KEY[] = "platformIndependent"; + +QList JsonWizardFactory::m_searchPaths + = QList() + << Utils::FileName::fromString(Core::ICore::userResourcePath() + QLatin1Char('/') + QLatin1String(WIZARD_PATH)) + << Utils::FileName::fromString(Core::ICore::resourcePath() + QLatin1Char('/') + QLatin1String(WIZARD_PATH)); + +int JsonWizardFactory::m_verbose = 0; + +// Return locale language attribute "de_UTF8" -> "de", empty string for "C" +static QString languageSetting() +{ + QString name = Core::ICore::userInterfaceLanguage(); + const int underScorePos = name.indexOf(QLatin1Char('_')); + if (underScorePos != -1) + name.truncate(underScorePos); + if (name.compare(QLatin1String("C"), Qt::CaseInsensitive) == 0) + name.clear(); + return name; +} + +template +static QString supportedTypeIds(const QList &factories) +{ + QStringList tmp; + foreach (const T*f, factories) { + foreach (Core::Id i, f->supportedIds()) + tmp.append(i.toString()); + } + return tmp.join(QLatin1String("', '")); +} + +static JsonWizardFactory::Generator parseGenerator(const QVariant &value, QString *errorMessage) +{ + JsonWizardFactory::Generator gen; + + if (value.type() != QVariant::Map) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", "Generator is not a object."); + return gen; + } + + QVariantMap data = value.toMap(); + QString strVal = data.value(QLatin1String(TYPE_ID_KEY)).toString(); + if (strVal.isEmpty()) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", "Generator has no typeId set."); + return gen; + } + Core::Id typeId = Core::Id::fromString(QLatin1String(Constants::GENERATOR_ID_PREFIX) + strVal); + JsonWizardGeneratorFactory *factory + = Utils::findOr(s_generatorFactories, 0, [typeId](JsonWizardGeneratorFactory *f) { return f->canCreate(typeId); }); + if (!factory) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", + "TypeId \"%1\" of generator is unknown. Supported typeIds are: \"%2\".") + .arg(strVal) + .arg(supportedTypeIds(s_generatorFactories).replace(QLatin1String(Constants::GENERATOR_ID_PREFIX), QLatin1String(""))); + return gen; + } + + QVariant varVal = data.value(QLatin1String(DATA_KEY)); + if (!factory->validateData(typeId, varVal, errorMessage)) + return gen; + + gen.typeId = typeId; + gen.data = varVal; + + return gen; +} + +static JsonWizardFactory::Page parsePage(const QVariant &value, QString *errorMessage) +{ + JsonWizardFactory::Page p; + + if (value.type() != QVariant::Map) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", "Page is not a object."); + return p; + } + + QVariantMap data = value.toMap(); + QString strVal = data.value(QLatin1String(TYPE_ID_KEY)).toString(); + if (strVal.isEmpty()) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", "Page has no typeId set."); + return p; + } + Core::Id typeId = Core::Id::fromString(QLatin1String(Constants::PAGE_ID_PREFIX) + strVal); + + JsonWizardPageFactory *factory + = Utils::findOr(s_pageFactories, 0, [typeId](JsonWizardPageFactory *f) { return f->canCreate(typeId); }); + if (!factory) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", + "TypeId \"%1\" of page is unknown. Supported typeIds are: \"%2\".") + .arg(strVal) + .arg(supportedTypeIds(s_pageFactories).replace(QLatin1String(Constants::PAGE_ID_PREFIX), QLatin1String(""))); + return p; + } + + QString title = JsonWizardFactory::localizedString(data.value(QLatin1String(DISPLAY_NAME_KEY))); + QString subTitle = JsonWizardFactory::localizedString(data.value(QLatin1String(PAGE_SUB_TITLE_KEY))); + QString shortTitle = JsonWizardFactory::localizedString(data.value(QLatin1String(PAGE_SHORT_TITLE_KEY))); + + bool ok; + int index = data.value(QLatin1String(PAGE_INDEX_KEY), -1).toInt(&ok); + if (!ok) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", "Page with typeId \"%1\" has invalid index.") + .arg(typeId.toString()); + return p; + } + + QVariant varVal = data.value(QLatin1String(DATA_KEY)); + if (!factory->validateData(typeId, varVal, errorMessage)) + return p; + + p.typeId = typeId; + p.title = title; + p.subTitle = subTitle; + p.shortTitle = shortTitle; + p.index = index; + p.data = varVal; + + return p; +} + +QList JsonWizardFactory::createWizardFactories() +{ + QString errorMessage; + QString verboseLog; + const QString wizardFileName = QLatin1String(WIZARD_FILE); + + QList result; + foreach (const Utils::FileName &path, m_searchPaths) { + if (path.isEmpty()) + continue; + + QDir dir(path.toString()); + if (!dir.exists()) { + if (verbose()) + verboseLog.append(tr("Path \"%1\" does not exist when checking Json wizard search paths.\n") + .arg(path.toUserOutput())); + continue; + } + + const QDir::Filters filters = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot; + const QDir::SortFlags sortflags = QDir::Name|QDir::IgnoreCase; + QList dirs = dir.entryInfoList(filters, sortflags); + + while (!dirs.isEmpty()) { + const QFileInfo dirFi = dirs.takeFirst(); + const QDir current(dirFi.absoluteFilePath()); + if (verbose()) + verboseLog.append(tr("Checking \"%1\" for %2.\n") + .arg(QDir::toNativeSeparators(current.absolutePath())) + .arg(wizardFileName)); + if (current.exists(wizardFileName)) { + QFile configFile(current.absoluteFilePath(wizardFileName)); + configFile.open(QIODevice::ReadOnly); + QJsonParseError error; + QByteArray fileData = configFile.readAll(); + QJsonDocument json = QJsonDocument::fromJson(fileData, &error); + configFile.close(); + + if (error.error != QJsonParseError::NoError) { + int line = 1; + int column = 1; + for (int i = 0; i < error.offset; ++i) { + if (fileData.at(i) == '\n') { + ++line; + column = 1; + } else { + ++column; + } + } + verboseLog.append(tr("* Failed to parse \"%1\":%2:%3: %4\n") + .arg(configFile.fileName()) + .arg(line).arg(column) + .arg(error.errorString())); + continue; + } + + if (!json.isObject()) { + verboseLog.append(tr("* Did not find a JSON object in \"%1\".\n") + .arg(configFile.fileName())); + continue; + } + + if (verbose()) + verboseLog.append(tr("* Configuration found and parsed.\n")); + + QVariantMap data = json.object().toVariantMap(); + + int version = data.value(QLatin1String(VERSION_KEY), 0).toInt(); + if (version < 1 || version > 1) { + verboseLog.append(tr("* Version %1 not supported.\n").arg(version)); + continue; + } + + bool isDisabled = data.value(QLatin1String(DISABLED_KEY), false).toBool(); + if (isDisabled) { + verboseLog.append(tr("* Wizard is disabled.\n")); + continue; + } + + JsonWizardFactory *factory = createWizardFactory(data, current, &errorMessage); + if (!factory) { + verboseLog.append(tr("* Failed to create: %1\n").arg(errorMessage)); + continue; + } + + result << factory; + } else { + QList subDirs = current.entryInfoList(filters, sortflags); + if (!subDirs.isEmpty()) { + // There is no QList::prepend(QList)... + dirs.swap(subDirs); + dirs.append(subDirs); + } else if (verbose()) { + verboseLog.append(tr("JsonWizard: \"%1\" not found\n").arg(wizardFileName)); + } + } + } + } + + if (verbose()) { // Print to output pane for Windows. + qWarning("%s", qPrintable(verboseLog)); + Core::MessageManager::write(verboseLog, Core::MessageManager::ModeSwitch); + } + + return result; +} + +JsonWizardFactory *JsonWizardFactory::createWizardFactory(const QVariantMap &data, const QDir &baseDir, + QString *errorMessage) +{ + JsonWizardFactory *factory = new JsonWizardFactory; + if (!factory->initialize(data, baseDir, errorMessage)) { + delete factory; + factory = 0; + } + return factory; +} + +void JsonWizardFactory::addWizardPath(const Utils::FileName &path) +{ + m_searchPaths.append(path); +} + +void JsonWizardFactory::setVerbose(int level) +{ + m_verbose = level; +} + +int JsonWizardFactory::verbose() +{ + return m_verbose; +} + +void JsonWizardFactory::registerPageFactory(JsonWizardPageFactory *factory) +{ + QTC_ASSERT(!s_pageFactories.contains(factory), return); + s_pageFactories.append(factory); +} + +void JsonWizardFactory::registerGeneratorFactory(JsonWizardGeneratorFactory *factory) +{ + QTC_ASSERT(!s_generatorFactories.contains(factory), return); + s_generatorFactories.append(factory); +} + +JsonWizardFactory::~JsonWizardFactory() +{ } + +void JsonWizardFactory::runWizard(const QString &path, QWidget *parent, const QString &platform, + const QVariantMap &variables) +{ + JsonWizard wizard(parent); + wizard.setWindowIcon(icon()); + + wizard.setValue(QStringLiteral("WizardDir"), m_wizardDir); + Core::FeatureSet tmp = requiredFeatures(); + tmp.remove(pluginFeatures()); + wizard.setValue(QStringLiteral("RequiredFeatures"), tmp.toStringList()); + tmp = m_preferredFeatures; + tmp.remove(pluginFeatures()); + wizard.setValue(QStringLiteral("PreferredFeatures"), tmp.toStringList()); + + // Add data to wizard: + for (auto i = variables.constBegin(); i != variables.constEnd(); ++i) + wizard.setProperty(i.key().toUtf8(), i.value()); + + wizard.setValue(QStringLiteral("GivenPath"), path); + wizard.setValue(QStringLiteral("Platform"), platform); + + QString kindStr = QLatin1String(Core::Constants::WIZARD_KIND_UNKNOWN); + if (kind() == IWizardFactory::FileWizard) + kindStr = QLatin1String(Core::Constants::WIZARD_KIND_FILE); + else if (kind() == IWizardFactory::ClassWizard) + kindStr = QLatin1String(Core::Constants::WIZARD_KIND_CLASS); + else if (kind() == IWizardFactory::ProjectWizard) + kindStr = QLatin1String(Core::Constants::WIZARD_KIND_PROJECT); + wizard.setValue(QStringLiteral("kind"), kindStr); + + for (auto i = m_options.constBegin(); i != m_options.constEnd(); ++i) + wizard.setValue(i.key(), i.value()); + + foreach (const Page &data, m_pages) { + QTC_ASSERT(data.isValid(), continue); + JsonWizardPageFactory *factory = Utils::findOr(s_pageFactories, 0, + [&data](JsonWizardPageFactory *f) { + return f->canCreate(data.typeId); + }); + QTC_ASSERT(factory, continue); + Utils::WizardPage *page = factory->create(&wizard, data.typeId, data.data); + QTC_ASSERT(page, continue); + + page->setTitle(data.title); + page->setSubTitle(data.subTitle); + page->setProperty(Utils::SHORT_TITLE_PROPERTY, data.shortTitle); + + if (data.index >= 0) { + wizard.setPage(data.index, page); + if (wizard.page(data.index) != page) // Failed to set page! + delete page; + } else { + wizard.addPage(page); + } + } + + foreach (const Generator &data, m_generators) { + QTC_ASSERT(data.isValid(), continue); + JsonWizardGeneratorFactory *factory = Utils::findOr(s_generatorFactories, 0, + [&data](JsonWizardGeneratorFactory *f) { + return f->canCreate(data.typeId); + }); + QTC_ASSERT(factory, continue); + JsonWizardGenerator *gen = factory->create(data.typeId, data.data, path, platform, variables); + QTC_ASSERT(gen, continue); + + wizard.addGenerator(gen); + } + + if (!m_pages.isEmpty()) + wizard.exec(); + else + wizard.accept(); +} + +QList JsonWizardFactory::objectOrList(const QVariant &data, QString *errorMessage) +{ + QList result; + if (data.type() == QVariant::Map) + result.append(data); + else if (data.type() == QVariant::List) + result = data.toList(); + else + *errorMessage = tr("Expected an object or a list."); + return result; +} + +QString JsonWizardFactory::localizedString(const QVariant &value) +{ + if (value.isNull()) + return QString(); + if (value.type() == QVariant::Map) { + QVariantMap tmp = value.toMap(); + const QString locale = languageSetting().toLower(); + QStringList locales; + locales << locale << QLatin1String("en") << QLatin1String("C") << tmp.keys(); + foreach (const QString &locale, locales) { + QString result = tmp.value(locale, QString()).toString(); + if (!result.isEmpty()) + return result; + } + return QString(); + } + return QCoreApplication::translate("ProjectExplorer::JsonWizardFactory", value.toByteArray()); + +} + +void JsonWizardFactory::destroyAllFactories() +{ + qDeleteAll(s_pageFactories); + s_pageFactories.clear(); + qDeleteAll(s_generatorFactories); + s_generatorFactories.clear(); +} + +bool JsonWizardFactory::initialize(const QVariantMap &data, const QDir &baseDir, QString *errorMessage) +{ + QTC_ASSERT(errorMessage, return false); + + errorMessage->clear(); + + m_wizardDir = baseDir.absolutePath(); + + QString strVal = data.value(QLatin1String(KIND_KEY)).toString(); + if (strVal != QLatin1String("class") + && strVal != QLatin1String("file") + && strVal != QLatin1String("project")) { + *errorMessage = tr("\"kind\" value \"%1\" is not \"class\", \"file\" or \"project\".").arg(strVal); + return false; + } + IWizardFactory::WizardKind kind = IWizardFactory::ProjectWizard; + if (strVal == QLatin1String("class")) + kind = IWizardFactory::ClassWizard; + if (strVal == QLatin1String("file")) + kind = IWizardFactory::FileWizard; + setWizardKind(kind); + + strVal = data.value(QLatin1String(ID_KEY)).toString(); + if (strVal.isEmpty()) { + *errorMessage = tr("No id set."); + return false; + } + setId(strVal); + + strVal = data.value(QLatin1String(CATEGORY_KEY)).toString(); + if (strVal.isEmpty()) { + *errorMessage = tr("No category is set."); + return false; + } + setCategory(strVal); + + strVal = data.value(QLatin1String(ICON_KEY)).toString(); + if (!strVal.isEmpty()) { + strVal = baseDir.absoluteFilePath(strVal); + if (!QFileInfo(strVal).exists()) { + *errorMessage = tr("Icon \"%1\" not found.").arg(strVal); + return false; + } + setIcon(QIcon(strVal)); + } + + setRequiredFeatures(Core::FeatureSet::fromStringList(data.value(QLatin1String(REQUIRED_FEATURES_KEY)).toStringList())); + m_preferredFeatures = Core::FeatureSet::fromStringList(data.value(QLatin1String(SUGGESTED_FEATURES_KEY)).toStringList()); + m_preferredFeatures |= requiredFeatures(); + + strVal = localizedString(data.value(QLatin1String(DISPLAY_NAME_KEY))); + if (strVal.isEmpty()) { + *errorMessage = tr("No displayName set."); + return false; + } + setDisplayName(strVal); + + strVal = localizedString(data.value(QLatin1String(CATEGORY_NAME_KEY))); + if (strVal.isEmpty()) { + *errorMessage = tr("No displayCategory set."); + return false; + } + setDisplayCategory(strVal); + + strVal = localizedString(data.value(QLatin1String(DESCRIPTION_KEY))); + if (strVal.isEmpty()) { + *errorMessage = tr("No description set."); + return false; + } + setDescription(strVal); + + // Generator: + QVariantList list = objectOrList(data.value(QLatin1String(GENERATOR_KEY)), errorMessage); + if (list.isEmpty()) { + *errorMessage = tr("When parsing \"generators\": %1").arg(*errorMessage); + return false; + } + + foreach (const QVariant &v, list) { + Generator gen = parseGenerator(v, errorMessage); + if (gen.isValid()) + m_generators.append(gen); + else + return false; + } + + // Pages: + list = objectOrList(data.value(QLatin1String(PAGES_KEY)), errorMessage); + if (!errorMessage->isEmpty()) { + *errorMessage = tr("When parsing \"pages\": %1").arg(*errorMessage); + return false; + } + + foreach (const QVariant &v, list) { + Page p = parsePage(v, errorMessage); + if (p.isValid()) + m_pages.append(p); + else + return false; + } + + WizardFlags flags = 0; + if (data.value(QLatin1String(PLATFORM_INDEPENDENT_KEY), false).toBool()) + flags |= PlatformIndependent; + setFlags(flags); + + // Options: + QVariant optionValue = data.value(QLatin1String(OPTIONS_KEY)); + if (optionValue.type() == QVariant::List) { + foreach (const QVariant &v, optionValue.toList()) { + if (v.type() != QVariant::Map) { + *errorMessage = tr("List element of \"options\" is not an object."); + return false; + } + QVariantMap data = v.toMap(); + const QString key = data.value(QStringLiteral("key"), QString()).toString(); + const QString value = data.value(QStringLiteral("value"), QString()).toString(); + if (key.isEmpty()) { + *errorMessage = tr("No \"key\" given for entry in \"options\"."); + return false; + } + if (m_options.contains(key)) { + *errorMessage = tr("When parsing \"options\": Key \"%1\" set more than once.").arg(key); + return false; + } + m_options.insert(key, value); + } + } else if (optionValue.isValid()) { + *errorMessage = tr("Value for \"options\" is not a list"); + return false; + } + + return true; +} + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h new file mode 100644 index 00000000000..27b9d185e95 --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** 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://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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 JSONWIZARDFACTORY_H +#define JSONWIZARDFACTORY_H + +#include "../projectexplorer_export.h" + +#include + +#include + +#include + +QT_BEGIN_NAMESPACE +class QDir; +QT_END_NAMESPACE + +namespace ProjectExplorer { + +class JsonWizardFactory; +class JsonWizardPageFactory; +class JsonWizardGeneratorFactory; +class ProjectExplorerPlugin; + +// Documentation inside. +class PROJECTEXPLORER_EXPORT JsonWizardFactory : public Core::IWizardFactory +{ + Q_OBJECT + +public: + // Add search paths for wizard.json files. All subdirs are going to be checked. + static void addWizardPath(const Utils::FileName &path); + + // actual interface of the wizard factory: + class Generator { + public: + bool isValid() const { return typeId.isValid(); } + + Core::Id typeId; + QVariant data; + }; + + class Page { + public: + bool isValid() const { return typeId.isValid(); } + QString title; + QString subTitle; + QString shortTitle; + int index; // page index in the wizard + Core::Id typeId; + QVariant data; + }; + + static void registerPageFactory(JsonWizardPageFactory *factory); + static void registerGeneratorFactory(JsonWizardGeneratorFactory *factory); + + ~JsonWizardFactory(); + + void runWizard(const QString &path, QWidget *parent, const QString &platform, + const QVariantMap &variables); + + static QList objectOrList(const QVariant &data, QString *errorMessage); + static QString localizedString(const QVariant &value); + +private: + // Create all wizards. As other plugins might register factories for derived + // classes. Called when the new file dialog is shown for the first time. + static QList createWizardFactories(); + static JsonWizardFactory *createWizardFactory(const QVariantMap &data, const QDir &baseDir, + QString *errorMessage); + + static void setVerbose(int level); + static int verbose(); + + static void destroyAllFactories(); + bool initialize(const QVariantMap &data, const QDir &baseDir, QString *errorMessage); + + QString m_wizardDir; + QList m_generators; + + QList m_pages; + QMap m_options; + + Core::FeatureSet m_preferredFeatures; + + static QList m_searchPaths; + static int m_verbose; + + friend class ProjectExplorerPlugin; +}; + +} //namespace ProjectExplorer + +#endif // JSONWIZARDFACTORY_H diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp new file mode 100644 index 00000000000..7cb1af98c19 --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** 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://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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 "jsonwizardgeneratorfactory.h" + +#include "jsonwizard.h" + +#include "../projectexplorerconstants.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace ProjectExplorer { + +// -------------------------------------------------------------------- +// JsonWizardGenerator: +// -------------------------------------------------------------------- + +JsonWizardGenerator::OverwriteResult JsonWizardGenerator::promptForOverwrite(JsonWizard::GeneratorFiles *files, + QString *errorMessage) +{ + QStringList existingFiles; + bool oddStuffFound = false; + + foreach (const JsonWizard::GeneratorFile &f, *files) { + const QFileInfo fi(f.file.path()); + if (fi.exists() && !(f.file.attributes() & Core::GeneratedFile::ForceOverwrite)) + existingFiles.append(f.file.path()); + } + if (existingFiles.isEmpty()) + return OverwriteOk; + + // Before prompting to overwrite existing files, loop over files and check + // if there is anything blocking overwriting them (like them being links or folders). + // Format a file list message as ( " [readonly], [folder]"). + const QString commonExistingPath = Utils::commonPath(existingFiles); + QString fileNamesMsgPart; + foreach (const QString &fileName, existingFiles) { + const QFileInfo fi(fileName); + if (fi.exists()) { + if (!fileNamesMsgPart.isEmpty()) + fileNamesMsgPart += QLatin1String(", "); + const QString namePart = QDir::toNativeSeparators(fileName.mid(commonExistingPath.size() + 1)); + if (fi.isDir()) { + oddStuffFound = true; + fileNamesMsgPart += QCoreApplication::translate("ProjectExplorer::JsonWizardGenerator", "%1 [folder]") + .arg(namePart); + } else if (fi.isSymLink()) { + oddStuffFound = true; + fileNamesMsgPart += QCoreApplication::translate("ProjectExplorer::JsonWizardGenerator", "%1 [symbolic link]") + .arg(namePart); + } else if (!fi.isWritable()) { + oddStuffFound = true; + fileNamesMsgPart += QCoreApplication::translate("ProjectExplorer::JsonWizardGenerator", "%1 [read only]") + .arg(namePart); + } + } + } + + if (oddStuffFound) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizardGenerator", + "The directory %1 contains files which cannot be overwritten:\n%2.") + .arg(QDir::toNativeSeparators(commonExistingPath)).arg(fileNamesMsgPart); + return OverwriteError; + } + + // Prompt to overwrite existing files. + Core::PromptOverwriteDialog overwriteDialog; + + // Scripts cannot handle overwrite + overwriteDialog.setFiles(existingFiles); + foreach (const JsonWizard::GeneratorFile &file, *files) + if (!file.generator->canKeepExistingFiles()) + overwriteDialog.setFileEnabled(file.file.path(), false); + if (overwriteDialog.exec() != QDialog::Accepted) + return OverwriteCanceled; + + const QStringList existingFilesToKeep = overwriteDialog.uncheckedFiles(); + if (existingFilesToKeep.size() == files->size()) // All exist & all unchecked->Cancel. + return OverwriteCanceled; + + // Set 'keep' attribute in files + foreach (const QString &keepFile, existingFilesToKeep) { + JsonWizard::GeneratorFile file + = Utils::findOr(*files, JsonWizard::GeneratorFile(), + [&keepFile](const JsonWizard::GeneratorFile &f) + { return f.file.path() == keepFile; }); + if (!file.isValid()) + return OverwriteCanceled; + file.file.setAttributes(file.file.attributes() | Core::GeneratedFile::KeepExistingFileAttribute); + } + return OverwriteOk; +} + +bool JsonWizardGenerator::formatFiles(const JsonWizard *wizard, JsonWizard::GeneratorFiles *files, QString *errorMessage) +{ + for (auto i = files->begin(); i != files->end(); ++i) { + if (!i->generator->formatFile(wizard, &(i->file), errorMessage)) + return false; + } + return true; +} + +bool JsonWizardGenerator::writeFiles(const JsonWizard *wizard, JsonWizard::GeneratorFiles *files, QString *errorMessage) +{ + for (auto i = files->begin(); i != files->end(); ++i) { + if (!i->generator->writeFile(wizard, &(i->file), errorMessage)) + return false; + } + return true; +} + +bool JsonWizardGenerator::postWrite(const JsonWizard *wizard, JsonWizard::GeneratorFiles *files, QString *errorMessage) +{ + for (auto i = files->begin(); i != files->end(); ++i) { + if (!i->generator->postWrite(wizard, &(i->file), errorMessage)) + return false; + } + return true; +} + +// -------------------------------------------------------------------- +// JsonWizardGeneratorFactory: +// -------------------------------------------------------------------- + +void JsonWizardGeneratorFactory::setTypeIdsSuffixes(const QStringList &suffixes) +{ + m_typeIds = Utils::transform(suffixes, [](QString suffix) + { return Core::Id::fromString(QString::fromLatin1(Constants::GENERATOR_ID_PREFIX) + suffix); }); +} + +void JsonWizardGeneratorFactory::setTypeIdsSuffix(const QString &suffix) +{ + setTypeIdsSuffixes(QStringList() << suffix); +} + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.h new file mode 100644 index 00000000000..d043237ec4d --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** 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://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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 JSONWIZARDGENERATORFACTORY_H +#define JSONWIZARDGENERATORFACTORY_H + +#include "../projectexplorer_export.h" + +#include "jsonwizard.h" + +#include + +#include +#include + +namespace Utils { class AbstractMacroExpander; } + +namespace ProjectExplorer { + +class JsonWizardGenerator +{ +public: + virtual ~JsonWizardGenerator() { } + + virtual Core::GeneratedFiles fileList(Utils::AbstractMacroExpander *expander, + const QString &baseDir, const QString &projectDir, + QString *errorMessage) = 0; + virtual bool formatFile(const JsonWizard *wizard, Core::GeneratedFile *file, QString *errorMessage) = 0; + virtual bool writeFile(const JsonWizard *wizard, Core::GeneratedFile *file, QString *errorMessage) = 0; + virtual bool postWrite(const JsonWizard *wizard, Core::GeneratedFile *file, QString *errorMessage) = 0; + + virtual bool canKeepExistingFiles() const { return true; } + + enum OverwriteResult { OverwriteOk, OverwriteError, OverwriteCanceled }; + static OverwriteResult promptForOverwrite(JsonWizard::GeneratorFiles *files, QString *errorMessage); + + static bool formatFiles(const JsonWizard *wizard, QList *files, QString *errorMessage); + static bool writeFiles(const JsonWizard *wizard, JsonWizard::GeneratorFiles *files, QString *errorMessage); + static bool postWrite(const JsonWizard *wizard, JsonWizard::GeneratorFiles *files, QString *errorMessage); +}; + +class JsonWizardGeneratorFactory : public QObject +{ + Q_OBJECT + +public: + bool canCreate(Core::Id typeId) const { return m_typeIds.contains(typeId); } + QList supportedIds() const { return m_typeIds; } + + virtual JsonWizardGenerator *create(Core::Id typeId, const QVariant &data, + const QString &path, const QString &platform, + const QVariantMap &variables) = 0; + + // Basic syntax check for the data taken from the wizard.json file: + virtual bool validateData(Core::Id typeId, const QVariant &data, QString *errorMessage) = 0; + +protected: + // This will add "PE.Wizard.Generator." in front of the suffixes and set those as supported typeIds + void setTypeIdsSuffixes(const QStringList &suffixes); + void setTypeIdsSuffix(const QString &suffix); + +private: + QList m_typeIds; +}; + +} // namespace ProjectExplorer + +#endif // JSONWIZARDGENERATORFACTORY_H diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory.cpp new file mode 100644 index 00000000000..ddf0a23d3e4 --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** 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://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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 "jsonwizardpagefactory.h" + +#include "../projectexplorerconstants.h" + +#include + +namespace ProjectExplorer { + +// -------------------------------------------------------------------- +// JsonWizardPageFactory: +// -------------------------------------------------------------------- + +void JsonWizardPageFactory::setTypeIdsSuffixes(const QStringList &suffixes) +{ + m_typeIds = Utils::transform(suffixes, [](const QString &suffix) { + return Core::Id::fromString(QString::fromLatin1(Constants::PAGE_ID_PREFIX) + suffix);}); +} + +void JsonWizardPageFactory::setTypeIdsSuffix(const QString &suffix) +{ + setTypeIdsSuffixes(QStringList() << suffix); +} + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory.h new file mode 100644 index 00000000000..b2042935139 --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** 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://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: 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 JSONWIZARDPAGEFACTORY_H +#define JSONWIZARDPAGEFACTORY_H + +#include "../projectexplorer_export.h" + +#include + +#include +#include + +namespace Utils { class WizardPage; } + +namespace ProjectExplorer { +class JsonWizard; + +class PROJECTEXPLORER_EXPORT JsonWizardPageFactory +{ +public: + virtual ~JsonWizardPageFactory() { } + + bool canCreate(Core::Id typeId) const { return m_typeIds.contains(typeId); } + QList supportedIds() const { return m_typeIds; } + + virtual Utils::WizardPage *create(JsonWizard *wizard, Core::Id typeId, const QVariant &data) = 0; + + // Basic syntax check for the data taken from the wizard.json file: + virtual bool validateData(Core::Id typeId, const QVariant &data, QString *errorMessage) = 0; + +protected: + // This will add "PE.Wizard.Page." in front of the suffixes and set those as supported typeIds + void setTypeIdsSuffixes(const QStringList &suffixes); + void setTypeIdsSuffix(const QString &suffix); + +private: + QList m_typeIds; +}; + +} // namespace ProjectExplorer + +#endif // JSONWIZARDPAGEFACTORY_H diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index f70123b286b..50d2745faef 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -35,6 +35,8 @@ #include "deployablefile.h" #include "deployconfiguration.h" #include "gcctoolchainfactories.h" +#include "jsonwizard/jsonwizardexpander.h" +#include "jsonwizard/jsonwizardfactory.h" #include "project.h" #include "projectexplorersettings.h" #include "projectmacroexpander.h" @@ -313,6 +315,9 @@ ProjectExplorerPlugin::~ProjectExplorerPlugin() { removeObject(d->m_welcomePage); delete d->m_welcomePage; + + JsonWizardFactory::destroyAllFactories(); + removeObject(this); // Force sequence of deletion: delete d->m_kitManager; // remove all the profile informations @@ -329,6 +334,7 @@ ProjectExplorerPlugin *ProjectExplorerPlugin::instance() bool ProjectExplorerPlugin::parseArguments(const QStringList &arguments, QString * /* error */) { CustomWizard::setVerbose(arguments.count(QLatin1String("-customwizard-verbose"))); + JsonWizardFactory::setVerbose(arguments.count(QLatin1String("-customwizard-verbose"))); return true; } @@ -1314,6 +1320,8 @@ void ProjectExplorerPlugin::loadCustomWizards() firstTime = false; foreach (IWizardFactory *cpw, ProjectExplorer::CustomWizard::createWizards()) addAutoReleasedObject(cpw); + foreach (IWizardFactory *cpw, JsonWizardFactory::createWizardFactories()) + addAutoReleasedObject(cpw); } } diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index 5fae1cab7da..712a3197256 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -2,6 +2,7 @@ QT += quick script xml include(../../qtcreatorplugin.pri) include(customwizard/customwizard.pri) +include(jsonwizard/jsonwizard.pri) HEADERS += projectexplorer.h \ abi.h \ abiwidget.h \ diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index d0aaac3d219..562287542d3 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -166,6 +166,18 @@ QtcPlugin { ] } + Group { + name: "JsonWizard" + prefix: "jsonwizard/" + files: [ + "jsonwizard.cpp", "jsonwizard.h", + "jsonwizardexpander.cpp", "jsonwizardexpander.h", + "jsonwizardfactory.cpp", "jsonwizardfactory.h", + "jsonwizardgeneratorfactory.cpp", "jsonwizardgeneratorfactory.h", + "jsonwizardpagefactory.cpp", "jsonwizardpagefactory.h" + ] + } + Group { name: "CustomWizard" prefix: "customwizard/" diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 60f7fd54a9b..70fc05920c8 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -260,6 +260,10 @@ const char HIDE_FILE_FILTER_DEFAULT[] = "Makefile*; *.o; *.lo; *.la; *.obj; *~; const char SHOW_FILE_FILTER_SETTING[] = "GenericProject/ShowFileFilter"; const char SHOW_FILE_FILTER_DEFAULT[] = "*.c; *.cc; *.cpp; *.cp; *.cxx; *.c++; *.h; *.hh; *.hpp; *.hxx;"; +// JsonWizard: +const char PAGE_ID_PREFIX[] = "PE.Wizard.Page."; +const char GENERATOR_ID_PREFIX[] = "PE.Wizard.Generator."; + } // namespace Constants // Run modes