WSL/SLF GitLab Repository

Commit f1b0eb77 authored by Michael Reisecker's avatar Michael Reisecker
Browse files

Add "validity" button to Number panel

Also a logic change: The Number panel does not allow free text
anymore, i. e. if something is entered it _must_ be an expression (at
least for the warning to go away).
An exception are plain numbers, also possible in scientific notation.

I. e.:
2+2 <-- not ok
text <-- not ok
${{2+2}} <-- OK
${env:VAR} <-- OK
123 <-- OK
10e-3 <-- OK
(empty) <-- OK
parent 44b57c19
......@@ -175,7 +175,7 @@ This is INIshell's user guide.
<help>Coordinates display a little globe which will lead to a map collection.</help>
</parameter>
</frame>
<frame caption="Number input">
<frame caption="Number input" key="help-number">
<parameter key="BUFF_CHUNK_SIZE" type="number" format="integer+" default="365" help="Data buffer size">
<help>Integer value for MeteoIO's data buffering routines. Set to your simulation length.</help>
</parameter>
......
......@@ -22,6 +22,7 @@
#include "src/main/inishell.h"
#include <QDoubleSpinBox>
#include <QFontMetrics>
#include <QSpinBox>
#include <QTimer>
......@@ -116,7 +117,7 @@ Number::Number(const QString &section, const QString &key, const QDomNode &optio
expression_element_->setToolTip(number_element_->toolTip());
connect(expression_element_, &QLineEdit::textChanged, this, &Number::checkStrValue);
/* switch button and layout for number element plus button */
/* switch button and layout for number element plus buttons */
switch_button_ = new QToolButton;
connect(switch_button_, &QToolButton::toggled, this, &Number::switchToggle);
switch_button_->setAutoRaise(true);
......@@ -126,11 +127,24 @@ Number::Number(const QString &section, const QString &key, const QDomNode &optio
switch_button_->setIcon(getIcon("displaymathmode"));
switch_button_->setToolTip(tr("Enter an expression such as ${other_ini_key}, ${env:my_env_var} or ${{arithm. expression}}"));
/* action button */
validity_button_ = new QToolButton; //a button that can pop up if the text has a certain format
validity_button_->hide();
validity_button_->setStyleSheet("* {border: none}");
validity_button_->setCursor(Qt::PointingHandCursor);
QSize sz_label;
sz_label.setWidth(static_cast<int>(fontMetrics().boundingRect(Cst::u_warning).width()));
sz_label.setHeight(static_cast<int>(fontMetrics().boundingRect(Cst::u_warning).height()));
validity_button_->setFixedSize(sz_label);
validity_button_->setText(Cst::u_warning);
connect(validity_button_, &QToolButton::clicked, this, &Number::onValidButtonClicked);
switcher_layout_ = new QHBoxLayout;
switcher_layout_->addWidget(number_element_, 0, Qt::AlignLeft);
switcher_layout_->addWidget(switch_button_);
if (options.toElement().attribute("notoggle").toLower() == "true")
switch_button_->hide();
switcher_layout_->addWidget(validity_button_);
/* layout of basic elements */
auto *number_layout( new QHBoxLayout );
......@@ -387,9 +401,20 @@ void Number::checkStrValue(const QString &str_check)
{
bool evaluation_success;
setDefaultPanelStyles(str_check);
if (expr::checkExpression(str_check, evaluation_success, substitutions_) || !evaluation_success)
setInvalidStyle(!evaluation_success && !str_check.isEmpty());
if (str_check.isEmpty()) { //"empty" not considered "invalid"
setInvalidStyle(false); //(also gives mandatory styling priority)
validity_button_->hide();
return;
}
const bool is_expression = expr::checkExpression(str_check, evaluation_success, substitutions_);
const bool is_valid = is_expression && evaluation_success;
setInvalidStyle(!is_valid);
validity_button_->setText(is_valid? Cst::u_valid : Cst::u_warning);
validity_button_->show();
validity_button_->setToolTip(is_valid? tr("Expression has correct syntax") : tr("Expression has wrong syntax"));
validity_button_->setProperty("invalid", !is_valid? "true" : "false"); //set "invalid" style for additional button text
validity_button_->style()->unpolish(validity_button_);
validity_button_->style()->polish(validity_button_);
QTimer::singleShot(1, this, [=]{ setEmpty(false); });
setIniValue(str_check); //it is just a hint - save anyway
}
......@@ -504,6 +529,7 @@ void Number::switchToggle(bool checked)
switcher_layout_->replaceWidget(number_element_, expression_element_);
number_element_->hide();
expression_element_->show();
validity_button_->show();
if (!qobject_cast<QLabel*>(getEmphasisWidget()))
setEmphasisWidget(expression_element_); //switch widget to style with properties
setIniValue(expression_element_->text()); //always use the visible number in INI
......@@ -512,6 +538,8 @@ void Number::switchToggle(bool checked)
} else { //spin box mode
switcher_layout_->replaceWidget(expression_element_, number_element_);
expression_element_->hide();
validity_button_->hide();
setInvalidStyle(false);
number_element_->show();
if (!qobject_cast<QLabel*>(getEmphasisWidget()))
setEmphasisWidget(number_element_);
......@@ -526,3 +554,13 @@ void Number::switchToggle(bool checked)
}
}
}
/**
* @brief Event listener for the action button.
* @details That button displays info about valid/invalid expressions
* and is clickable to go to the help files.
*/
void Number::onValidButtonClicked()
{
getMainWindow()->loadHelp("Input panels 1", "help-number");
}
......@@ -69,6 +69,7 @@ class Number : public Atomic {
QLineEdit *expression_element_ = nullptr;
QHBoxLayout *switcher_layout_ = nullptr;
QToolButton *switch_button_ = nullptr;
QToolButton *validity_button_ = nullptr;
int default_precision_ = 2;
int precision_ = default_precision_; //current precision
number_mode mode_;
......@@ -81,6 +82,7 @@ class Number : public Atomic {
bool isNumber(const QString &expression) const;
void onPropertySet() override;
void switchToggle(bool checked);
void onValidButtonClicked();
};
#endif //NUMBER_H
......@@ -49,22 +49,22 @@ Textfield::Textfield(const QString &section, const QString &key, const QDomNode
connect(textfield_, &QLineEdit::textEdited, this, &Textfield::checkValue);
/* action button */
nav_button_ = new QToolButton; //a button that can pop up if the text has a certain format
nav_button_->setStyleSheet("* {border: none}");
validity_button_ = new QToolButton; //a button that can pop up if the text has a certain format
validity_button_->setStyleSheet("* {border: none}");
QSize sz_label;
sz_label.setWidth(static_cast<int>(fontMetrics().boundingRect(Cst::u_globe).width()) * 1.2);
sz_label.setHeight(static_cast<int>(fontMetrics().boundingRect(Cst::u_globe).height()));
nav_button_->setFixedSize(sz_label);
connect(nav_button_, &QToolButton::clicked, this, &Textfield::navButtonClicked);
validity_button_->setFixedSize(sz_label);
connect(validity_button_, &QToolButton::clicked, this, &Textfield::onValidButtonClicked);
/* layout of textbox plus button and the main layout */
auto *nav_button_layout( new QHBoxLayout );
nav_button_layout->addWidget(textfield_);
nav_button_layout->addWidget(nav_button_);
auto *validity_button_layout( new QHBoxLayout );
validity_button_layout->addWidget(textfield_);
validity_button_layout->addWidget(validity_button_);
auto *textfield_layout( new QHBoxLayout );
setLayoutMargins(textfield_layout);
textfield_layout->addWidget(key_label, 0, Qt::AlignLeft);
textfield_layout->addLayout(nav_button_layout);
textfield_layout->addLayout(validity_button_layout);
/* choose size of text box */
const QString size( options.toElement().attribute("size") );
......@@ -129,9 +129,9 @@ void Textfield::checkValue(const QString &text)
static const QRegularExpression rex_coord(regex_coord);
const QRegularExpressionMatch coord_match(rex_coord.match(text));
if (coord_match.captured(idx_full) == text && !text.isEmpty()) {
nav_button_->setText(Cst::u_globe);
nav_button_->setCursor(Qt::PointingHandCursor);
nav_button_->setToolTip(tr("Show online map"));
validity_button_->setText(Cst::u_globe);
validity_button_->setCursor(Qt::PointingHandCursor);
validity_button_->setToolTip(tr("Show online map"));
return;
}
......@@ -140,13 +140,13 @@ void Textfield::checkValue(const QString &text)
substitutions_, needs_prefix_for_evaluation_);
const bool is_invalid = is_expression && !evaluation_success;
setInvalidStyle(is_invalid);
nav_button_->setText(is_invalid? Cst::u_warning : (is_expression? Cst::u_valid : ""));
nav_button_->setCursor(is_expression? Qt::PointingHandCursor : Qt::ArrowCursor);
nav_button_->setToolTip(is_expression?
validity_button_->setText(is_invalid? Cst::u_warning : (is_expression? Cst::u_valid : ""));
validity_button_->setCursor(is_expression? Qt::PointingHandCursor : Qt::ArrowCursor);
validity_button_->setToolTip(is_expression?
(is_invalid? tr("Entered expression has wrong format") : tr("Valid expression")) : "");
nav_button_->setProperty("invalid", is_invalid? "true" : "false");
nav_button_->style()->unpolish(nav_button_);
nav_button_->style()->polish(nav_button_);
validity_button_->setProperty("invalid", is_invalid? "true" : "false");
validity_button_->style()->unpolish(validity_button_);
validity_button_->style()->polish(validity_button_);
} else { //check against regex specified in XML
......@@ -154,14 +154,14 @@ void Textfield::checkValue(const QString &text)
const QRegularExpressionMatch xml_match(rex_xml.match(text));
const bool is_invalid = xml_match.captured(idx_full) != text && !text.isEmpty();
setInvalidStyle(is_invalid);
nav_button_->setText(is_invalid? Cst::u_warning : (text.isEmpty()? "" : Cst::u_valid));
nav_button_->setCursor(text.isEmpty()? Qt::ArrowCursor : Qt::PointingHandCursor); //mark as link
nav_button_->setToolTip(text.isEmpty()? "" :
validity_button_->setText(is_invalid? Cst::u_warning : (text.isEmpty()? "" : Cst::u_valid));
validity_button_->setCursor(text.isEmpty()? Qt::ArrowCursor : Qt::PointingHandCursor); //mark as link
validity_button_->setToolTip(text.isEmpty()? "" :
(is_invalid? tr("Entered expression has wrong format") : tr("Valid expression")));
//set "invalid" style on navigation button also:
nav_button_->setProperty("invalid", is_invalid? "true" : "false");
nav_button_->style()->unpolish(nav_button_);
nav_button_->style()->polish(nav_button_);
validity_button_->setProperty("invalid", is_invalid? "true" : "false");
validity_button_->style()->unpolish(validity_button_);
validity_button_->style()->polish(validity_button_);
}
setIniValue(text); //checks are just a hint - set anyway
......@@ -169,14 +169,15 @@ void Textfield::checkValue(const QString &text)
/**
* @brief Event listener for the action button.
* @details Currently, the button is only shown for coordinates and will open the Browser
* with a map link.
* @details The button is only shown for coordinates and will open the Browser
* with a map link, or it acts to display info about valid/invalid expressions
* (then leading to the help files).
*/
void Textfield::navButtonClicked() //for now this button only pops up for coordinates
void Textfield::onValidButtonClicked() //for now this button only pops up for coordinates
{
if (nav_button_->text().isEmpty())
if (validity_button_->text().isEmpty())
return;
if (nav_button_->text() != Cst::u_globe) { //"valid" resp. "invalid" icons
if (validity_button_->text() != Cst::u_globe) { //"valid" resp. "invalid" icons
getMainWindow()->loadHelp("Input panels 1", "help-textfield");
return;
}
......
......@@ -48,13 +48,13 @@ class Textfield : public Atomic {
std::vector<std::pair<QString, QString>> substitutions_; //user-set substitutions to translate to tinyexpr
QString validation_regex_;
QLineEdit *textfield_ = nullptr;
QToolButton *nav_button_ = nullptr;
QToolButton *validity_button_ = nullptr;
bool needs_prefix_for_evaluation_ = true;
private slots:
void onPropertySet() override;
void checkValue(const QString &text);
void navButtonClicked();
void onValidButtonClicked();
};
#endif // TEXTFIELD_H
......@@ -38,6 +38,11 @@ namespace expr {
bool checkExpression(const QString &expression, bool &evaluation_success,
const std::vector< std::pair<QString, QString> > &substitutions, const bool &needs_prefix)
{
if (expression.isEmpty()) {
evaluation_success = false;
return false;
}
static const QString regex_envvar(R"(\${env:(.+)})"); //ex.: ${env:USER}
QString regex_expression;
if (needs_prefix)
......@@ -57,11 +62,6 @@ bool checkExpression(const QString &expression, bool &evaluation_success,
static const size_t idx_total = 0;
static const size_t idx_check = 1;
if (expression.isEmpty()) {
evaluation_success = false;
return false;
}
if (match_envvar.captured(idx_total) == expression) {
/* check if environment variable is set */
const QByteArray envvar( qgetenv(match_envvar.captured(idx_check).toLocal8Bit()) );
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment