FreeCAD

Форк
0
/
ExpressionBinding.cpp 
315 строк · 10.3 Кб
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 <QLineEdit>
26
# include <QPixmapCache>
27
# include <QStyle>
28
#endif
29

30
#include "BitmapFactory.h"
31
#include "Command.h"
32
#include "ExpressionBinding.h"
33
#include "QuantitySpinBox_p.h"
34

35
#include <App/Application.h>
36
#include <App/Document.h>
37
#include <App/DocumentObject.h>
38
#include <App/Expression.h>
39
#include <App/ObjectIdentifier.h>
40
#include <App/PropertyGeo.h>
41
#include <Base/Tools.h>
42

43

44
FC_LOG_LEVEL_INIT("Expression",true,true)
45

46
using namespace Gui;
47
using namespace App;
48
namespace sp = std::placeholders;
49

50
ExpressionBinding::ExpressionBinding() = default;
51

52
ExpressionBinding::~ExpressionBinding() = default;
53

54
bool ExpressionBinding::isBound() const
55
{
56
    return path.getDocumentObject() != nullptr;
57
}
58

59
void ExpressionBinding::unbind()
60
{
61
    expressionchanged.disconnect();
62
    objectdeleted.disconnect();
63
    path = App::ObjectIdentifier();
64
}
65

66
void Gui::ExpressionBinding::setExpression(std::shared_ptr<Expression> expr)
67
{
68
    DocumentObject * docObj = path.getDocumentObject();
69

70
    if (expr) {
71
        const std::string error = docObj->ExpressionEngine.validateExpression(path, expr);
72

73
        if (!error.empty())
74
            throw Base::RuntimeError(error.c_str());
75

76
    }
77

78
    lastExpression = getExpression();
79

80
    bool transaction = !App::GetApplication().getActiveTransaction();
81
    if(transaction) {
82
        std::ostringstream ss;
83
        ss << (expr?"Set":"Discard") << " expression " << docObj->Label.getValue();
84
        App::GetApplication().setActiveTransaction(ss.str().c_str());
85
    }
86

87
    docObj->ExpressionEngine.setValue(path, expr);
88

89
    if(m_autoApply)
90
        apply();
91

92
    if(transaction)
93
        App::GetApplication().closeActiveTransaction();
94

95
}
96

97
void ExpressionBinding::bind(const App::ObjectIdentifier &_path)
98
{
99
    const Property * prop = _path.getProperty();
100

101
    Q_ASSERT(prop != nullptr);
102

103
    path = prop->canonicalPath(_path);
104

105
    //connect to be informed about changes
106
    DocumentObject * docObj = path.getDocumentObject();
107
    if (docObj) {
108
        //NOLINTBEGIN
109
        expressionchanged = docObj->ExpressionEngine.expressionChanged.connect(std::bind(&ExpressionBinding::expressionChange, this, sp::_1));
110
        App::Document* doc = docObj->getDocument();
111
        objectdeleted = doc->signalDeletedObject.connect(std::bind(&ExpressionBinding::objectDeleted, this, sp::_1));
112
        //NOLINTEND
113
    }
114
}
115

116
void ExpressionBinding::bind(const Property &prop)
117
{
118
    bind(App::ObjectIdentifier(prop));
119
}
120

121
bool ExpressionBinding::hasExpression() const
122
{
123
    return isBound() && getExpression() != nullptr;
124
}
125

126
std::shared_ptr<App::Expression> ExpressionBinding::getExpression() const
127
{
128
    DocumentObject * docObj = path.getDocumentObject();
129

130
    Q_ASSERT(isBound() && docObj != nullptr);
131

132
    return docObj->getExpression(path).expression;
133
}
134

135
std::string ExpressionBinding::getExpressionString(bool no_throw) const
136
{
137
    try {
138
        if (!getExpression())
139
            throw Base::RuntimeError("No expression found.");
140
        return getExpression()->toString();
141
    } catch (Base::Exception &e) {
142
        if(no_throw)
143
            FC_ERR("failed to get expression string: " << e.what());
144
        else
145
            throw;
146
    } catch (std::exception &e) {
147
        if(no_throw)
148
            FC_ERR("failed to get expression string: " << e.what());
149
        else
150
            throw;
151
    } catch (...) {
152
        if(no_throw)
153
            FC_ERR("failed to get expression string: unknown exception");
154
        else
155
            throw;
156
    }
157
    return {};
158
}
159

160
std::string ExpressionBinding::getEscapedExpressionString() const
161
{
162
    std::string escapedstr;
163
    escapedstr = Base::Tools::escapedUnicodeFromUtf8(getExpressionString(false).c_str());
164
    escapedstr = Base::Tools::escapeQuotesFromString(escapedstr);
165
    return escapedstr;
166
}
167

168
bool ExpressionBinding::assignToProperty(const std::string & propName, double value)
169
{
170
    if (isBound()) {
171
        const App::ObjectIdentifier & path = getPath();
172
        const Property * prop = path.getProperty();
173

174
        /* Skip update if property is bound and we know it is read-only */
175
        if (prop && prop->isReadOnly())
176
            return true;
177

178
        if (prop && prop->isDerivedFrom<App::PropertyPlacement>()) {
179
            std::string p = path.getSubPathStr();
180
            if (p == ".Rotation.Angle") {
181
                value = Base::toRadians(value);
182
            }
183
        }
184
    }
185

186
    Gui::Command::doCommand(Gui::Command::Doc, "%s = %f", propName.c_str(), value);
187
    return true;
188
}
189

190
bool ExpressionBinding::apply(const std::string & propName)
191
{
192
    Q_UNUSED(propName);
193
    if (hasExpression()) {
194
        DocumentObject * docObj = path.getDocumentObject();
195

196
        if (!docObj)
197
            throw Base::RuntimeError("Document object not found.");
198

199
        bool transaction = !App::GetApplication().getActiveTransaction();
200
        if(transaction) {
201
            std::ostringstream ss;
202
            ss << "Set expression " << docObj->Label.getValue();
203
            App::GetApplication().setActiveTransaction(ss.str().c_str());
204
        }
205
        Gui::Command::doCommand(Gui::Command::Doc,"App.getDocument('%s').%s.setExpression('%s', u'%s')",
206
                                docObj->getDocument()->getName(),
207
                                docObj->getNameInDocument(),
208
                                path.toEscapedString().c_str(),
209
                                getEscapedExpressionString().c_str());
210
        if(transaction)
211
            App::GetApplication().closeActiveTransaction();
212
        return true;
213
    }
214
    else {
215
        if (isBound()) {
216
            DocumentObject * docObj = path.getDocumentObject();
217

218
            if (!docObj)
219
                throw Base::RuntimeError("Document object not found.");
220

221
            if (lastExpression) {
222
                bool transaction = !App::GetApplication().getActiveTransaction();
223
                if(transaction) {
224
                    std::ostringstream ss;
225
                    ss << "Discard expression " << docObj->Label.getValue();
226
                    App::GetApplication().setActiveTransaction(ss.str().c_str());
227
                }
228
                Gui::Command::doCommand(Gui::Command::Doc,"App.getDocument('%s').%s.setExpression('%s', None)",
229
                                        docObj->getDocument()->getName(),
230
                                        docObj->getNameInDocument(),
231
                                        path.toEscapedString().c_str());
232
                if(transaction)
233
                    App::GetApplication().closeActiveTransaction();
234
            }
235
        }
236

237
        return false;
238
    }
239
}
240

241
bool ExpressionBinding::apply()
242
{
243
    Property * prop(path.getProperty());
244

245
    assert(prop);
246
    Q_UNUSED(prop);
247

248
    DocumentObject * docObj(path.getDocumentObject());
249

250
    if (!docObj)
251
        throw Base::RuntimeError("Document object not found.");
252

253
    /* Skip updating read-only properties */
254
    if (prop->isReadOnly())
255
        return true;
256

257
    std::string _path = getPath().toEscapedString();
258
    const char *path = _path.c_str();
259
    if(path[0] == '.')
260
        ++path;
261
    return apply(Gui::Command::getObjectCmd(docObj) + "." + path);
262
}
263

264
void ExpressionBinding::expressionChange(const ObjectIdentifier& id) {
265

266
    if(id==path)
267
        onChange();
268
}
269

270
void ExpressionBinding::objectDeleted(const App::DocumentObject& obj)
271
{
272
    DocumentObject * docObj = path.getDocumentObject();
273
    if (docObj == &obj) {
274
        unbind();
275
    }
276
}
277

278
// ----------------------------------------------------------------------------
279

280
ExpressionWidget::ExpressionWidget() = default;
281

282
QPixmap ExpressionWidget::getIcon(const char* name, const QSize& size) const
283
{
284
    QString key = QString::fromLatin1("%1_%2x%3")
285
        .arg(QString::fromLatin1(name))
286
        .arg(size.width())
287
        .arg(size.height());
288
    QPixmap icon;
289
    if (QPixmapCache::find(key, &icon))
290
        return icon;
291

292
    icon = BitmapFactory().pixmapFromSvg(name, size);
293
    if (!icon.isNull())
294
        QPixmapCache::insert(key, icon);
295
    return icon;
296
}
297

298
void ExpressionWidget::makeLabel(QLineEdit* le)
299
{
300
    defaultPalette = le->palette();
301
    defaultPalette.setCurrentColorGroup(QPalette::Active);
302

303
    /* Icon for f(x) */
304
    QFontMetrics fm(le->font());
305
    int frameWidth = le->style()->pixelMetric(QStyle::PM_SpinBoxFrameWidth);
306
    iconHeight = fm.height() - frameWidth;
307
    iconLabel = new ExpressionLabel(le);
308
    iconLabel->setCursor(Qt::ArrowCursor);
309
    QPixmap pixmap = getIcon(":/icons/bound-expression-unset.svg", QSize(iconHeight, iconHeight));
310
    iconLabel->setPixmap(pixmap);
311
    iconLabel->setStyleSheet(QString::fromLatin1("QLabel { border: none; padding: 0px; padding-top: %2px; width: %1px; height: %1px }").arg(iconHeight).arg(frameWidth/2));
312
    iconLabel->hide();
313
    iconLabel->setExpressionText(QString());
314
    le->setStyleSheet(QString::fromLatin1("QLineEdit { padding-right: %1px } ").arg(iconHeight+frameWidth));
315
}
316

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

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

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

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