FreeCAD

Форк
0
/
DlgExpressionInput.cpp 
746 строк · 24.9 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2015 Eivind Kvedalen <eivind@kvedalen.name>             *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
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.      *
10
 *                                                                         *
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.                  *
15
 *                                                                         *
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                              *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
#include <QApplication>
26
#include <QMenu>
27
#include <QMouseEvent>
28
#include <QTreeWidget>
29
#endif
30

31
#include <App/Application.h>
32
#include <App/Document.h>
33
#include <App/DocumentObject.h>
34
#include <App/ExpressionParser.h>
35
#include <App/VarSet.h>
36
#include <Base/Tools.h>
37

38
#include "DlgExpressionInput.h"
39
#include "ui_DlgExpressionInput.h"
40
#include "Application.h"
41
#include "Command.h"
42
#include "Tools.h"
43
#include "ExpressionBinding.h"
44
#include "BitmapFactory.h"
45
#include "ViewProviderDocumentObject.h"
46

47
using namespace App;
48
using namespace Gui::Dialog;
49

50
bool DlgExpressionInput::varSetsVisible = false;
51

52
DlgExpressionInput::DlgExpressionInput(const App::ObjectIdentifier & _path,
53
                                       std::shared_ptr<const Expression> _expression,
54
                                       const Base::Unit & _impliedUnit, QWidget *parent)
55
  : QDialog(parent)
56
  , ui(new Ui::DlgExpressionInput)
57
  , expression(_expression ? _expression->copy() : nullptr)
58
  , path(_path)
59
  , discarded(false)
60
  , impliedUnit(_impliedUnit)
61
  , minimumWidth(10)
62
{
63
    assert(path.getDocumentObject());
64

65
    // Setup UI
66
    ui->setupUi(this);
67

68
    initializeVarSets();
69

70
    // Connect signal(s)
71
    connect(ui->expression, &ExpressionLineEdit::textChanged,
72
        this, &DlgExpressionInput::textChanged);
73
    connect(ui->discardBtn, &QPushButton::clicked,
74
        this, &DlgExpressionInput::setDiscarded);
75

76
    if (expression) {
77
        ui->expression->setText(Base::Tools::fromStdString(expression->toString()));
78
    }
79
    else {
80
        QVariant text = parent->property("text");
81
        if (text.canConvert<QString>()) {
82
            ui->expression->setText(text.toString());
83
        }
84
    }
85

86
    // Set document object on line edit to create auto completer
87
    DocumentObject * docObj = path.getDocumentObject();
88
    ui->expression->setDocumentObject(docObj);
89

90
    // There are some platforms where setting no system background causes a black
91
    // rectangle to appear. To avoid this the 'NoSystemBackground' parameter can be
92
    // set to false. Then a normal non-modal dialog will be shown instead (#0002440).
93
    bool noBackground = App::GetApplication().GetParameterGroupByPath
94
        ("User parameter:BaseApp/Preferences/Expression")->GetBool("NoSystemBackground", false);
95

96
    if (noBackground) {
97
#if defined(Q_OS_MACOS)
98
        setWindowFlags(Qt::Widget | Qt::Popup | Qt::FramelessWindowHint);
99
#else
100
        setWindowFlags(Qt::SubWindow | Qt::Widget | Qt::Popup | Qt::FramelessWindowHint);
101
#endif
102
        setAttribute(Qt::WA_NoSystemBackground, true);
103
        setAttribute(Qt::WA_TranslucentBackground, true);
104
    }
105
    else {
106
        ui->expression->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
107
        ui->horizontalSpacer_3->changeSize(0, 2);
108
        ui->verticalLayout->setContentsMargins(9, 9, 9, 9);
109
        this->adjustSize();
110
        // It is strange that (at least on Linux) DlgExpressionInput will shrink
111
        // to be narrower than ui->expression after calling adjustSize() above.
112
        // Why?
113
        if(this->width() < ui->expression->width() + 18)
114
            this->resize(ui->expression->width()+18,this->height());
115
    }
116
    ui->expression->setFocus();
117
}
118

119
DlgExpressionInput::~DlgExpressionInput()
120
{
121
    delete ui;
122
}
123

124
static void getVarSetsDocument(std::vector<App::VarSet*>& varSets, App::Document* doc) {
125
    for (auto obj : doc->getObjects()) {
126
        auto varSet = dynamic_cast<App::VarSet*>(obj);
127
        if (varSet) {
128
            varSets.push_back(varSet);
129
        }
130
    }
131
}
132

133
static std::vector<App::VarSet*> getAllVarSets()
134
{
135
    std::vector<App::Document*> docs = App::GetApplication().getDocuments();
136
    std::vector<App::VarSet*> varSets;
137

138
    for (auto doc : docs) {
139
        getVarSetsDocument(varSets, doc);
140
    }
141

142
    return varSets;
143
}
144

145
Base::Type DlgExpressionInput::getTypePath()
146
{
147
    return path.getProperty()->getTypeId();
148
}
149

150
Base::Type DlgExpressionInput::determineTypeVarSet()
151
{
152
    Base::Type typePath = getTypePath();
153

154
    // The type of the path is leading.  If it is one of the types below, we
155
    // can create a property in the varset.
156
    if (typePath == App::PropertyString::getClassTypeId() ||
157
        typePath.isDerivedFrom(App::PropertyFloat::getClassTypeId()) ||
158
        typePath.isDerivedFrom(App::PropertyInteger::getClassTypeId())) {
159
        return typePath;
160
    }
161

162
    // If we cannot determine the type by means of the path, for example when
163
    // dealing with a sketcher constraint list or with the x, y, or z of a
164
    // Placement, the type of the unit allows us to create a property in the
165
    // varset.  Since unit properties are derived from App::PropertyFloat, it
166
    // allows us to create a property and set the value.
167

168
    std::string unitTypeString = impliedUnit.getTypeString().toStdString();
169
    if (unitTypeString.empty()) {
170
        // no type was provided
171
        return Base::Type::badType();
172
    }
173

174
    std::string typeString = "App::Property" + unitTypeString;
175
    // may return badType
176
    return Base::Type::fromName(typeString.c_str());
177
}
178

179
bool DlgExpressionInput::typeOkForVarSet()
180
{
181
    std::string unitType = impliedUnit.getTypeString().toStdString();
182
    return determineTypeVarSet() != Base::Type::badType();
183
}
184

185
void DlgExpressionInput::initializeVarSets()
186
{
187
    ui->labelInfoActive->setAlignment(Qt::AlignTop | Qt::AlignLeft);
188
    ui->labelInfoActive->setWordWrap(true);
189

190
    connect(ui->checkBoxVarSets, &QCheckBox::stateChanged,
191
            this, &DlgExpressionInput::onCheckVarSets);
192
    connect(ui->comboBoxVarSet, qOverload<int>(&QComboBox::currentIndexChanged),
193
            this, &DlgExpressionInput::onVarSetSelected);
194
    connect(ui->lineEditGroup, &QLineEdit::textChanged,
195
            this, &DlgExpressionInput::onTextChangedGroup);
196
    connect(ui->lineEditPropNew, &QLineEdit::textChanged,
197
            this, &DlgExpressionInput::namePropChanged);
198

199
    std::vector<App::VarSet*> varSets = getAllVarSets();
200
    if (!varSets.empty() && typeOkForVarSet()) {
201
        ui->checkBoxVarSets->setVisible(true);
202
        ui->checkBoxVarSets->setCheckState(varSetsVisible ? Qt::Checked : Qt::Unchecked);
203
        ui->groupBoxVarSets->setVisible(varSetsVisible);
204
        if (varSetsVisible) {
205
            setupVarSets();
206
        }
207
    }
208
    else {
209
        // The dialog is shown without any VarSet options.
210
        varSetsVisible = false;
211
        ui->checkBoxVarSets->setVisible(false);
212
        ui->groupBoxVarSets->setVisible(false);
213
    }
214
}
215

216
void NumberRange::setRange(double min, double max)
217
{
218
    minimum = min;
219
    maximum = max;
220
    defined = true;
221
}
222

223
void NumberRange::clearRange()
224
{
225
    defined = false;
226
}
227

228
void NumberRange::throwIfOutOfRange(const Base::Quantity& value) const
229
{
230
    if (!defined)
231
        return;
232

233
    if (value.getValue() < minimum || value.getValue() > maximum) {
234
        Base::Quantity minVal(minimum, value.getUnit());
235
        Base::Quantity maxVal(maximum, value.getUnit());
236
        QString valStr = value.getUserString();
237
        QString minStr = minVal.getUserString();
238
        QString maxStr = maxVal.getUserString();
239
        QString error = QString::fromLatin1("Value out of range (%1 out of [%2, %3])").arg(valStr, minStr, maxStr);
240

241
        throw Base::ValueError(error.toStdString());
242
    }
243
}
244

245
void DlgExpressionInput::setRange(double minimum, double maximum)
246
{
247
    numberRange.setRange(minimum, maximum);
248
}
249

250
void DlgExpressionInput::clearRange()
251
{
252
    numberRange.clearRange();
253
}
254

255
QPoint DlgExpressionInput::expressionPosition() const
256
{
257
    return ui->expression->pos();
258
}
259

260
void DlgExpressionInput::checkExpression(const QString& text)
261
{
262
        //now handle expression
263
        std::shared_ptr<Expression> expr(ExpressionParser::parse(path.getDocumentObject(), text.toUtf8().constData()));
264

265
        if (expr) {
266
            std::string error = path.getDocumentObject()->ExpressionEngine.validateExpression(path, expr);
267

268
            if (!error.empty())
269
                throw Base::RuntimeError(error.c_str());
270

271
            std::unique_ptr<Expression> result(expr->eval());
272

273
            expression = expr;
274
            ui->okBtn->setEnabled(true);
275
            ui->msg->clear();
276

277
            //set default palette as we may have read text right now
278
            ui->msg->setPalette(ui->okBtn->palette());
279

280
            auto * n = Base::freecad_dynamic_cast<NumberExpression>(result.get());
281
            if (n) {
282
                Base::Quantity value = n->getQuantity();
283
                QString msg = value.getUserString();
284

285
                if (!value.isValid()) {
286
                    throw Base::ValueError("Not a number");
287
                }
288
                else if (!impliedUnit.isEmpty()) {
289
                    if (!value.getUnit().isEmpty() && value.getUnit() != impliedUnit)
290
                        throw Base::UnitsMismatchError("Unit mismatch between result and required unit");
291

292
                    value.setUnit(impliedUnit);
293

294
                }
295
                else if (!value.getUnit().isEmpty()) {
296
                    msg += QString::fromUtf8(" (Warning: unit discarded)");
297

298
                    QPalette p(ui->msg->palette());
299
                    p.setColor(QPalette::WindowText, Qt::red);
300
                    ui->msg->setPalette(p);
301
                }
302

303
                numberRange.throwIfOutOfRange(value);
304

305
                ui->msg->setText(msg);
306
            }
307
            else {
308
                ui->msg->setText(Base::Tools::fromStdString(result->toString()));
309
            }
310

311
        }
312
}
313

314
static const bool NO_CHECK_EXPR = false;
315

316
void DlgExpressionInput::textChanged(const QString &text)
317
{
318
    if (text.isEmpty()) {
319
        ui->okBtn->setDisabled(true);
320
        ui->discardBtn->setDefault(true);
321
        return;
322
    }
323

324
    ui->okBtn->setDefault(true);
325

326
    try {
327
        //resize the input field according to text size
328
        QFontMetrics fm(ui->expression->font());
329
        int width = QtTools::horizontalAdvance(fm, text) + 15;
330
        if (width < minimumWidth)
331
            ui->expression->setMinimumWidth(minimumWidth);
332
        else
333
            ui->expression->setMinimumWidth(width);
334

335
        if(this->width() < ui->expression->minimumWidth())
336
            setMinimumWidth(ui->expression->minimumWidth());
337

338
        checkExpression(text);
339
        if (varSetsVisible) {
340
            // If varsets are visible, check whether the varset info also
341
            // agrees that the button should be enabled.
342
            // No need to check the expression in that function.
343
            updateVarSetInfo(NO_CHECK_EXPR);
344
        }
345
    }
346
    catch (Base::Exception & e) {
347
        ui->msg->setText(QString::fromUtf8(e.what()));
348
        QPalette p(ui->msg->palette());
349
        p.setColor(QPalette::WindowText, Qt::red);
350
        ui->msg->setPalette(p);
351
        ui->okBtn->setDisabled(true);
352
    }
353
}
354

355
void DlgExpressionInput::setDiscarded()
356
{
357
    discarded = true;
358
    reject();
359
}
360

361
void DlgExpressionInput::setExpressionInputSize(int width, int height)
362
{
363
    if (ui->expression->minimumHeight() < height)
364
        ui->expression->setMinimumHeight(height);
365

366
    if (ui->expression->minimumWidth() < width)
367
        ui->expression->setMinimumWidth(width);
368

369
    minimumWidth = width;
370
}
371

372
void DlgExpressionInput::mouseReleaseEvent(QMouseEvent* ev)
373
{
374
    Q_UNUSED(ev);
375
}
376

377
void DlgExpressionInput::mousePressEvent(QMouseEvent* ev)
378
{
379
    Q_UNUSED(ev);
380

381
    // The 'FramelessWindowHint' is also set when the background is transparent.
382
    if (windowFlags() & Qt::FramelessWindowHint) {
383
        //we need to reject the dialog when clicked on the background. As the background is transparent
384
        //this is the expected behaviour for the user
385
        bool on = ui->expression->completerActive();
386
        if (!on)
387
            this->reject();
388
    }
389
}
390

391
void DlgExpressionInput::show()
392
{
393
    QDialog::show();
394
    this->activateWindow();
395
    ui->expression->selectAll();
396
}
397

398
class Binding : public Gui::ExpressionBinding
399
{
400
    // helper class to compensate for the fact that
401
    // ExpressionBinding::setExpression is protected.
402
public:
403
    Binding() = default;
404

405
    void setExpression(std::shared_ptr<App::Expression> expr) override
406
    {
407
        ExpressionBinding::setExpression(expr);
408
    }
409
};
410

411
static bool isNamePropOk(const QString& nameProp, App::DocumentObject* obj,
412
                         std::stringstream& message)
413
{
414
    if (!obj) {
415
        message << "Unknown object";
416
        return false;
417
    }
418

419
    std::string name = nameProp.toStdString();
420
    if (name.empty()) {
421
        message << "Please provide a name for the property.";
422
        return false;
423
    }
424

425
    if (name != Base::Tools::getIdentifier(name)) {
426
        message << "Invalid property name (must only contain alphanumericals, underscore, "
427
                << "and must not start with digit";
428
        return false;
429
    }
430

431
    auto prop = obj->getPropertyByName(name.c_str());
432
    if (prop && prop->getContainer() == obj) {
433
        message << name << " already exists";
434
        return false;
435
    }
436

437
    return true;
438
}
439

440
static const int ROLE_DOC = Qt::UserRole;
441
static const int ROLE_VARSET_NAME = Qt::UserRole + 1;
442
static const int ROLE_VARSET_LABEL = Qt::UserRole + 2;
443
static const int ROLE_GROUP = Qt::UserRole + 3;
444

445
static QString getValue(QTreeWidgetItem* item, int role)
446
{
447
    QVariant variant = item->data(0, role);
448
    return variant.toString();
449
}
450

451
void DlgExpressionInput::acceptWithVarSet()
452
{
453
    // all checks have been performed in updateVarSetInfo and textChanged that
454
    // decide to enable the button
455

456
    // create a property in the VarSet
457
    QTreeWidgetItem *selected = treeWidget->currentItem();
458
    QString nameVarSet = getValue(selected, ROLE_VARSET_NAME);
459
    QString nameGroup = ui->lineEditGroup->text();
460
    QString nameProp = ui->lineEditPropNew->text();
461

462
    QString nameDoc = getValue(selected, ROLE_DOC);
463
    App::Document* doc = App::GetApplication().getDocument(nameDoc.toUtf8());
464
    App::DocumentObject* obj = doc->getObject(nameVarSet.toUtf8());
465

466
    std::string name = nameProp.toStdString();
467
    std::string group = nameGroup.toStdString();
468
    std::string type = getType();
469
    auto prop = obj->addDynamicProperty(type.c_str(), name.c_str(), group.c_str());
470

471
    // Set the value of the property in the VarSet
472
    //
473
    // The value of the property is going to be the value that was originally
474
    // meant to be the value for the property that this dialog is targeting.
475
    Expression* exprSimplfied = expression->simplify();
476
    auto ne = dynamic_cast<NumberExpression*>(exprSimplfied);
477
    auto se = dynamic_cast<StringExpression*>(exprSimplfied);
478
    if (ne) {
479
        // the value is a number: directly assign it to the property instead of
480
        // making it an expression in the variable set
481
        Gui::Command::doCommand(Gui::Command::Doc, "App.getDocument('%s').getObject('%s').%s = %f",
482
                                obj->getDocument()->getName(),
483
                                obj->getNameInDocument(),
484
                                prop->getName(), ne->getValue());
485
    }
486
    else if (se) {
487
        // the value is a string: directly assign it to the property.
488
        Gui::Command::doCommand(Gui::Command::Doc, "App.getDocument('%s').getObject('%s').%s = \"%s\"",
489
                                obj->getDocument()->getName(),
490
                                obj->getNameInDocument(),
491
                                prop->getName(), se->getText().c_str());
492
    }
493
    else {
494
        // the value is an epxression: make an expression binding in the variable set.
495
        ObjectIdentifier objId(*prop);
496
        Binding binding;
497
        binding.bind(objId);
498
        binding.setExpression(expression);
499
        binding.apply();
500
    }
501

502
    // Create a new expression that refers to the property in the variable set
503
    // for the original property that is the target of this dialog.
504
    expression.reset(ExpressionParser::parse(path.getDocumentObject(),
505
                                             prop->getFullName().c_str()));
506
}
507

508
void DlgExpressionInput::accept() {
509
    if (varSetsVisible) {
510
        acceptWithVarSet();
511
    }
512
    QDialog::accept();
513
}
514

515
static void addGroupsVarSetComboBox(App::VarSet* varSet, QTreeWidgetItem* varSetItem)
516
{
517
    std::vector<Property*> properties;
518
    std::set<std::string> namesGroup;
519
    varSet->getPropertyList(properties);
520
    for (auto prop : properties) {
521
        const char* nameGroup = prop->getGroup();
522
        if (!nameGroup || strcmp(nameGroup, "") == 0) {
523
            namesGroup.insert("Base");
524
        }
525
        else {
526
            namesGroup.insert(nameGroup);
527
        }
528
    }
529
    for (const auto& nameGroup : namesGroup) {
530
        // the item will be automatically destroyed when the varSetItem will be destroyed
531
        auto item = new QTreeWidgetItem(varSetItem);
532
        item->setText(0, QString::fromStdString(nameGroup));
533
        item->setData(0, ROLE_GROUP, QString::fromStdString(nameGroup));
534
        item->setData(0, ROLE_VARSET_NAME, varSetItem->data(0, ROLE_VARSET_NAME));
535
        item->setData(0, ROLE_VARSET_LABEL, varSetItem->data(0, ROLE_VARSET_LABEL));
536
        item->setData(0, ROLE_DOC, varSetItem->data(0, ROLE_DOC));
537
    }
538
}
539

540
static void addVarSetsVarSetComboBox(std::vector<App::VarSet*>& varSets, QTreeWidgetItem* docItem)
541
{
542
    for (auto varSet : varSets) {
543
        auto vp = Base::freecad_dynamic_cast<Gui::ViewProviderDocumentObject>(
544
                Gui::Application::Instance->getViewProvider(varSet));
545
        // the item will be automatically destroyed when the docItem will be destroyed
546
        auto item = new QTreeWidgetItem(docItem);
547
        item->setIcon(0, vp->getIcon());
548
        item->setText(0, QString::fromUtf8(varSet->Label.getValue()));
549
        item->setData(0, ROLE_VARSET_LABEL, QString::fromUtf8(varSet->Label.getValue()));
550
        item->setData(0, ROLE_VARSET_NAME, QString::fromUtf8(varSet->getNameInDocument()));
551
        item->setData(0, ROLE_DOC, docItem->data(0, ROLE_DOC));
552
        addGroupsVarSetComboBox(varSet, item);
553
    }
554
}
555

556
static void addDocVarSetComboBox(App::Document* doc, QPixmap& docIcon, QTreeWidgetItem* rootItem)
557
{
558
    if (!doc->testStatus(App::Document::TempDoc)) {
559
        std::vector<App::VarSet*> varSets;
560
        getVarSetsDocument(varSets, doc);
561
        if (!varSets.empty()) {
562
            // the item will be automatically destroyed when the rootItem will be destroyed
563
            auto item = new QTreeWidgetItem(rootItem);
564
            item->setIcon(0, docIcon);
565
            item->setText(0, QString::fromUtf8(doc->Label.getValue()));
566
            item->setData(0, ROLE_DOC, QByteArray(doc->getName()));
567
            item->setFlags(Qt::ItemIsEnabled);
568
            item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
569
            addVarSetsVarSetComboBox(varSets, item);
570
        }
571
    }
572
}
573

574
static QTreeWidget* createVarSetTreeWidget()
575
{
576
    // the caller of the function is responsible of managing the tree widget
577
    auto treeWidget = new QTreeWidget();
578
    treeWidget->setColumnCount(1);
579
    treeWidget->setHeaderHidden(true);
580
    // the rootItem will be destroyed when the treeWidget will be destroyed
581
    QTreeWidgetItem *rootItem = treeWidget->invisibleRootItem();
582

583
    QPixmap docIcon(Gui::BitmapFactory().pixmap("Document"));
584
    std::vector<App::Document*> docs = App::GetApplication().getDocuments();
585

586
    for (auto doc : docs) {
587
        addDocVarSetComboBox(doc, docIcon, rootItem);
588
    }
589
    treeWidget->expandAll();
590

591
    return treeWidget;
592
}
593

594
void DlgExpressionInput::setupVarSets()
595
{
596
    ui->comboBoxVarSet->clear();
597
    // createVarSetTreeWidget returns a dynamically allocated tree widget
598
    // the memory is managed by means of the unique pointer treeWidget.
599
    treeWidget.reset(createVarSetTreeWidget());
600
    ui->comboBoxVarSet->setModel(treeWidget->model());
601
    ui->comboBoxVarSet->setView(treeWidget.get());
602

603
    ui->okBtn->setEnabled(false);
604
}
605

606
std::string DlgExpressionInput::getType()
607
{
608
    return determineTypeVarSet().getName();
609
}
610

611
void DlgExpressionInput::onCheckVarSets(int state) {
612
    varSetsVisible = state == Qt::Checked;
613
    ui->groupBoxVarSets->setVisible(varSetsVisible);
614
    if (varSetsVisible) {
615
        setupVarSets();
616
    }
617
    else {
618
        ui->okBtn->setEnabled(true); // normal expression
619
    }
620
}
621

622
void DlgExpressionInput::onVarSetSelected(int)
623
{
624
    QTreeWidgetItem* selected = treeWidget->currentItem();
625

626
    if (selected) {
627
        // if group is known, fill it in
628
        QVariant variantGroup = selected->data(0, ROLE_GROUP);
629
        if (variantGroup.isValid()) {
630
            ui->lineEditGroup->setText(variantGroup.toString());
631
        }
632
        else {
633
            ui->lineEditGroup->clear();
634
        }
635
    }
636

637
    updateVarSetInfo();
638
}
639

640
void DlgExpressionInput::onTextChangedGroup(const QString&)
641
{
642
    updateVarSetInfo();
643
}
644

645
void DlgExpressionInput::namePropChanged(const QString&)
646
{
647
    updateVarSetInfo();
648
}
649

650
static bool isNameGroupOk(const QString& nameGroup,
651
                          std::stringstream& message)
652
{
653
    std::string name = nameGroup.toStdString();
654
    if (name.empty() || name != Base::Tools::getIdentifier(name)) {
655
        message << "Invalid group name (must only contain alphanumericals, underscore, "
656
                << "and must not start with digit";
657
        return false;
658
    }
659

660
    return true;
661
}
662

663
void DlgExpressionInput::reportVarSetInfo(const char* message)
664
{
665
    ui->labelInfoActive->setText(QString::fromUtf8(message));
666
}
667

668
bool DlgExpressionInput::reportGroup(QString& nameGroup)
669
{
670
    if (nameGroup.isEmpty()) {
671
        reportVarSetInfo("Please provide a group.");
672
        return true;
673
    }
674

675
    std::stringstream message;
676
    if (!isNameGroupOk(nameGroup, message)) {
677
        reportVarSetInfo(message.str().c_str());
678
        return true;
679
    }
680

681
    return false;
682
}
683

684
bool DlgExpressionInput::reportName(QTreeWidgetItem* item)
685
{
686
    QString nameProp = ui->lineEditPropNew->text();
687
    QString nameVarSet = getValue(item, ROLE_VARSET_NAME);
688
    QString nameDoc = getValue(item, ROLE_DOC);
689
    App::Document* doc = App::GetApplication().getDocument(nameDoc.toUtf8());
690
    App::DocumentObject* obj = doc->getObject(nameVarSet.toUtf8());
691
    std::stringstream message;
692
    if (!isNamePropOk(nameProp, obj, message)) {
693
        reportVarSetInfo(message.str().c_str());
694
        return true;
695
    }
696

697
    return false;
698
}
699

700
void DlgExpressionInput::updateVarSetInfo(bool checkExpr)
701
{
702
    QTreeWidgetItem* selected = treeWidget->currentItem();
703

704
    if (selected) {
705
        QString nameGroup = ui->lineEditGroup->text();
706
        if (reportGroup(nameGroup)) {
707
            // needed to report something about the group, so disable the button
708
            ui->okBtn->setEnabled(false);
709
            return;
710
        }
711

712
        if (reportName(selected)) {
713
            // needed to report something about the name, so disable the button
714
            ui->okBtn->setEnabled(false);
715
            return;
716
        }
717

718
        QString nameProp = ui->lineEditPropNew->text();
719
        QString labelVarSet = getValue(selected, ROLE_VARSET_LABEL);
720
        QString nameDoc = getValue(selected, ROLE_DOC);
721
        std::stringstream message;
722
        message << "Adding property " << nameProp.toStdString() << std::endl
723
                << "of type " << getType() << std::endl
724
                << "to variable set " << labelVarSet.toStdString() << std::endl
725
                << "in group " << nameGroup.toStdString() << std::endl
726
                << "in document " << nameDoc.toStdString() << ".";
727

728
        reportVarSetInfo(message.str().c_str());
729
        if (checkExpr) {
730
            // We have to check the text of the expression as well
731
            try {
732
                checkExpression(ui->expression->text());
733
                ui->okBtn->setEnabled(true);
734
            }
735
            catch (Base::Exception&) {
736
                ui->okBtn->setDisabled(true);
737
            }
738
        }
739
    }
740
    else {
741
        ui->okBtn->setEnabled(false);
742
        reportVarSetInfo("Please select a variable set.");
743
    }
744
}
745

746
#include "moc_DlgExpressionInput.cpp"
747

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.