1
/***************************************************************************
2
* Copyright (c) 2015 Eivind Kvedalen <eivind@kvedalen.name> *
4
* This file is part of the FreeCAD CAx development system. *
6
* This library is free software; you can redistribute it and/or *
7
* modify it under the terms of the GNU Library General Public *
8
* License as published by the Free Software Foundation; either *
9
* version 2 of the License, or (at your option) any later version. *
11
* This library is distributed in the hope that it will be useful, *
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
* GNU Library General Public License for more details. *
16
* You should have received a copy of the GNU Library General Public *
17
* License along with this library; see the file COPYING.LIB. If not, *
18
* write to the Free Software Foundation, Inc., 51 Franklin Street, *
19
* Fifth Floor, Boston, MA 02110-1301, USA *
21
***************************************************************************/
23
#include "PreCompiled.h"
25
#include <QApplication>
30
#include <App/Application.h>
31
#include <App/DocumentObject.h>
32
#include <App/ExpressionParser.h>
33
#include <Base/Tools.h>
35
#include "DlgExpressionInput.h"
36
#include "ui_DlgExpressionInput.h"
41
using namespace Gui::Dialog;
43
DlgExpressionInput::DlgExpressionInput(const App::ObjectIdentifier & _path,
44
std::shared_ptr<const Expression> _expression,
45
const Base::Unit & _impliedUnit, QWidget *parent)
47
, ui(new Ui::DlgExpressionInput)
48
, expression(_expression ? _expression->copy() : nullptr)
51
, impliedUnit(_impliedUnit)
54
assert(path.getDocumentObject());
60
connect(ui->expression, &ExpressionLineEdit::textChanged,
61
this, &DlgExpressionInput::textChanged);
62
connect(ui->discardBtn, &QPushButton::clicked,
63
this, &DlgExpressionInput::setDiscarded);
66
ui->expression->setText(Base::Tools::fromStdString(expression->toString()));
69
QVariant text = parent->property("text");
70
if (text.canConvert<QString>()) {
71
ui->expression->setText(text.toString());
75
// Set document object on line edit to create auto completer
76
DocumentObject * docObj = path.getDocumentObject();
77
ui->expression->setDocumentObject(docObj);
79
// There are some platforms where setting no system background causes a black
80
// rectangle to appear. To avoid this the 'NoSystemBackground' parameter can be
81
// set to false. Then a normal non-modal dialog will be shown instead (#0002440).
82
bool noBackground = App::GetApplication().GetParameterGroupByPath
83
("User parameter:BaseApp/Preferences/Expression")->GetBool("NoSystemBackground", false);
87
setWindowFlags(Qt::Widget | Qt::Popup | Qt::FramelessWindowHint);
89
setWindowFlags(Qt::SubWindow | Qt::Widget | Qt::Popup | Qt::FramelessWindowHint);
91
setAttribute(Qt::WA_NoSystemBackground, true);
92
setAttribute(Qt::WA_TranslucentBackground, true);
95
ui->expression->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
96
ui->horizontalSpacer_3->changeSize(0, 2);
97
ui->verticalLayout->setContentsMargins(9, 9, 9, 9);
99
// It is strange that (at least on Linux) DlgExpressionInput will shrink
100
// to be narrower than ui->expression after calling adjustSize() above.
102
if(this->width() < ui->expression->width() + 18)
103
this->resize(ui->expression->width()+18,this->height());
105
ui->expression->setFocus();
108
DlgExpressionInput::~DlgExpressionInput()
113
void NumberRange::setRange(double min, double max)
120
void NumberRange::clearRange()
125
void NumberRange::throwIfOutOfRange(const Base::Quantity& value) const
130
if (value.getValue() < minimum || value.getValue() > maximum) {
131
Base::Quantity minVal(minimum, value.getUnit());
132
Base::Quantity maxVal(maximum, value.getUnit());
133
QString valStr = value.getUserString();
134
QString minStr = minVal.getUserString();
135
QString maxStr = maxVal.getUserString();
136
QString error = QString::fromLatin1("Value out of range (%1 out of [%2, %3])").arg(valStr, minStr, maxStr);
138
throw Base::ValueError(error.toStdString());
142
void DlgExpressionInput::setRange(double minimum, double maximum)
144
numberRange.setRange(minimum, maximum);
147
void DlgExpressionInput::clearRange()
149
numberRange.clearRange();
152
QPoint DlgExpressionInput::expressionPosition() const
154
return ui->expression->pos();
157
void DlgExpressionInput::textChanged(const QString &text)
159
if (text.isEmpty()) {
160
ui->okBtn->setDisabled(true);
161
ui->discardBtn->setDefault(true);
165
ui->okBtn->setDefault(true);
168
//resize the input field according to text size
169
QFontMetrics fm(ui->expression->font());
170
int width = QtTools::horizontalAdvance(fm, text) + 15;
171
if (width < minimumWidth)
172
ui->expression->setMinimumWidth(minimumWidth);
174
ui->expression->setMinimumWidth(width);
176
if(this->width() < ui->expression->minimumWidth())
177
setMinimumWidth(ui->expression->minimumWidth());
179
//now handle expression
180
std::shared_ptr<Expression> expr(ExpressionParser::parse(path.getDocumentObject(), text.toUtf8().constData()));
183
std::string error = path.getDocumentObject()->ExpressionEngine.validateExpression(path, expr);
186
throw Base::RuntimeError(error.c_str());
188
std::unique_ptr<Expression> result(expr->eval());
191
ui->okBtn->setEnabled(true);
194
//set default palette as we may have read text right now
195
ui->msg->setPalette(ui->okBtn->palette());
197
auto * n = Base::freecad_dynamic_cast<NumberExpression>(result.get());
199
Base::Quantity value = n->getQuantity();
200
QString msg = value.getUserString();
202
if (!value.isValid()) {
203
throw Base::ValueError("Not a number");
205
else if (!impliedUnit.isEmpty()) {
206
if (!value.getUnit().isEmpty() && value.getUnit() != impliedUnit)
207
throw Base::UnitsMismatchError("Unit mismatch between result and required unit");
209
value.setUnit(impliedUnit);
212
else if (!value.getUnit().isEmpty()) {
213
msg += QString::fromUtf8(" (Warning: unit discarded)");
215
QPalette p(ui->msg->palette());
216
p.setColor(QPalette::WindowText, Qt::red);
217
ui->msg->setPalette(p);
220
numberRange.throwIfOutOfRange(value);
222
ui->msg->setText(msg);
225
ui->msg->setText(Base::Tools::fromStdString(result->toString()));
230
catch (Base::Exception & e) {
231
ui->msg->setText(QString::fromUtf8(e.what()));
232
QPalette p(ui->msg->palette());
233
p.setColor(QPalette::WindowText, Qt::red);
234
ui->msg->setPalette(p);
235
ui->okBtn->setDisabled(true);
239
void DlgExpressionInput::setDiscarded()
245
void DlgExpressionInput::setExpressionInputSize(int width, int height)
247
if (ui->expression->minimumHeight() < height)
248
ui->expression->setMinimumHeight(height);
250
if (ui->expression->minimumWidth() < width)
251
ui->expression->setMinimumWidth(width);
253
minimumWidth = width;
256
void DlgExpressionInput::mouseReleaseEvent(QMouseEvent* ev)
261
void DlgExpressionInput::mousePressEvent(QMouseEvent* ev)
265
// The 'FramelessWindowHint' is also set when the background is transparent.
266
if (windowFlags() & Qt::FramelessWindowHint) {
267
//we need to reject the dialog when clicked on the background. As the background is transparent
268
//this is the expected behaviour for the user
269
bool on = ui->expression->completerActive();
275
void DlgExpressionInput::show()
278
this->activateWindow();
279
ui->expression->selectAll();
283
#include "moc_DlgExpressionInput.cpp"