forked from qt-creator/qt-creator
Custom wizard: Add validation rules.
Add XML-elements allowing for Javascript-based validation rules along with error messages. Rubber-stamped-by: Erik Verbruggen <erik.verbruggen@nokia.com>
This commit is contained in:
@@ -67,4 +67,11 @@ Custom class wizard example configuration file. -->
|
|||||||
<fielddescription xml:lang="de">Datentyp:</fielddescription>
|
<fielddescription xml:lang="de">Datentyp:</fielddescription>
|
||||||
</field>
|
</field>
|
||||||
</fields>
|
</fields>
|
||||||
|
<!-- Example of a validation rule -->
|
||||||
|
<validationrules>
|
||||||
|
<validationrule condition='"%ClassName%" != "QAbstractListModel"'>
|
||||||
|
<message>%ClassName% cannot be used as class name.</message>
|
||||||
|
<message xml:lang="de">%ClassName% kann nicht als Klassenname verwendet werden.</message>
|
||||||
|
</validationrule>
|
||||||
|
</validationrules>
|
||||||
</wizard>
|
</wizard>
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ let $prefix := string("QT_TRANSLATE_NOOP("ProjectExplorer::CustomWizard&quo
|
|||||||
let $suffix := concat("")", codepoints-to-string(10))
|
let $suffix := concat("")", codepoints-to-string(10))
|
||||||
for $file in tokenize($files, string("\|"))
|
for $file in tokenize($files, string("\|"))
|
||||||
let $doc := doc($file)
|
let $doc := doc($file)
|
||||||
for $text in ($doc/*:wizard/*:description, $doc/*:wizard/*:displayname, $doc/*:wizard/*:displaycategory, $doc/*:wizard/*:fieldpagetitle, $doc/*:wizard/*:fields/*:field/*:fielddescription, $doc/*:wizard/*:fields/*:field/*:fieldcontrol/*:comboentries/*:comboentry/*:comboentrytext)
|
for $text in ($doc/*:wizard/*:description, $doc/*:wizard/*:displayname, $doc/*:wizard/*:displaycategory, $doc/*:wizard/*:fieldpagetitle, $doc/*:wizard/*:fields/*:field/*:fielddescription, $doc/*:wizard/*:fields/*:field/*:fieldcontrol/*:comboentries/*:comboentry/*:comboentrytext, $doc/*:wizard/*:validationrules/*:validationrule/*:message)
|
||||||
return fn:concat($prefix, data($text), $suffix)
|
return fn:concat($prefix, data($text), $suffix)
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ void CustomWizard::initWizardDialog(Utils::Wizard *wizard, const QString &defaul
|
|||||||
QTC_ASSERT(!parameters().isNull(), return);
|
QTC_ASSERT(!parameters().isNull(), return);
|
||||||
|
|
||||||
d->m_context->reset();
|
d->m_context->reset();
|
||||||
Internal::CustomWizardPage *customPage = new Internal::CustomWizardPage(d->m_context, parameters()->fields);
|
Internal::CustomWizardPage *customPage = new Internal::CustomWizardPage(d->m_context, parameters());
|
||||||
customPage->setPath(defaultPath);
|
customPage->setPath(defaultPath);
|
||||||
addWizardPage(wizard, customPage, parameters()->firstPageId);
|
addWizardPage(wizard, customPage, parameters()->firstPageId);
|
||||||
if (!parameters()->fieldPageTitle.isEmpty())
|
if (!parameters()->fieldPageTitle.isEmpty())
|
||||||
@@ -298,15 +298,7 @@ Core::GeneratedFiles CustomWizard::generateWizardFiles(QString *errorMessage) co
|
|||||||
// Create a replacement map of static base fields + wizard dialog fields
|
// Create a replacement map of static base fields + wizard dialog fields
|
||||||
CustomWizard::FieldReplacementMap CustomWizard::replacementMap(const QWizard *w) const
|
CustomWizard::FieldReplacementMap CustomWizard::replacementMap(const QWizard *w) const
|
||||||
{
|
{
|
||||||
FieldReplacementMap fieldReplacementMap = d->m_context->baseReplacements;
|
return Internal::CustomWizardFieldPage::replacementMap(w, context(), d->m_parameters->fields);
|
||||||
foreach(const Internal::CustomWizardField &field, d->m_parameters->fields) {
|
|
||||||
const QString value = w->field(field.name).toString();
|
|
||||||
fieldReplacementMap.insert(field.name, value);
|
|
||||||
}
|
|
||||||
// Insert paths for generator scripts.
|
|
||||||
fieldReplacementMap.insert(QLatin1String("Path"), QDir::toNativeSeparators(context()->path));
|
|
||||||
fieldReplacementMap.insert(QLatin1String("TargetPath"), QDir::toNativeSeparators(context()->targetPath));
|
|
||||||
return fieldReplacementMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomWizard::CustomWizardParametersPtr CustomWizard::parameters() const
|
CustomWizard::CustomWizardParametersPtr CustomWizard::parameters() const
|
||||||
@@ -501,7 +493,7 @@ void CustomProjectWizard::initProjectWizardDialog(BaseProjectWizardDialog *w,
|
|||||||
w->setWindowTitle(displayName());
|
w->setWindowTitle(displayName());
|
||||||
|
|
||||||
if (!pa->fields.isEmpty()) {
|
if (!pa->fields.isEmpty()) {
|
||||||
Internal::CustomWizardFieldPage *cp = new Internal::CustomWizardFieldPage(ctx, pa->fields);
|
Internal::CustomWizardFieldPage *cp = new Internal::CustomWizardFieldPage(ctx, pa);
|
||||||
addWizardPage(w, cp, parameters()->firstPageId);
|
addWizardPage(w, cp, parameters()->firstPageId);
|
||||||
if (!pa->fieldPageTitle.isEmpty())
|
if (!pa->fieldPageTitle.isEmpty())
|
||||||
cp->setTitle(pa->fieldPageTitle);
|
cp->setTitle(pa->fieldPageTitle);
|
||||||
|
|||||||
@@ -35,14 +35,17 @@
|
|||||||
|
|
||||||
#include <QtCore/QRegExp>
|
#include <QtCore/QRegExp>
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtCore/QDir>
|
||||||
|
|
||||||
#include <QtGui/QWizardPage>
|
#include <QtGui/QWizardPage>
|
||||||
#include <QtGui/QFormLayout>
|
#include <QtGui/QFormLayout>
|
||||||
|
#include <QtGui/QVBoxLayout>
|
||||||
#include <QtGui/QLineEdit>
|
#include <QtGui/QLineEdit>
|
||||||
#include <QtGui/QLabel>
|
#include <QtGui/QLabel>
|
||||||
#include <QtGui/QRegExpValidator>
|
#include <QtGui/QRegExpValidator>
|
||||||
#include <QtGui/QComboBox>
|
#include <QtGui/QComboBox>
|
||||||
#include <QtGui/QTextEdit>
|
#include <QtGui/QTextEdit>
|
||||||
|
#include <QtGui/QSpacerItem>
|
||||||
|
|
||||||
enum { debug = 0 };
|
enum { debug = 0 };
|
||||||
|
|
||||||
@@ -127,18 +130,26 @@ CustomWizardFieldPage::TextEditData::TextEditData(QTextEdit* le, const QString &
|
|||||||
}
|
}
|
||||||
|
|
||||||
CustomWizardFieldPage::CustomWizardFieldPage(const QSharedPointer<CustomWizardContext> &ctx,
|
CustomWizardFieldPage::CustomWizardFieldPage(const QSharedPointer<CustomWizardContext> &ctx,
|
||||||
const FieldList &fields,
|
const QSharedPointer<CustomWizardParameters> ¶meters,
|
||||||
QWidget *parent) :
|
QWidget *parent) :
|
||||||
QWizardPage(parent),
|
QWizardPage(parent),
|
||||||
|
m_parameters(parameters),
|
||||||
m_context(ctx),
|
m_context(ctx),
|
||||||
m_formLayout(new QFormLayout)
|
m_formLayout(new QFormLayout),
|
||||||
|
m_errorLabel(new QLabel)
|
||||||
{
|
{
|
||||||
|
QVBoxLayout *vLayout = new QVBoxLayout;
|
||||||
m_formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
|
m_formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow);
|
||||||
if (debug)
|
if (debug)
|
||||||
qDebug() << Q_FUNC_INFO << fields.size();
|
qDebug() << Q_FUNC_INFO << parameters->fields.size();
|
||||||
foreach(const CustomWizardField &f, fields)
|
foreach(const CustomWizardField &f, parameters->fields)
|
||||||
addField(f);
|
addField(f);
|
||||||
setLayout(m_formLayout);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomWizardFieldPage::~CustomWizardFieldPage()
|
CustomWizardFieldPage::~CustomWizardFieldPage()
|
||||||
@@ -150,6 +161,18 @@ void CustomWizardFieldPage::addRow(const QString &name, QWidget *w)
|
|||||||
m_formLayout->addRow(name, w);
|
m_formLayout->addRow(name, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CustomWizardFieldPage::showError(const QString &m)
|
||||||
|
{
|
||||||
|
m_errorLabel->setText(m);
|
||||||
|
m_errorLabel->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomWizardFieldPage::clearError()
|
||||||
|
{
|
||||||
|
m_errorLabel->setText(QString());
|
||||||
|
m_errorLabel->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
// Create widget a control based on the control attributes map
|
// Create widget a control based on the control attributes map
|
||||||
// and register it with the QWizard.
|
// and register it with the QWizard.
|
||||||
void CustomWizardFieldPage::addField(const CustomWizardField &field)\
|
void CustomWizardFieldPage::addField(const CustomWizardField &field)\
|
||||||
@@ -294,6 +317,7 @@ QWidget *CustomWizardFieldPage::registerLineEdit(const QString &fieldName,
|
|||||||
void CustomWizardFieldPage::initializePage()
|
void CustomWizardFieldPage::initializePage()
|
||||||
{
|
{
|
||||||
QWizardPage::initializePage();
|
QWizardPage::initializePage();
|
||||||
|
clearError();
|
||||||
// Note that the field mechanism will always restore the value
|
// Note that the field mechanism will always restore the value
|
||||||
// set on it when entering the page, so, there is no point in
|
// set on it when entering the page, so, there is no point in
|
||||||
// trying to preserve user modifications of the text.
|
// trying to preserve user modifications of the text.
|
||||||
@@ -315,6 +339,7 @@ void CustomWizardFieldPage::initializePage()
|
|||||||
|
|
||||||
bool CustomWizardFieldPage::validatePage()
|
bool CustomWizardFieldPage::validatePage()
|
||||||
{
|
{
|
||||||
|
clearError();
|
||||||
// Check line edits with validators
|
// Check line edits with validators
|
||||||
foreach(const LineEditData &led, m_lineEdits) {
|
foreach(const LineEditData &led, m_lineEdits) {
|
||||||
if (const QValidator *val = led.lineEdit->validator()) {
|
if (const QValidator *val = led.lineEdit->validator()) {
|
||||||
@@ -326,15 +351,40 @@ bool CustomWizardFieldPage::validatePage()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Any user validation rules -> Check all and display messages with
|
||||||
|
// place holders applied.
|
||||||
|
if (!m_parameters->rules.isEmpty()) {
|
||||||
|
const QMap<QString, QString> values = replacementMap(wizard(), m_context, m_parameters->fields);
|
||||||
|
QString message;
|
||||||
|
if (!CustomWizardValidationRule::validateRules(m_parameters->rules, values, &message)) {
|
||||||
|
showError(message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return QWizardPage::validatePage();
|
return QWizardPage::validatePage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMap<QString, QString> CustomWizardFieldPage::replacementMap(const QWizard *w,
|
||||||
|
const QSharedPointer<CustomWizardContext> &ctx,
|
||||||
|
const FieldList &f)
|
||||||
|
{
|
||||||
|
QMap<QString, QString> fieldReplacementMap = ctx->baseReplacements;
|
||||||
|
foreach(const Internal::CustomWizardField &field, f) {
|
||||||
|
const QString value = w->field(field.name).toString();
|
||||||
|
fieldReplacementMap.insert(field.name, value);
|
||||||
|
}
|
||||||
|
// Insert paths for generator scripts.
|
||||||
|
fieldReplacementMap.insert(QLatin1String("Path"), QDir::toNativeSeparators(ctx->path));
|
||||||
|
fieldReplacementMap.insert(QLatin1String("TargetPath"), QDir::toNativeSeparators(ctx->targetPath));
|
||||||
|
return fieldReplacementMap;
|
||||||
|
}
|
||||||
|
|
||||||
// --------------- CustomWizardPage
|
// --------------- CustomWizardPage
|
||||||
|
|
||||||
CustomWizardPage::CustomWizardPage(const QSharedPointer<CustomWizardContext> &ctx,
|
CustomWizardPage::CustomWizardPage(const QSharedPointer<CustomWizardContext> &ctx,
|
||||||
const FieldList &f,
|
const QSharedPointer<CustomWizardParameters> ¶meters,
|
||||||
QWidget *parent) :
|
QWidget *parent) :
|
||||||
CustomWizardFieldPage(ctx, f, parent),
|
CustomWizardFieldPage(ctx, parameters, parent),
|
||||||
m_pathChooser(new Utils::PathChooser)
|
m_pathChooser(new Utils::PathChooser)
|
||||||
{
|
{
|
||||||
addRow(tr("Path:"), m_pathChooser);
|
addRow(tr("Path:"), m_pathChooser);
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
class QFormLayout;
|
class QFormLayout;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QTextEdit;
|
class QTextEdit;
|
||||||
|
class QLabel;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
@@ -110,23 +111,30 @@ private:
|
|||||||
// as page 2 of a BaseProjectWizardDialog if there are any fields.
|
// as page 2 of a BaseProjectWizardDialog if there are any fields.
|
||||||
// Uses the 'field' functionality of QWizard.
|
// Uses the 'field' functionality of QWizard.
|
||||||
// Implements validatePage() as the field logic cannot be tied up
|
// Implements validatePage() as the field logic cannot be tied up
|
||||||
// with additional validation.
|
// with additional validation. Performs checking of the Javascript-based
|
||||||
|
// validation rules of the parameters and displays error messages in a red
|
||||||
|
// warning label.
|
||||||
class CustomWizardFieldPage : public QWizardPage {
|
class CustomWizardFieldPage : public QWizardPage {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
typedef QList<CustomWizardField> FieldList;
|
typedef QList<CustomWizardField> FieldList;
|
||||||
|
|
||||||
explicit CustomWizardFieldPage(const QSharedPointer<CustomWizardContext> &ctx,
|
explicit CustomWizardFieldPage(const QSharedPointer<CustomWizardContext> &ctx,
|
||||||
const FieldList &f,
|
const QSharedPointer<CustomWizardParameters> ¶meters,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
virtual ~CustomWizardFieldPage();
|
virtual ~CustomWizardFieldPage();
|
||||||
|
|
||||||
virtual bool validatePage();
|
virtual bool validatePage();
|
||||||
virtual void initializePage();
|
virtual void initializePage();
|
||||||
|
|
||||||
|
static QMap<QString, QString> replacementMap(const QWizard *w,
|
||||||
|
const QSharedPointer<CustomWizardContext> &ctx,
|
||||||
|
const FieldList &f);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
inline void addRow(const QString &name, QWidget *w);
|
inline void addRow(const QString &name, QWidget *w);
|
||||||
|
void showError(const QString &);
|
||||||
|
void clearError();
|
||||||
private:
|
private:
|
||||||
struct LineEditData {
|
struct LineEditData {
|
||||||
explicit LineEditData(QLineEdit* le = 0, const QString &defText = QString());
|
explicit LineEditData(QLineEdit* le = 0, const QString &defText = QString());
|
||||||
@@ -150,10 +158,12 @@ private:
|
|||||||
const CustomWizardField &field);
|
const CustomWizardField &field);
|
||||||
void addField(const CustomWizardField &f);
|
void addField(const CustomWizardField &f);
|
||||||
|
|
||||||
|
const QSharedPointer<CustomWizardParameters> m_parameters;
|
||||||
const QSharedPointer<CustomWizardContext> m_context;
|
const QSharedPointer<CustomWizardContext> m_context;
|
||||||
QFormLayout *m_formLayout;
|
QFormLayout *m_formLayout;
|
||||||
LineEditDataList m_lineEdits;
|
LineEditDataList m_lineEdits;
|
||||||
TextEditDataList m_textEdits;
|
TextEditDataList m_textEdits;
|
||||||
|
QLabel *m_errorLabel;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A custom wizard page presenting the fields to be used and a path chooser
|
// A custom wizard page presenting the fields to be used and a path chooser
|
||||||
@@ -164,7 +174,7 @@ class CustomWizardPage : public CustomWizardFieldPage {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit CustomWizardPage(const QSharedPointer<CustomWizardContext> &ctx,
|
explicit CustomWizardPage(const QSharedPointer<CustomWizardContext> &ctx,
|
||||||
const FieldList &f,
|
const QSharedPointer<CustomWizardParameters> ¶meters,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
|
|
||||||
QString path() const;
|
QString path() const;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
#include <QtCore/QXmlStreamReader>
|
#include <QtCore/QXmlStreamReader>
|
||||||
#include <QtCore/QXmlStreamAttribute>
|
#include <QtCore/QXmlStreamAttribute>
|
||||||
#include <QtCore/QTemporaryFile>
|
#include <QtCore/QTemporaryFile>
|
||||||
|
#include <QtScript/QScriptEngine>
|
||||||
|
|
||||||
#include <QtGui/QIcon>
|
#include <QtGui/QIcon>
|
||||||
|
|
||||||
@@ -90,6 +91,11 @@ static const char fileSourceAttributeC[] = "source";
|
|||||||
static const char fileTargetAttributeC[] = "target";
|
static const char fileTargetAttributeC[] = "target";
|
||||||
static const char fileBinaryAttributeC[] = "binary";
|
static const char fileBinaryAttributeC[] = "binary";
|
||||||
|
|
||||||
|
static const char rulesElementC[] = "validationrules";
|
||||||
|
static const char ruleElementC[] = "validationrule";
|
||||||
|
static const char ruleConditionAttributeC[] = "condition";
|
||||||
|
static const char ruleMessageElementC[] = "message";
|
||||||
|
|
||||||
enum ParseState {
|
enum ParseState {
|
||||||
ParseBeginning,
|
ParseBeginning,
|
||||||
ParseWithinWizard,
|
ParseWithinWizard,
|
||||||
@@ -104,6 +110,9 @@ enum ParseState {
|
|||||||
ParseWithinFile,
|
ParseWithinFile,
|
||||||
ParseWithinScript,
|
ParseWithinScript,
|
||||||
ParseWithinScriptArguments,
|
ParseWithinScriptArguments,
|
||||||
|
ParseWithinValidationRules,
|
||||||
|
ParseWithinValidationRule,
|
||||||
|
ParseWithinValidationRuleMessage,
|
||||||
ParseError
|
ParseError
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -142,6 +151,38 @@ CustomWizardFile::CustomWizardFile() :
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CustomWizardValidationRule::validateRules(const QList<CustomWizardValidationRule> &rules,
|
||||||
|
const QMap<QString, QString> &replacementMap,
|
||||||
|
QString *errorMessage)
|
||||||
|
{
|
||||||
|
errorMessage->clear();
|
||||||
|
if (rules.isEmpty())
|
||||||
|
return true;
|
||||||
|
QScriptEngine engine;
|
||||||
|
foreach(const CustomWizardValidationRule &rule, rules)
|
||||||
|
if (!rule.validate(engine, replacementMap)) {
|
||||||
|
*errorMessage = rule.message;
|
||||||
|
CustomWizardContext::replaceFields(replacementMap, errorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CustomWizardValidationRule::validate(QScriptEngine &engine, const QMap<QString, QString> &replacementMap) const
|
||||||
|
{
|
||||||
|
// Apply parameters and evaluate using JavaScript
|
||||||
|
QString cond = condition;
|
||||||
|
CustomWizardContext::replaceFields(replacementMap, &cond);
|
||||||
|
bool valid = false;
|
||||||
|
QString errorMessage;
|
||||||
|
if (!evaluateBooleanJavaScriptExpression(engine, cond, &valid, &errorMessage)) {
|
||||||
|
qWarning("Error in custom wizard validation expression '%s': %s",
|
||||||
|
qPrintable(cond), qPrintable(errorMessage));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
CustomWizardParameters::CustomWizardParameters() :
|
CustomWizardParameters::CustomWizardParameters() :
|
||||||
firstPageId(-1)
|
firstPageId(-1)
|
||||||
{
|
{
|
||||||
@@ -155,6 +196,7 @@ void CustomWizardParameters::clear()
|
|||||||
filesGeneratorScript.clear();
|
filesGeneratorScript.clear();
|
||||||
filesGeneratorScriptArguments.clear();
|
filesGeneratorScriptArguments.clear();
|
||||||
firstPageId = -1;
|
firstPageId = -1;
|
||||||
|
rules.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve icon file path relative to config file directory.
|
// Resolve icon file path relative to config file directory.
|
||||||
@@ -296,6 +338,8 @@ static ParseState nextOpeningState(ParseState in, const QStringRef &name)
|
|||||||
return ParseWithinFiles;
|
return ParseWithinFiles;
|
||||||
if (name == QLatin1String(generatorScriptElementC))
|
if (name == QLatin1String(generatorScriptElementC))
|
||||||
return ParseWithinScript;
|
return ParseWithinScript;
|
||||||
|
if (name == QLatin1String(rulesElementC))
|
||||||
|
return ParseWithinValidationRules;
|
||||||
break;
|
break;
|
||||||
case ParseWithinFields:
|
case ParseWithinFields:
|
||||||
if (name == QLatin1String(fieldElementC))
|
if (name == QLatin1String(fieldElementC))
|
||||||
@@ -327,11 +371,20 @@ static ParseState nextOpeningState(ParseState in, const QStringRef &name)
|
|||||||
if (name == QLatin1String(generatorScriptArgumentElementC))
|
if (name == QLatin1String(generatorScriptArgumentElementC))
|
||||||
return ParseWithinScriptArguments;
|
return ParseWithinScriptArguments;
|
||||||
break;
|
break;
|
||||||
|
case ParseWithinValidationRules:
|
||||||
|
if (name == QLatin1String(ruleElementC))
|
||||||
|
return ParseWithinValidationRule;
|
||||||
|
break;
|
||||||
|
case ParseWithinValidationRule:
|
||||||
|
if (name == QLatin1String(ruleMessageElementC))
|
||||||
|
return ParseWithinValidationRuleMessage;
|
||||||
|
break;
|
||||||
case ParseWithinFieldDescription: // No subelements
|
case ParseWithinFieldDescription: // No subelements
|
||||||
case ParseWithinComboEntryText:
|
case ParseWithinComboEntryText:
|
||||||
case ParseWithinFile:
|
case ParseWithinFile:
|
||||||
case ParseError:
|
case ParseError:
|
||||||
case ParseWithinScriptArguments:
|
case ParseWithinScriptArguments:
|
||||||
|
case ParseWithinValidationRuleMessage:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ParseError;
|
return ParseError;
|
||||||
@@ -391,6 +444,12 @@ static ParseState nextClosingState(ParseState in, const QStringRef &name)
|
|||||||
if (name == QLatin1String(generatorScriptArgumentElementC))
|
if (name == QLatin1String(generatorScriptArgumentElementC))
|
||||||
return ParseWithinScript;
|
return ParseWithinScript;
|
||||||
break;
|
break;
|
||||||
|
case ParseWithinValidationRuleMessage:
|
||||||
|
return ParseWithinValidationRule;
|
||||||
|
case ParseWithinValidationRule:
|
||||||
|
return ParseWithinValidationRules;
|
||||||
|
case ParseWithinValidationRules:
|
||||||
|
return ParseWithinWizard;
|
||||||
case ParseError:
|
case ParseError:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -575,6 +634,18 @@ CustomWizardParameters::ParseResult
|
|||||||
filesGeneratorScriptArguments.push_back(argument);
|
filesGeneratorScriptArguments.push_back(argument);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ParseWithinValidationRule: {
|
||||||
|
CustomWizardValidationRule rule;
|
||||||
|
rule.condition = reader.attributes().value(QLatin1String(ruleConditionAttributeC)).toString();
|
||||||
|
rules.push_back(rule);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ParseWithinValidationRuleMessage:
|
||||||
|
QTC_ASSERT(!rules.isEmpty(), return ParseFailed; )
|
||||||
|
// This reads away the end tag, set state here.
|
||||||
|
assignLanguageElementText(reader, language, &(rules.back().message));
|
||||||
|
state = ParseWithinValidationRule;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -664,6 +735,8 @@ QString CustomWizardParameters::toString() const
|
|||||||
}
|
}
|
||||||
str << '\n';
|
str << '\n';
|
||||||
}
|
}
|
||||||
|
foreach(const CustomWizardValidationRule &r, rules)
|
||||||
|
str << " Rule: '" << r.condition << "'->'" << r.message << '\n';
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ QT_BEGIN_NAMESPACE
|
|||||||
class QIODevice;
|
class QIODevice;
|
||||||
class QDebug;
|
class QDebug;
|
||||||
class QTemporaryFile;
|
class QTemporaryFile;
|
||||||
|
class QScriptEngine;
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
@@ -71,6 +72,22 @@ struct CustomWizardFile {
|
|||||||
bool binary;
|
bool binary;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A validation rule based on Javascript-expressions over the field placeholders.
|
||||||
|
// Placeholder replacement is performed on the condition and it is evaluated
|
||||||
|
// using Javascript. So, for example '"%ProjectName%" != "untitled" would block
|
||||||
|
// default names. On failure, the message is displayed in a red warning label
|
||||||
|
// in the wizard page. Placeholder replacement is also performed on the message
|
||||||
|
// prior to displaying.
|
||||||
|
struct CustomWizardValidationRule {
|
||||||
|
// Validate a set of rules and return false + message on the first failing one.
|
||||||
|
static bool validateRules(const QList<CustomWizardValidationRule> &rules,
|
||||||
|
const QMap<QString, QString> &replacementMap,
|
||||||
|
QString *errorMessage);
|
||||||
|
bool validate(QScriptEngine &, const QMap<QString, QString> &replacementMap) const;
|
||||||
|
QString condition;
|
||||||
|
QString message;
|
||||||
|
};
|
||||||
|
|
||||||
// Argument to the generator script containing placeholders to
|
// Argument to the generator script containing placeholders to
|
||||||
// be replaced by field values or file names
|
// be replaced by field values or file names
|
||||||
// as in '--class-name=%ClassName%' or '--description=%Description%'.
|
// as in '--class-name=%ClassName%' or '--description=%Description%'.
|
||||||
@@ -110,6 +127,7 @@ public:
|
|||||||
|
|
||||||
QString fieldPageTitle;
|
QString fieldPageTitle;
|
||||||
QList<CustomWizardField> fields;
|
QList<CustomWizardField> fields;
|
||||||
|
QList<CustomWizardValidationRule> rules;
|
||||||
int firstPageId;
|
int firstPageId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void reset();
|
void reset();
|
||||||
bool evaluateExpression(const QString &expression, bool *result, QString *errorMessage);
|
|
||||||
PreprocessorSection preprocessorLine(const QString & in, QString *ifExpression) const;
|
PreprocessorSection preprocessorLine(const QString & in, QString *ifExpression) const;
|
||||||
|
|
||||||
mutable QRegExp m_ifPattern;
|
mutable QRegExp m_ifPattern;
|
||||||
@@ -134,17 +133,15 @@ PreprocessorSection PreprocessContext::preprocessorLine(const QString &in,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate an expression within an 'if'/'elsif' to a bool via QScript
|
// Evaluate an expression within an 'if'/'elsif' to a bool via QScript
|
||||||
bool PreprocessContext::evaluateExpression(const QString &expression,
|
bool evaluateBooleanJavaScriptExpression(QScriptEngine &engine, const QString &expression, bool *result, QString *errorMessage)
|
||||||
bool *result,
|
|
||||||
QString *errorMessage)
|
|
||||||
{
|
{
|
||||||
errorMessage->clear();
|
errorMessage->clear();
|
||||||
*result = false;
|
*result = false;
|
||||||
m_scriptEngine.clearExceptions();
|
engine.clearExceptions();
|
||||||
const QScriptValue value = m_scriptEngine.evaluate(expression);
|
const QScriptValue value = engine.evaluate(expression);
|
||||||
if (m_scriptEngine.hasUncaughtException()) {
|
if (engine.hasUncaughtException()) {
|
||||||
*errorMessage = QString::fromLatin1("Error in '%1': %2").
|
*errorMessage = QString::fromLatin1("Error in '%1': %2").
|
||||||
arg(expression, m_scriptEngine.uncaughtException().toString());
|
arg(expression, engine.uncaughtException().toString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Try to convert to bool, be that an int or whatever.
|
// Try to convert to bool, be that an int or whatever.
|
||||||
@@ -196,7 +193,7 @@ bool PreprocessContext::process(const QString &in, QString *out, QString *errorM
|
|||||||
case IfSection:
|
case IfSection:
|
||||||
// '@If': Push new section
|
// '@If': Push new section
|
||||||
if (top.parentEnabled) {
|
if (top.parentEnabled) {
|
||||||
if (!evaluateExpression(expression, &expressionValue, errorMessage)) {
|
if (!evaluateBooleanJavaScriptExpression(m_scriptEngine, expression, &expressionValue, errorMessage)) {
|
||||||
*errorMessage = QString::fromLatin1("Error in @if at %1: %2").
|
*errorMessage = QString::fromLatin1("Error in @if at %1: %2").
|
||||||
arg(l + 1).arg(*errorMessage);
|
arg(l + 1).arg(*errorMessage);
|
||||||
return false;
|
return false;
|
||||||
@@ -214,7 +211,7 @@ bool PreprocessContext::process(const QString &in, QString *out, QString *errorM
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (top.parentEnabled) {
|
if (top.parentEnabled) {
|
||||||
if (!evaluateExpression(expression, &expressionValue, errorMessage)) {
|
if (!evaluateBooleanJavaScriptExpression(m_scriptEngine, expression, &expressionValue, errorMessage)) {
|
||||||
*errorMessage = QString::fromLatin1("Error in @elsif at %1: %2").
|
*errorMessage = QString::fromLatin1("Error in @elsif at %1: %2").
|
||||||
arg(l + 1).arg(*errorMessage);
|
arg(l + 1).arg(*errorMessage);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QScriptEngine)
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -51,7 +53,8 @@ Blup
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
bool customWizardPreprocess(const QString &in, QString *out, QString *errorMessage);
|
bool customWizardPreprocess(const QString &in, QString *out, QString *errorMessage);
|
||||||
|
/* Helper to evaluate an expression. */
|
||||||
|
bool evaluateBooleanJavaScriptExpression(QScriptEngine &engine, const QString &expression, bool *result, QString *errorMessage);
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user