FreeCAD

Форк
0
/
Property.cpp 
364 строки · 10.3 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de>              *
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., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23

24
#include "PreCompiled.h"
25

26
#ifndef _PreComp_
27
#include <cassert>
28
#endif
29

30
#include <atomic>
31
#include <Base/Tools.h>
32
#include <Base/Writer.h>
33
#include <CXX/Objects.hxx>
34

35
#include "Property.h"
36
#include "ObjectIdentifier.h"
37
#include "PropertyContainer.h"
38

39

40
using namespace App;
41

42

43
//**************************************************************************
44
//**************************************************************************
45
// Property
46
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
47

48
TYPESYSTEM_SOURCE_ABSTRACT(App::Property , Base::Persistence)
49

50
//**************************************************************************
51
// Construction/Destruction
52

53
static std::atomic<int64_t> _PropID;
54

55
// Here is the implementation! Description should take place in the header file!
56
Property::Property()
57
  : _id(++_PropID)
58
{
59
}
60

61
Property::~Property() = default;
62

63
const char* Property::getName() const
64
{
65
    return myName ? myName : "";
66
}
67

68
bool Property::hasName() const
69
{
70
    return isValidName(myName);
71
}
72

73
bool Property::isValidName(const char* name)
74
{
75
    return name && name[0] != '\0';
76
}
77

78
std::string Property::getFullName() const {
79
    std::string name;
80
    if(myName) {
81
        if(father)
82
            name = father->getFullName() + ".";
83
        else
84
            name = "?.";
85
        name += myName;
86
    }else
87
        return "?";
88
    return name;
89
}
90

91
short Property::getType() const
92
{
93
    short type = 0;
94
#define GET_PTYPE(_name) do {\
95
        if(testStatus(App::Property::Prop##_name)) type|=Prop_##_name;\
96
    }while(0)
97
    GET_PTYPE(ReadOnly);
98
    GET_PTYPE(Hidden);
99
    GET_PTYPE(Output);
100
    GET_PTYPE(Transient);
101
    GET_PTYPE(NoRecompute);
102
    GET_PTYPE(NoPersist);
103
    return type;
104
}
105

106
void Property::syncType(unsigned type) {
107
#define SYNC_PTYPE(_name) do{\
108
        if(type & Prop_##_name) StatusBits.set((size_t)Prop##_name);\
109
    }while(0)
110
    SYNC_PTYPE(ReadOnly);
111
    SYNC_PTYPE(Transient);
112
    SYNC_PTYPE(Hidden);
113
    SYNC_PTYPE(Output);
114
    SYNC_PTYPE(NoRecompute);
115
    SYNC_PTYPE(NoPersist);
116
}
117

118
const char* Property::getGroup() const
119
{
120
    return father->getPropertyGroup(this);
121
}
122

123
const char* Property::getDocumentation() const
124
{
125
    return father->getPropertyDocumentation(this);
126
}
127

128
void Property::setContainer(PropertyContainer *Father)
129
{
130
    father = Father;
131
}
132

133
void Property::setPathValue(const ObjectIdentifier &path, const boost::any &value)
134
{
135
    path.setValue(value);
136
}
137

138
const boost::any Property::getPathValue(const ObjectIdentifier &path) const
139
{
140
    return path.getValue();
141
}
142

143
void Property::getPaths(std::vector<ObjectIdentifier> &paths) const
144
{
145
    paths.emplace_back(getContainer(), getName());
146
}
147

148
ObjectIdentifier Property::canonicalPath(const ObjectIdentifier &p) const
149
{
150
    return p;
151
}
152

153
namespace App {
154
/*!
155
 * \brief The PropertyCleaner struct
156
 * Make deleting dynamic property safer by postponing its destruction.
157
 *
158
 * Dynamic property can be removed at any time, even during triggering of
159
 * onChanged() signal of the removing property. This patch introduced
160
 * static function Property::destroy() to make it safer by queueing any
161
 * removed property, and only deleting them when no onChanged() call is
162
 * active.
163
 */
164
struct PropertyCleaner {
165
    explicit PropertyCleaner(Property *p)
166
        : prop(p)
167
    {
168
        ++_PropCleanerCounter;
169
    }
170
    ~PropertyCleaner() {
171
        if(--_PropCleanerCounter)
172
            return;
173
        bool found = false;
174
        while (!_RemovedProps.empty()) {
175
            auto p = _RemovedProps.back();
176
            _RemovedProps.pop_back();
177
            if(p != prop)
178
                delete p;
179
            else
180
                found = true;
181
        }
182

183
        if (found)
184
            _RemovedProps.push_back(prop);
185
    }
186
    static void add(Property *prop) {
187
        _RemovedProps.push_back(prop);
188
    }
189

190
    Property *prop;
191

192
    static std::vector<Property*> _RemovedProps;
193
    static int _PropCleanerCounter;
194
};
195
}
196

197
std::vector<Property*> PropertyCleaner::_RemovedProps;
198
int PropertyCleaner::_PropCleanerCounter = 0;
199

200
void Property::destroy(Property *p) {
201
    if (p) {
202
        // Is it necessary to nullify the container? May cause crash if any
203
        // onChanged() caller assumes a non-null container.
204
        //
205
        // p->setContainer(0);
206

207
        PropertyCleaner::add(p);
208
    }
209
}
210

211
void Property::touch()
212
{
213
    PropertyCleaner guard(this);
214
    if (father) {
215
        father->onEarlyChange(this);
216
        father->onChanged(this);
217
    }
218
    StatusBits.set(Touched);
219
}
220

221
void Property::setReadOnly(bool readOnly)
222
{
223
    this->setStatus(App::Property::ReadOnly, readOnly);
224
}
225

226
void Property::hasSetValue()
227
{
228
    PropertyCleaner guard(this);
229
    if (father) {
230
        father->onChanged(this);
231
        if(!testStatus(Busy)) {
232
            Base::BitsetLocker<decltype(StatusBits)> guard(StatusBits,Busy);
233
            signalChanged(*this);
234
        }
235
    }
236
    StatusBits.set(Touched);
237
}
238

239
void Property::aboutToSetValue()
240
{
241
    if (father)
242
        father->onBeforeChange(this);
243
}
244

245
void Property::verifyPath(const ObjectIdentifier &p) const
246
{
247
    p.verify(*this);
248
}
249

250
Property *Property::Copy() const
251
{
252
    // have to be reimplemented by a subclass!
253
    assert(0);
254
    return nullptr;
255
}
256

257
void Property::Paste(const Property& /*from*/)
258
{
259
    // have to be reimplemented by a subclass!
260
    assert(0);
261
}
262

263
void Property::setStatusValue(unsigned long status) {
264
    static const unsigned long mask =
265
        (1<<PropDynamic)
266
        |(1<<PropNoRecompute)
267
        |(1<<PropReadOnly)
268
        |(1<<PropTransient)
269
        |(1<<PropOutput)
270
        |(1<<PropHidden)
271
        |(1<<PropNoPersist)
272
        |(1<<Busy);
273

274
    status &= ~mask;
275
    status |= StatusBits.to_ulong() & mask;
276
    unsigned long oldStatus = StatusBits.to_ulong();
277
    StatusBits = decltype(StatusBits)(status);
278

279
    if(father) {
280
        static unsigned long _signalMask = (1<<ReadOnly) | (1<<Hidden);
281
        if((status & _signalMask) != (oldStatus & _signalMask))
282
            father->onPropertyStatusChanged(*this,oldStatus);
283
    }
284
}
285

286
void Property::setStatus(Status pos, bool on) {
287
    auto bits = StatusBits;
288
    bits.set(pos,on);
289
    setStatusValue(bits.to_ulong());
290
}
291

292
bool Property::isSame(const Property &other) const {
293
    if(&other == this)
294
        return true;
295
    if(other.getTypeId() != getTypeId() || getMemSize() != other.getMemSize())
296
        return false;
297

298
    Base::StringWriter writer,writer2;
299
    Save(writer);
300
    other.Save(writer2);
301
    return writer.getString() == writer2.getString();
302
}
303

304
//**************************************************************************
305
//**************************************************************************
306
// PropertyListsBase
307
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
308

309
void PropertyListsBase::_setPyObject(PyObject *value) {
310
    std::vector<int> indices;
311
    std::vector<PyObject *> vals;
312
    Py::Object pySeq;
313

314
    if (PyDict_Check(value)) {
315
        Py::Dict dict(value);
316
        auto size = dict.size();
317
        vals.reserve(size);
318
        indices.reserve(size);
319
        int listSize = getSize();
320
        for(auto it=dict.begin();it!=dict.end();++it) {
321
            const auto &item = *it;
322
            PyObject *key = item.first.ptr();
323
            if(!PyLong_Check(key))
324
                throw Base::TypeError("expect key type to be integer");
325
            long idx = PyLong_AsLong(key);
326
            if(idx<-1 || idx>listSize)
327
                throw Base::ValueError("index out of bound");
328
            if(idx==-1 || idx==listSize) {
329
                idx = listSize;
330
                ++listSize;
331
            }
332
            indices.push_back(idx);
333
            vals.push_back(item.second.ptr());
334
        }
335
    } else {
336
        if (PySequence_Check(value))
337
            pySeq = value;
338
        else {
339
            PyObject *iter = PyObject_GetIter(value);
340
            if(iter) {
341
                Py::Object pyIter(iter,true);
342
                pySeq = Py::asObject(PySequence_Fast(iter,""));
343
            } else {
344
                PyErr_Clear();
345
                vals.push_back(value);
346
            }
347
        }
348
        if(!pySeq.isNone()) {
349
            Py::Sequence seq(pySeq);
350
            vals.reserve(seq.size());
351
            for(auto it=seq.begin();it!=seq.end();++it)
352
                vals.push_back((*it).ptr());
353
        }
354
    }
355
    setPyValues(vals,indices);
356
}
357

358

359
//**************************************************************************
360
//**************************************************************************
361
// PropertyLists
362
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
363

364
TYPESYSTEM_SOURCE_ABSTRACT(App::PropertyLists , App::Property)
365

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

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

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

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