mirror of
https://github.com/leozide/leocad.git
synced 2026-10-26 22:10:32 +00:00
Reject invalid Array and transform input with optional results
Rename the localized float parser to lcParseFloatValueLocalized and return std::optional<float> so conversion failures and nonfinite values cannot silently become zero. Return std::optional<lcVector3> from GetTransformAmount and apply transforms only when every nonempty axis is valid, preserving blank axes as zero. Validate all Array offsets and rotations before updating dialog results, and show an informational message with focus on invalid input. Verified with a macOS Qt debug build and actual Array/transform checks in US English, German, and Arabic locales, including blank input, overflow, NaN, and infinity.
This commit is contained in:
1 parent
2125868dc6
commit
5c1126519d
5 files changed
+80
-32
No files matched your search
+38
-21
@@ -76,27 +76,44 @@ void lcArrayDialog::accept()
|
||||
return;
|
||||
}
|
||||
|
||||
mCounts[0] = Counts[0];
|
||||
mCounts[1] = Counts[1];
|
||||
mCounts[2] = Counts[2];
|
||||
mOffsets[0].x = lcParseValueLocalized(ui->offset1x->text());
|
||||
mOffsets[0].y = lcParseValueLocalized(ui->offset1y->text());
|
||||
mOffsets[0].z = lcParseValueLocalized(ui->offset1z->text());
|
||||
mOffsets[1].x = lcParseValueLocalized(ui->offset2x->text());
|
||||
mOffsets[1].y = lcParseValueLocalized(ui->offset2y->text());
|
||||
mOffsets[1].z = lcParseValueLocalized(ui->offset2z->text());
|
||||
mOffsets[2].x = lcParseValueLocalized(ui->offset3x->text());
|
||||
mOffsets[2].y = lcParseValueLocalized(ui->offset3y->text());
|
||||
mOffsets[2].z = lcParseValueLocalized(ui->offset3z->text());
|
||||
mRotations[0].x = lcParseValueLocalized(ui->rotation1x->text());
|
||||
mRotations[0].y = lcParseValueLocalized(ui->rotation1y->text());
|
||||
mRotations[0].z = lcParseValueLocalized(ui->rotation1z->text());
|
||||
mRotations[1].x = lcParseValueLocalized(ui->rotation2x->text());
|
||||
mRotations[1].y = lcParseValueLocalized(ui->rotation2y->text());
|
||||
mRotations[1].z = lcParseValueLocalized(ui->rotation2z->text());
|
||||
mRotations[2].x = lcParseValueLocalized(ui->rotation3x->text());
|
||||
mRotations[2].y = lcParseValueLocalized(ui->rotation3y->text());
|
||||
mRotations[2].z = lcParseValueLocalized(ui->rotation3z->text());
|
||||
QLineEdit* Edits[2][3][3] =
|
||||
{
|
||||
{
|
||||
{ ui->offset1x, ui->offset1y, ui->offset1z },
|
||||
{ ui->offset2x, ui->offset2y, ui->offset2z },
|
||||
{ ui->offset3x, ui->offset3y, ui->offset3z }
|
||||
},
|
||||
{
|
||||
{ ui->rotation1x, ui->rotation1y, ui->rotation1z },
|
||||
{ ui->rotation2x, ui->rotation2y, ui->rotation2z },
|
||||
{ ui->rotation3x, ui->rotation3y, ui->rotation3z }
|
||||
}
|
||||
};
|
||||
lcVector3 Values[2][3];
|
||||
|
||||
for (int Type = 0; Type < 2; Type++)
|
||||
for (int Dimension = 0; Dimension < 3; Dimension++)
|
||||
for (int Axis = 0; Axis < 3; Axis++)
|
||||
{
|
||||
QLineEdit* Edit = Edits[Type][Dimension][Axis];
|
||||
const std::optional<float> Value = lcParseFloatValueLocalized(Edit->text(), Edit->validator()->locale());
|
||||
|
||||
if (!Value || !Edit->hasAcceptableInput())
|
||||
{
|
||||
QMessageBox::information(this, windowTitle(), tr("Please enter a valid value for '%1'.").arg(Edit->accessibleName()));
|
||||
Edit->setFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
Values[Type][Dimension][Axis] = *Value;
|
||||
}
|
||||
|
||||
for (int Dimension = 0; Dimension < 3; Dimension++)
|
||||
{
|
||||
mCounts[Dimension] = Counts[Dimension];
|
||||
mOffsets[Dimension] = Values[0][Dimension];
|
||||
mRotations[Dimension] = Values[1][Dimension];
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
@@ -2073,15 +2073,35 @@ void lcMainWindow::SetInsertPieceData(lcPieceData* PieceData)
|
||||
lcGetPiecesLibrary()->RequestPieceDataLoad(mInsertPieceData.Get(), lcLoadPriority::Normal);
|
||||
}
|
||||
|
||||
lcVector3 lcMainWindow::GetTransformAmount()
|
||||
std::optional<lcVector3> lcMainWindow::GetTransformAmount()
|
||||
{
|
||||
lcVector3 Transform;
|
||||
QLineEdit* Edits[] = { mTransformXEdit, mTransformYEdit, mTransformZEdit };
|
||||
lcVector3 Values;
|
||||
|
||||
Transform.x = lcParseValueLocalized(mTransformXEdit->text());
|
||||
Transform.y = lcParseValueLocalized(mTransformYEdit->text());
|
||||
Transform.z = lcParseValueLocalized(mTransformZEdit->text());
|
||||
for (int Axis = 0; Axis < 3; Axis++)
|
||||
{
|
||||
QLineEdit* Edit = Edits[Axis];
|
||||
const QString Text = Edit->text().trimmed();
|
||||
|
||||
return Transform;
|
||||
if (Text.isEmpty())
|
||||
{
|
||||
Values[Axis] = 0.0f;
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::optional<float> Value = lcParseFloatValueLocalized(Text, Edit->locale());
|
||||
|
||||
if (!Value)
|
||||
{
|
||||
QMessageBox::information(this, tr("Transform"), tr("Please enter a valid value for '%1'.").arg(Edit->accessibleName()));
|
||||
Edit->setFocus();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
Values[Axis] = *Value;
|
||||
}
|
||||
|
||||
return Values;
|
||||
}
|
||||
|
||||
void lcMainWindow::SplitView(Qt::Orientation Orientation)
|
||||
@@ -3730,7 +3750,12 @@ void lcMainWindow::HandleCommand(lcCommandId CommandId)
|
||||
|
||||
case LC_EDIT_TRANSFORM:
|
||||
if (ActiveModel)
|
||||
ActiveModel->TransformSelectedObjects(GetTransformType(), GetTransformAmount());
|
||||
{
|
||||
const std::optional<lcVector3> Transform = GetTransformAmount();
|
||||
|
||||
if (Transform)
|
||||
ActiveModel->TransformSelectedObjects(GetTransformType(), *Transform);
|
||||
}
|
||||
break;
|
||||
|
||||
case LC_EDIT_TRANSFORM_ABSOLUTE_TRANSLATION:
|
||||
|
||||
@@ -259,7 +259,7 @@ public:
|
||||
void UpdateModified(bool Modified);
|
||||
void UpdateShortcuts();
|
||||
|
||||
lcVector3 GetTransformAmount();
|
||||
std::optional<lcVector3> GetTransformAmount();
|
||||
|
||||
bool eventFilter(QObject* Object, QEvent* Event) override;
|
||||
|
||||
|
||||
+8
-2
@@ -90,9 +90,15 @@ QString lcFormatIntegerLocalized(qlonglong Value, QLocale Locale)
|
||||
return Locale.toString(Value);
|
||||
}
|
||||
|
||||
float lcParseValueLocalized(const QString& Value)
|
||||
std::optional<float> lcParseFloatValueLocalized(const QString& Value, QLocale Locale)
|
||||
{
|
||||
return QLocale::system().toFloat(Value);
|
||||
bool Ok;
|
||||
const float Number = Locale.toFloat(Value, &Ok);
|
||||
|
||||
if (!Ok || !std::isfinite(Number))
|
||||
return std::nullopt;
|
||||
|
||||
return Number;
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ constexpr int LC_MAX_AREA_LIGHT_GRID = 64;
|
||||
QString lcFormatValue(float Value, int Precision);
|
||||
QString lcFormatValueLocalized(float Value);
|
||||
QString lcFormatIntegerLocalized(qlonglong Value, QLocale Locale);
|
||||
float lcParseValueLocalized(const QString& Value);
|
||||
std::optional<float> lcParseFloatValueLocalized(const QString& Value, QLocale Locale);
|
||||
|
||||
void lcSetupDialogHelp(QDialog* Dialog, QDialogButtonBox* ButtonBox);
|
||||
void lcSetupWidgetHelp(QWidget* Root, QDialogButtonBox* ButtonBox);
|
||||
|
||||
Reference in new issue
Block a user