diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp new file mode 100644 index 00000000000..46d6866feb6 --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp @@ -0,0 +1,798 @@ +/**************************************************************************** +** +** 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 "jsonfieldpage.h" + +#include "jsonwizard.h" +#include "jsonwizardexpander.h" +#include "jsonwizardfactory.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const char NAME_KEY[] = "name"; +static const char DISPLAY_NAME_KEY[] = "trDisplayName"; +static const char MANDATORY_KEY[] = "mandatory"; +static const char VISIBLE_KEY[] = "visible"; +static const char ENABLED_KEY[] = "enabled"; +static const char SPAN_KEY[] = "span"; +static const char TYPE_KEY[] = "type"; +static const char DATA_KEY[] = "data"; + + +namespace ProjectExplorer { + +// -------------------------------------------------------------------- +// Helper: +// -------------------------------------------------------------------- + +static JsonFieldPage::Field *createFieldData(const QString &type) +{ + if (type == QLatin1String("Label")) + return new JsonFieldPage::LabelField; + else if (type == QLatin1String("Spacer")) + return new JsonFieldPage::SpacerField; + else if (type == QLatin1String("LineEdit")) + return new JsonFieldPage::LineEditField; + else if (type == QLatin1String("TextEdit")) + return new JsonFieldPage::TextEditField; + else if (type == QLatin1String("PathChooser")) + return new JsonFieldPage::PathChooserField; + else if (type == QLatin1String("CheckBox")) + return new JsonFieldPage::CheckBoxField; + else if (type == QLatin1String("ComboBox")) + return new JsonFieldPage::ComboBoxField; + return 0; +} + +// -------------------------------------------------------------------- +// JsonFieldPage::FieldData: +// -------------------------------------------------------------------- + +JsonFieldPage::Field *JsonFieldPage::Field::parse(const QVariant &input, QString *errorMessage) +{ + if (input.type() != QVariant::Map) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "Field is not an object."); + return 0; + } + + QVariantMap tmp = input.toMap(); + const QString name = tmp.value(QLatin1String(NAME_KEY)).toString(); + if (name.isEmpty()) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "Field has no name."); + return 0; + } + const QString type = tmp.value(QLatin1String(TYPE_KEY)).toString(); + if (type.isEmpty()) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "Field '%1' has no type.").arg(name); + return 0; + } + + Field *data = createFieldData(type); + if (!data) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "Field '%1' has unsupported type '%2'.") + .arg(name).arg(type); + return 0; + } + data->name = name; + + data->m_visibleExpression = tmp.value(QLatin1String(VISIBLE_KEY), true); + data->m_enabledExpression = tmp.value(QLatin1String(ENABLED_KEY), true); + data->mandatory = tmp.value(QLatin1String(MANDATORY_KEY), true).toBool(); + data->span = tmp.value(QLatin1String(SPAN_KEY), false).toBool(); + + data->displayName = JsonWizardFactory::localizedString(tmp.value(QLatin1String(DISPLAY_NAME_KEY)).toString()); + + QVariant dataVal = tmp.value(QLatin1String(DATA_KEY)); + if (!data->parseData(dataVal, errorMessage)) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "When parsing Field '%1': %2") + .arg(name).arg(*errorMessage); + delete data; + return 0; + } + + return data; +} + +void JsonFieldPage::Field::createWidget(JsonFieldPage *page) +{ + QWidget *w = widget(displayName); + w->setObjectName(name); + QFormLayout *layout = page->layout(); + + if (suppressName()) + layout->addWidget(w); + else if (span) + layout->addRow(w); + else + layout->addRow(displayName, w); + + setup(page, name); +} + +void JsonFieldPage::Field::adjustState(Utils::AbstractMacroExpander *expander) +{ + setVisible(JsonWizard::boolFromVariant(m_visibleExpression, expander)); + setEnabled(JsonWizard::boolFromVariant(m_enabledExpression, expander)); +} + +void JsonFieldPage::Field::initialize(Utils::AbstractMacroExpander *expander) +{ + adjustState(expander); + initializeData(expander); +} + +// -------------------------------------------------------------------- +// JsonFieldPage::LabelFieldData: +// -------------------------------------------------------------------- + +JsonFieldPage::LabelField::LabelField() : + m_wordWrap(false) +{ } + +bool JsonFieldPage::LabelField::parseData(const QVariant &data, QString *errorMessage) +{ + if (data.type() != QVariant::Map) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "Label data is not an object."); + return false; + } + + QVariantMap tmp = data.toMap(); + + m_wordWrap = tmp.value(QLatin1String("wordWrap"), false).toBool(); + m_text = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trText"))); + + if (m_text.isEmpty()) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "No text given for Label."); + return false; + } + + return true; +} + +QWidget *JsonFieldPage::LabelField::widget(const QString &displayName) +{ + Q_UNUSED(displayName); + QTC_ASSERT(!m_widget, return m_widget); + + QLabel *w = new QLabel(); + w->setWordWrap(m_wordWrap); + w->setText(m_text); + + m_widget = w; + return m_widget; +} + +// -------------------------------------------------------------------- +// JsonFieldPage::SpacerFieldData: +// -------------------------------------------------------------------- + +JsonFieldPage::SpacerField::SpacerField() : + m_factor(2) +{ } + +bool JsonFieldPage::SpacerField::parseData(const QVariant &data, QString *errorMessage) +{ + if (data.isNull()) + return true; + + if (data.type() != QVariant::Map) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "Spacer data is not an object."); + return false; + } + + QVariantMap tmp = data.toMap(); + + bool ok; + m_factor = tmp.value(QLatin1String("factor"), 2).toInt(&ok); + + if (!ok) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "'size' was not an integer value."); + return false; + } + + return true; +} + +QWidget *JsonFieldPage::SpacerField::widget(const QString &displayName) +{ + Q_UNUSED(displayName); + QTC_ASSERT(!m_widget, return m_widget); + + int size = m_widget->style()->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, + Qt::Vertical) * m_factor; + m_widget = new QWidget(); + m_widget->setMinimumSize(size, size); + m_widget->setMaximumSize(size, size); + m_widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + return m_widget; +} + +// -------------------------------------------------------------------- +// JsonFieldPage::LineEditFieldData: +// -------------------------------------------------------------------- + +JsonFieldPage::LineEditField::LineEditField() : + m_isModified(false) +{ } + +bool JsonFieldPage::LineEditField::parseData(const QVariant &data, QString *errorMessage) +{ + if (data.isNull()) + return true; + + if (data.type() != QVariant::Map) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "LineEdit data is not an object."); + return false; + } + + QVariantMap tmp = data.toMap(); + + m_defaultText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trText")).toString()); + m_disabledText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trDisabledText")).toString()); + m_placeholderText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trPlaceholder")).toString()); + + return true; +} + +QWidget *JsonFieldPage::LineEditField::widget(const QString &displayName) +{ + Q_UNUSED(displayName); + QTC_ASSERT(!m_widget, return m_widget); + QLineEdit *w = new QLineEdit; + connect(w, &QLineEdit::textEdited, [this](){ m_isModified = true; }); + + m_widget = w; + return m_widget; +} + +void JsonFieldPage::LineEditField::setup(JsonFieldPage *page, const QString &name) +{ + QLineEdit *w = static_cast(m_widget); + page->registerFieldWithName(name, w); + connect(w, &QLineEdit::textChanged, page, [page](QString) { page->completeChanged(); }); +} + +bool JsonFieldPage::LineEditField::validate(Utils::AbstractMacroExpander *expander, QString *message) +{ + Q_UNUSED(message); + QLineEdit *w = static_cast(m_widget); + + if (!m_isModified) + w->setText(Utils::expandMacros(m_defaultText, expander)); + + if (!w->isEnabled() && !m_disabledText.isNull() && m_currentText.isNull()) { + m_currentText = w->text(); + w->setText(Utils::expandMacros(m_disabledText, expander)); + } else if (w->isEnabled() && !m_currentText.isNull()) { + w->setText(m_currentText); + m_currentText.clear(); + } + + // TODO: Add support for validators + return !w->text().isEmpty(); +} + +void JsonFieldPage::LineEditField::initializeData(Utils::AbstractMacroExpander *expander) +{ + QTC_ASSERT(m_widget, return); + + m_isModified = false; + + QLineEdit *w = static_cast(m_widget); + w->setText(Utils::expandMacros(m_defaultText, expander)); + w->setPlaceholderText(m_placeholderText); +} + +// -------------------------------------------------------------------- +// JsonFieldPage::TextEditFieldData: +// -------------------------------------------------------------------- + + +JsonFieldPage::TextEditField::TextEditField() : + m_acceptRichText(false) +{ } + +bool JsonFieldPage::TextEditField::parseData(const QVariant &data, QString *errorMessage) +{ + if (data.isNull()) + return true; + + if (data.type() != QVariant::Map) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "TextEdit data is not an object."); + return false; + } + + QVariantMap tmp = data.toMap(); + + m_defaultText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trText")).toString()); + m_disabledText = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trDisabledText")).toString()); + m_acceptRichText = tmp.value(QLatin1String("richText"), true).toBool(); + + return true; +} + +QWidget *JsonFieldPage::TextEditField::widget(const QString &displayName) +{ + // TODO: Set up modification monitoring... + Q_UNUSED(displayName); + QTC_ASSERT(!m_widget, return m_widget); + QTextEdit *w = new QTextEdit; + w->setAcceptRichText(m_acceptRichText); + m_widget = w; + return m_widget; +} + +void JsonFieldPage::TextEditField::setup(JsonFieldPage *page, const QString &name) +{ + QTextEdit *w = static_cast(m_widget); + page->registerFieldWithName(name, w, "plainText", SIGNAL(textChanged())); + connect(w, &QTextEdit::textChanged, page, &QWizardPage::completeChanged); +} + +bool JsonFieldPage::TextEditField::validate(Utils::AbstractMacroExpander *expander, QString *message) +{ + Q_UNUSED(expander); + Q_UNUSED(message); + + QTextEdit *w = static_cast(m_widget); + + if (!w->isEnabled() && !m_disabledText.isNull() && m_currentText.isNull()) { + m_currentText = w->toHtml(); + w->setPlainText(Utils::expandMacros(m_disabledText, expander)); + } else if (w->isEnabled() && !m_currentText.isNull()) { + w->setText(m_currentText); + m_currentText.clear(); + } + + return !w->toPlainText().isEmpty(); +} + +void JsonFieldPage::TextEditField::initializeData(Utils::AbstractMacroExpander *expander) +{ + QTextEdit *w = static_cast(m_widget); + w->setPlainText(Utils::expandMacros(m_defaultText, expander)); +} + +// -------------------------------------------------------------------- +// JsonFieldPage::PathChooserFieldData: +// -------------------------------------------------------------------- + +JsonFieldPage::PathChooserField::PathChooserField() : + m_kind(Utils::PathChooser::ExistingDirectory) +{ } + +bool JsonFieldPage::PathChooserField::parseData(const QVariant &data, QString *errorMessage) +{ + if (data.isNull()) + return true; + + if (data.type() != QVariant::Map) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "PathChooser data is not an object."); + return false; + } + + QVariantMap tmp = data.toMap(); + + m_path = tmp.value(QLatin1String("path")).toString(); + m_basePath = tmp.value(QLatin1String("basePath")).toString(); + + QString kindStr = tmp.value(QLatin1String("kind"), QLatin1String("existingDirectory")).toString(); + if (kindStr == QLatin1String("existingDirectory")) { + m_kind = Utils::PathChooser::ExistingDirectory; + } else if (kindStr == QLatin1String("directory")) { + m_kind = Utils::PathChooser::Directory; + } else if (kindStr == QLatin1String("file")) { + m_kind = Utils::PathChooser::File; + } else if (kindStr == QLatin1String("saveFile")) { + m_kind = Utils::PathChooser::SaveFile; + } else if (kindStr == QLatin1String("existingCommand")) { + m_kind = Utils::PathChooser::ExistingCommand; + } else if (kindStr == QLatin1String("command")) { + m_kind = Utils::PathChooser::Command; + } else if (kindStr == QLatin1String("any")) { + m_kind = Utils::PathChooser::Any; + } else { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "kind '%1' is not one of the supported 'existingDirectory', " + "'directory', 'file', 'saveFile', 'existingCommand', " + "'command', 'any'.") + .arg(kindStr); + return false; + } + + return true; +} + +QWidget *JsonFieldPage::PathChooserField::widget(const QString &displayName) +{ + Q_UNUSED(displayName); + QTC_ASSERT(!m_widget, return m_widget); + m_widget = new Utils::PathChooser; + return m_widget; +} + +void JsonFieldPage::PathChooserField::setEnabled(bool e) +{ + QTC_ASSERT(m_widget, return); + Utils::PathChooser *w = static_cast(m_widget); + w->setReadOnly(!e); +} + +void JsonFieldPage::PathChooserField::setup(JsonFieldPage *page, const QString &name) +{ + Utils::PathChooser *w = static_cast(m_widget); + page->registerFieldWithName(name, w, "path", SIGNAL(changed(QString))); + connect(w, &Utils::PathChooser::changed, page, [page](QString) { page->completeChanged(); }); +} + +bool JsonFieldPage::PathChooserField::validate(Utils::AbstractMacroExpander *expander, QString *message) +{ + Q_UNUSED(expander); + Q_UNUSED(message); + Utils::PathChooser *w = static_cast(m_widget); + return w->isValid(); +} + +void JsonFieldPage::PathChooserField::initializeData(Utils::AbstractMacroExpander *expander) +{ + QTC_ASSERT(m_widget, return); + Utils::PathChooser *w = static_cast(m_widget); + w->setBaseDirectory(Utils::expandMacros(m_basePath, expander)); + w->setExpectedKind(m_kind); + + if (m_currentPath.isNull()) + w->setPath(Utils::expandMacros(m_path, expander)); + else + w->setPath(m_currentPath); +} + +// -------------------------------------------------------------------- +// JsonFieldPage::CheckBoxFieldData: +// -------------------------------------------------------------------- + +JsonFieldPage::CheckBoxField::CheckBoxField() : + m_checkedValue(QLatin1String("0")), + m_uncheckedValue(QLatin1String("1")), + m_isModified(false) +{ } + +bool JsonFieldPage::CheckBoxField::parseData(const QVariant &data, QString *errorMessage) +{ + if (data.isNull()) + return true; + + if (data.type() != QVariant::Map) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "CheckBox data is not an object."); + return false; + } + + QVariantMap tmp = data.toMap(); + + m_checkedValue = tmp.value(QLatin1String("checkedValue"), QLatin1String("0")).toString(); + m_uncheckedValue = tmp.value(QLatin1String("uncheckedValue"), QLatin1String("1")).toString(); + if (m_checkedValue == m_uncheckedValue) { + *errorMessage= QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "CheckBox values for checked and unchecked state are identical."); + return false; + } + m_checkedExpression = tmp.value(QLatin1String("checked"), false); + + return true; +} + +QWidget *JsonFieldPage::CheckBoxField::widget(const QString &displayName) +{ + QTC_ASSERT(!m_widget, return m_widget); + Utils::TextFieldCheckBox *w = new Utils::TextFieldCheckBox(displayName); + m_widget = w; + return m_widget; +} + +void JsonFieldPage::CheckBoxField::setup(JsonFieldPage *page, const QString &name) +{ + Utils::TextFieldCheckBox *w = static_cast(m_widget); + connect(w, &Utils::TextFieldCheckBox::clicked, [this]() { m_isModified = true; }); + page->registerFieldWithName(name, w, "text", SIGNAL(textChanged(QString))); +} + +bool JsonFieldPage::CheckBoxField::validate(Utils::AbstractMacroExpander *expander, QString *message) +{ + Q_UNUSED(message); + if (!m_isModified) { + Utils::TextFieldCheckBox *w = static_cast(m_widget); + w->setChecked(JsonWizard::boolFromVariant(m_checkedExpression, expander)); + } + return true; +} + +void JsonFieldPage::CheckBoxField::initializeData(Utils::AbstractMacroExpander *expander) +{ + QTC_ASSERT(m_widget, return); + + Utils::TextFieldCheckBox *w = static_cast(m_widget); + w->setTrueText(Utils::expandMacros(m_checkedValue, expander)); + w->setFalseText(Utils::expandMacros(m_uncheckedValue, expander)); + + w->setChecked(JsonWizard::boolFromVariant(m_checkedExpression, expander)); +} + +// -------------------------------------------------------------------- +// JsonFieldPage::ComboBoxFieldData: +// -------------------------------------------------------------------- + +JsonFieldPage::ComboBoxField::ComboBoxField() : + m_index(-1), m_disabledIndex(-1), m_savedIndex(-1), m_currentIndex(-1) +{ } + +QPair parseComboBoxItem(const QVariant &item, QString *errorMessage) +{ + if (item.type() == QVariant::List) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "No lists allowed inside ComboBox items list."); + return qMakePair(QString(), QString()); + } else if (item.type() == QVariant::Map) { + QVariantMap tmp = item.toMap(); + QString key = JsonWizardFactory::localizedString(tmp.value(QLatin1String("trKey"), QString()).toString()); + QString value = tmp.value(QLatin1String("value"), QString()).toString(); + if (key.isNull() || key.isEmpty()) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "No 'key' found in ComboBox items."); + return qMakePair(QString(), QString()); + } + if (value.isNull()) + value = key; + return qMakePair(key, value); + } else { + QString keyvalue = item.toString(); + return qMakePair(keyvalue, keyvalue); + } +} + +bool JsonFieldPage::ComboBoxField::parseData(const QVariant &data, QString *errorMessage) +{ + if (data.type() != QVariant::Map) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "ComboBox data is not an object."); + return false; + } + + QVariantMap tmp = data.toMap(); + + bool ok; + m_index = tmp.value(QLatin1String("index"), 0).toInt(&ok); + if (!ok) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "ComboBox 'index' is not a integer value."); + return false; + } + m_disabledIndex = tmp.value(QLatin1String("disabledIndex"), -1).toInt(&ok); + if (!ok) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "ComboBox 'disabledIndex' is not a integer value."); + return false; + } + + QVariant value = tmp.value(QLatin1String("items")); + if (value.isNull()) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "ComboBox 'items' missing."); + return false; + } + if (value.type() != QVariant::List) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonFieldPage", + "ComboBox 'items' is not a list."); + return false; + } + + foreach (const QVariant &i, value.toList()) { + QPair keyValue = parseComboBoxItem(i, errorMessage); + if (keyValue.first.isNull()) + return false; // an error happened... + m_itemList.append(keyValue.first); + m_itemDataList.append(keyValue.second); + } + + return true; +} + +QWidget *JsonFieldPage::ComboBoxField::widget(const QString &displayName) +{ + Q_UNUSED(displayName); + QTC_ASSERT(!m_widget, return m_widget); + m_widget = new Utils::TextFieldComboBox; + return m_widget; +} + +void JsonFieldPage::ComboBoxField::setup(JsonFieldPage *page, const QString &name) +{ + Utils::TextFieldComboBox *w = static_cast(m_widget); + page->registerFieldWithName(name, w, "text", SIGNAL(text4Changed(QString))); + connect(w, &Utils::TextFieldComboBox::text4Changed, page, [page](QString) { page->completeChanged(); }); +} + +bool JsonFieldPage::ComboBoxField::validate(Utils::AbstractMacroExpander *expander, QString *message) +{ + Q_UNUSED(expander); + Q_UNUSED(message); + + Utils::TextFieldComboBox *w = static_cast(m_widget); + if (!w->isEnabled() && m_disabledIndex >= 0 && m_savedIndex < 0) { + m_savedIndex = w->currentIndex(); + w->setCurrentIndex(m_disabledIndex); + } else if (w->isEnabled() && m_savedIndex >= 0) { + w->setCurrentIndex(m_savedIndex); + m_savedIndex = -1; + } + + return true; +} + +void JsonFieldPage::ComboBoxField::initializeData(Utils::AbstractMacroExpander *expander) +{ + Utils::TextFieldComboBox *w = static_cast(m_widget); + QStringList tmpItems + = Utils::transform(m_itemList, + [expander](const QString &i) { return Utils::expandMacros(i, expander); }); + QStringList tmpData + = Utils::transform(m_itemDataList, + [expander](const QString &i) { return Utils::expandMacros(i, expander); }); + w->setItems(tmpItems, tmpData); + w->setInsertPolicy(QComboBox::NoInsert); + + if (m_currentIndex >= 0) + w->setCurrentIndex(m_currentIndex); + else + w->setCurrentIndex(m_index); +} + +// -------------------------------------------------------------------- +// JsonFieldPage: +// -------------------------------------------------------------------- + +JsonFieldPage::JsonFieldPage(Utils::AbstractMacroExpander *expander, QWidget *parent) : + Utils::WizardPage(parent), + m_formLayout(new QFormLayout), + m_errorLabel(new QLabel), + m_expander(expander) +{ + QTC_CHECK(m_expander); + + QVBoxLayout *vLayout = new QVBoxLayout; + m_formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); + vLayout->addLayout(m_formLayout); + m_errorLabel->setVisible(false); + m_errorLabel->setStyleSheet(QLatin1String("background: red")); + vLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); + vLayout->addWidget(m_errorLabel); + setLayout(vLayout); +} + +JsonFieldPage::~JsonFieldPage() +{ + // Do not delete m_expander, it belongs to the wizard! + qDeleteAll(m_fields); +} + +bool JsonFieldPage::setup(const QVariant &data) +{ + QString errorMessage; + QList fieldList = JsonWizardFactory::objectOrList(data, &errorMessage); + foreach (const QVariant &field, fieldList) { + Field *f = JsonFieldPage::Field::parse(field, &errorMessage); + if (!f) + continue; + f->createWidget(this); + m_fields.append(f); + } + + return true; +} + +bool JsonFieldPage::isComplete() const +{ + QString message; + + bool result = true; + bool hasErrorMessage = false; + foreach (Field *f, m_fields) { + f->adjustState(m_expander); + if (!f->validate(m_expander, &message)) { + if (!message.isEmpty()) { + showError(message); + hasErrorMessage = true; + } + if (f->mandatory) + result = false; + } + } + + if (!hasErrorMessage) + clearError(); + + return result; +} + +void JsonFieldPage::initializePage() +{ + foreach (Field *f, m_fields) + f->initialize(m_expander); +} + +void JsonFieldPage::cleanupPage() +{ + foreach (Field *f, m_fields) + f->cleanup(m_expander); +} + +void JsonFieldPage::showError(const QString &m) const +{ + m_errorLabel->setText(m); + m_errorLabel->setVisible(true); +} + +void JsonFieldPage::clearError() const +{ + m_errorLabel->setText(QString()); + m_errorLabel->setVisible(false); +} + +Utils::AbstractMacroExpander *JsonFieldPage::expander() +{ + return m_expander; +} + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.h b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.h new file mode 100644 index 00000000000..cde0bdc06fa --- /dev/null +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.h @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** 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 JSONFIELDPAGE_H +#define JSONFIELDPAGE_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QFormLayout; +class QLabel; +class QLineEdit; +class QTextEdit; +QT_END_NAMESPACE + +namespace Utils { +class AbstractMacroExpander; +class TextFieldCheckBox; +class TextFieldComboBox; +} // namespace Utils + +namespace ProjectExplorer { + +// Documentation inside. +class JsonFieldPage : public Utils::WizardPage +{ + Q_OBJECT + +public: + class Field + { + public: + Field() : mandatory(false), span(false), m_visibleExpression(true), m_widget(0) { } + virtual ~Field() { delete m_widget; } + + static Field *parse(const QVariant &input, QString *errorMessage); + void createWidget(JsonFieldPage *page); + + void adjustState(Utils::AbstractMacroExpander *expander); + virtual void setEnabled(bool e) { m_widget->setEnabled(e); } + void setVisible(bool v) { m_widget->setVisible(v); } + + virtual bool validate(Utils::AbstractMacroExpander *expander, QString *message) + { Q_UNUSED(expander); Q_UNUSED(message); return true; } + + void initialize(Utils::AbstractMacroExpander *expander); + virtual void cleanup(Utils::AbstractMacroExpander *expander) { Q_UNUSED(expander); } + + virtual bool suppressName() const { return false; } + + QString name; + QString displayName; + bool mandatory; + bool span; + + protected: + QVariant m_visibleExpression; + QVariant m_enabledExpression; + + virtual bool parseData(const QVariant &data, QString *errorMessage) = 0; + virtual void initializeData(Utils::AbstractMacroExpander *expander) { Q_UNUSED(expander); } + virtual QWidget *widget(const QString &displayName) = 0; + virtual void setup(JsonFieldPage *page, const QString &name) + { Q_UNUSED(page); Q_UNUSED(name); } + + QWidget *m_widget; + }; + + class LabelField : public Field + { + public: + LabelField(); + + private: + QWidget *widget(const QString &displayName); + bool parseData(const QVariant &data, QString *errorMessage); + + bool m_wordWrap; + QString m_text; + }; + + class SpacerField : public Field + { + public: + SpacerField(); + + bool suppressName() const { return true; } + + private: + bool parseData(const QVariant &data, QString *errorMessage); + QWidget *widget(const QString &displayName); + + int m_factor; + }; + + class LineEditField : public Field + { + public: + LineEditField(); + + private: + bool parseData(const QVariant &data, QString *errorMessage); + QWidget *widget(const QString &displayName); + + void setup(JsonFieldPage *page, const QString &name); + + bool validate(Utils::AbstractMacroExpander *expander, QString *message); + void initializeData(Utils::AbstractMacroExpander *expander); + + QString m_placeholderText; + QString m_defaultText; + QString m_disabledText; + + bool m_isModified; + mutable QString m_currentText; + }; + + class TextEditField : public Field + { + public: + TextEditField(); + + private: + bool parseData(const QVariant &data, QString *errorMessage); + QWidget *widget(const QString &displayName); + + void setup(JsonFieldPage *page, const QString &name); + + bool validate(Utils::AbstractMacroExpander *expander, QString *message); + void initializeData(Utils::AbstractMacroExpander *expander); + + QString m_defaultText; + bool m_acceptRichText; + QString m_disabledText; + + mutable QString m_currentText; + }; + + class PathChooserField : public Field + { + public: + PathChooserField(); + + private: + bool parseData(const QVariant &data, QString *errorMessage); + + QWidget *widget(const QString &displayName); + void setEnabled(bool e); + + void setup(JsonFieldPage *page, const QString &name); + + bool validate(Utils::AbstractMacroExpander *expander, QString *message); + void initializeData(Utils::AbstractMacroExpander *expander); + + QString m_path; + QString m_basePath; + Utils::PathChooser::Kind m_kind; + + QString m_currentPath; + }; + + class CheckBoxField : public Field + { + public: + CheckBoxField(); + + bool suppressName() const { return true; } + + private: + bool parseData(const QVariant &data, QString *errorMessage); + + QWidget *widget(const QString &displayName); + + void setup(JsonFieldPage *page, const QString &name); + + bool validate(Utils::AbstractMacroExpander *expander, QString *message); + void initializeData(Utils::AbstractMacroExpander *expander); + + QString m_checkedValue; + QString m_uncheckedValue; + QVariant m_checkedExpression; + + bool m_isModified; + }; + + class ComboBoxField : public Field + { + public: + ComboBoxField(); + + private: + bool parseData(const QVariant &data, QString *errorMessage); + + QWidget *widget(const QString &displayName); + + void setup(JsonFieldPage *page, const QString &name); + + bool validate(Utils::AbstractMacroExpander *expander, QString *message); + void initializeData(Utils::AbstractMacroExpander *expander); + + QStringList m_itemList; + QStringList m_itemDataList; + int m_index; + int m_disabledIndex; + + mutable int m_savedIndex; + int m_currentIndex; + }; + + JsonFieldPage(Utils::AbstractMacroExpander *expander, QWidget *parent = 0); + ~JsonFieldPage(); + + bool setup(const QVariant &data); + + bool isComplete() const; + void initializePage(); + void cleanupPage(); + + QFormLayout *layout() const { return m_formLayout; } + + void showError(const QString &m) const; + void clearError() const; + + Utils::AbstractMacroExpander *expander(); + +private: + QFormLayout *m_formLayout; + QLabel *m_errorLabel; + + QList m_fields; + + Utils::AbstractMacroExpander *m_expander; +}; + +} // namespace ProjectExplorer + +#endif // JSONFIELDPAGE_H diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizard.pri b/src/plugins/projectexplorer/jsonwizard/jsonwizard.pri index ba9e728065a..40d0f6a2a6d 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizard.pri +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizard.pri @@ -1,4 +1,5 @@ -HEADERS += $$PWD/jsonfilepage.h \ +HEADERS += $$PWD/jsonfieldpage.h \ + $$PWD/jsonfilepage.h \ $$PWD/jsonsummarypage.h \ $$PWD/jsonwizard.h \ $$PWD/jsonwizardexpander.h \ @@ -8,7 +9,8 @@ HEADERS += $$PWD/jsonfilepage.h \ $$PWD/jsonwizardpagefactory.h \ $$PWD/jsonwizardpagefactory_p.h -SOURCES += $$PWD/jsonfilepage.cpp \ +SOURCES += $$PWD/jsonfieldpage.cpp \ + $$PWD/jsonfilepage.cpp \ $$PWD/jsonsummarypage.cpp \ $$PWD/jsonwizard.cpp \ $$PWD/jsonwizardexpander.cpp \ diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.cpp index 9d6b8b0927c..10db8959533 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.cpp @@ -29,8 +29,10 @@ #include "jsonwizardpagefactory_p.h" +#include "jsonfieldpage.h" #include "jsonfilepage.h" #include "jsonsummarypage.h" +#include "jsonwizardfactory.h" #include #include @@ -41,6 +43,53 @@ namespace ProjectExplorer { namespace Internal { +// -------------------------------------------------------------------- +// FieldPageFactory: +// -------------------------------------------------------------------- + +FieldPageFactory::FieldPageFactory() +{ + setTypeIdsSuffix(QLatin1String("Fields")); +} + +Utils::WizardPage *FieldPageFactory::create(JsonWizard *wizard, Core::Id typeId, const QVariant &data) +{ + Q_UNUSED(wizard); + + QTC_ASSERT(canCreate(typeId), return 0); + + JsonFieldPage *page = new JsonFieldPage(wizard->expander()); + + if (!page->setup(data)) { + delete page; + return 0; + } + + return page; +} + +bool FieldPageFactory::validateData(Core::Id typeId, const QVariant &data, QString *errorMessage) +{ + QTC_ASSERT(canCreate(typeId), return false); + + QList list = JsonWizardFactory::objectOrList(data, errorMessage); + if (list.isEmpty()) { + *errorMessage = QCoreApplication::translate("ProjectExplorer::JsonWizard", + "When parsing fields of page '%1': %2") + .arg(typeId.toString()).arg(*errorMessage); + return false; + } + + foreach (const QVariant &v, list) { + JsonFieldPage::Field *field = JsonFieldPage::Field::parse(v, errorMessage); + if (!field) + return false; + delete field; + } + + return true; +} + // -------------------------------------------------------------------- // FilePageFactory: // -------------------------------------------------------------------- diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.h b/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.h index 0e7f2f21b1a..2d0b0ce65bd 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardpagefactory_p.h @@ -35,6 +35,15 @@ namespace ProjectExplorer { namespace Internal { +class FieldPageFactory : public JsonWizardPageFactory +{ +public: + FieldPageFactory(); + + Utils::WizardPage *create(JsonWizard *wizard, Core::Id typeId, const QVariant &data); + bool validateData(Core::Id typeId, const QVariant &data, QString *errorMessage); +}; + class FilePageFactory : public JsonWizardPageFactory { public: diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index a5bbad38751..dfa33eb513b 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -460,6 +460,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er addAutoReleasedObject(new CustomWizardMetaFactory(Core::IWizardFactory::ClassWizard)); // For JsonWizard: + JsonWizardFactory::registerPageFactory(new FieldPageFactory); JsonWizardFactory::registerPageFactory(new FilePageFactory); JsonWizardFactory::registerPageFactory(new SummaryPageFactory); diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 4d9b515dd51..a9547898430 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -170,6 +170,7 @@ QtcPlugin { name: "JsonWizard" prefix: "jsonwizard/" files: [ + "jsonfieldpage.cpp", "jsonfieldpage.h", "jsonfilepage.cpp", "jsonfilepage.h", "jsonsummarypage.cpp", "jsonsummarypage.h", "jsonwizard.cpp", "jsonwizard.h",