FreeCAD

Форк
0
/
Property.cpp 
391 строка · 10.9 Кб
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
std::string Property::getFileName(const char* postfix, const char* prefix) const
92
{
93
    std::ostringstream ss;
94
    if (prefix) {
95
        ss << prefix;
96
    }
97
    if (!myName) {
98
        ss << "Property";
99
    }
100
    else {
101
        std::string name = getFullName();
102
        auto pos = name.find('#');
103
        if (pos == std::string::npos) {
104
            ss << name;
105
        }
106
        else {
107
            ss << (name.c_str() + pos + 1);
108
        }
109
    }
110
    if (postfix) {
111
        ss << postfix;
112
    }
113
    return ss.str();
114
}
115

116
short Property::getType() const
117
{
118
    short type = 0;
119
#define GET_PTYPE(_name) do {\
120
        if(testStatus(App::Property::Prop##_name)) type|=Prop_##_name;\
121
    }while(0)
122
    GET_PTYPE(ReadOnly);
123
    GET_PTYPE(Hidden);
124
    GET_PTYPE(Output);
125
    GET_PTYPE(Transient);
126
    GET_PTYPE(NoRecompute);
127
    GET_PTYPE(NoPersist);
128
    return type;
129
}
130

131
void Property::syncType(unsigned type) {
132
#define SYNC_PTYPE(_name) do{\
133
        if(type & Prop_##_name) StatusBits.set((size_t)Prop##_name);\
134
    }while(0)
135
    SYNC_PTYPE(ReadOnly);
136
    SYNC_PTYPE(Transient);
137
    SYNC_PTYPE(Hidden);
138
    SYNC_PTYPE(Output);
139
    SYNC_PTYPE(NoRecompute);
140
    SYNC_PTYPE(NoPersist);
141
}
142

143
const char* Property::getGroup() const
144
{
145
    return father->getPropertyGroup(this);
146
}
147

148
const char* Property::getDocumentation() const
149
{
150
    return father->getPropertyDocumentation(this);
151
}
152

153
void Property::setContainer(PropertyContainer *Father)
154
{
155
    father = Father;
156
}
157

158
void Property::setPathValue(const ObjectIdentifier &path, const boost::any &value)
159
{
160
    path.setValue(value);
161
}
162

163
const boost::any Property::getPathValue(const ObjectIdentifier &path) const
164
{
165
    return path.getValue();
166
}
167

168
void Property::getPaths(std::vector<ObjectIdentifier> &paths) const
169
{
170
    paths.emplace_back(getContainer(), getName());
171
}
172

173
ObjectIdentifier Property::canonicalPath(const ObjectIdentifier &p) const
174
{
175
    return p;
176
}
177

178
namespace App {
179
/*!
180
 * \brief The PropertyCleaner struct
181
 * Make deleting dynamic property safer by postponing its destruction.
182
 *
183
 * Dynamic property can be removed at any time, even during triggering of
184
 * onChanged() signal of the removing property. This patch introduced
185
 * static function Property::destroy() to make it safer by queueing any
186
 * removed property, and only deleting them when no onChanged() call is
187
 * active.
188
 */
189
struct PropertyCleaner {
190
    explicit PropertyCleaner(Property *p)
191
        : prop(p)
192
    {
193
        ++_PropCleanerCounter;
194
    }
195
    ~PropertyCleaner() {
196
        if(--_PropCleanerCounter)
197
            return;
198
        bool found = false;
199
        while (!_RemovedProps.empty()) {
200
            auto p = _RemovedProps.back();
201
            _RemovedProps.pop_back();
202
            if(p != prop)
203
                delete p;
204
            else
205
                found = true;
206
        }
207

208
        if (found)
209
            _RemovedProps.push_back(prop);
210
    }
211
    static void add(Property *prop) {
212
        _RemovedProps.push_back(prop);
213
    }
214

215
    Property *prop;
216

217
    static std::vector<Property*> _RemovedProps;
218
    static int _PropCleanerCounter;
219
};
220
}
221

222
std::vector<Property*> PropertyCleaner::_RemovedProps;
223
int PropertyCleaner::_PropCleanerCounter = 0;
224

225
void Property::destroy(Property *p) {
226
    if (p) {
227
        // Is it necessary to nullify the container? May cause crash if any
228
        // onChanged() caller assumes a non-null container.
229
        //
230
        // p->setContainer(0);
231

232
        PropertyCleaner::add(p);
233
    }
234
}
235

236
void Property::touch()
237
{
238
    PropertyCleaner guard(this);
239
    if (father) {
240
        father->onEarlyChange(this);
241
        father->onChanged(this);
242
    }
243
    StatusBits.set(Touched);
244
}
245

246
void Property::setReadOnly(bool readOnly)
247
{
248
    this->setStatus(App::Property::ReadOnly, readOnly);
249
}
250

251
void Property::hasSetValue()
252
{
253
    PropertyCleaner guard(this);
254
    if (father) {
255
        father->onChanged(this);
256
        if(!testStatus(Busy)) {
257
            Base::BitsetLocker<decltype(StatusBits)> guard(StatusBits,Busy);
258
            signalChanged(*this);
259
        }
260
    }
261
    StatusBits.set(Touched);
262
}
263

264
void Property::aboutToSetValue()
265
{
266
    if (father)
267
        father->onBeforeChange(this);
268
}
269

270
void Property::verifyPath(const ObjectIdentifier &p) const
271
{
272
    p.verify(*this);
273
}
274

275
Property *Property::Copy() const
276
{
277
    // have to be reimplemented by a subclass!
278
    assert(0);
279
    return nullptr;
280
}
281

282
void Property::Paste(const Property& /*from*/)
283
{
284
    // have to be reimplemented by a subclass!
285
    assert(0);
286
}
287

288
void Property::setStatusValue(unsigned long status) {
289
    // clang-format off
290
    static const unsigned long mask =
291
         (1<<PropDynamic)
292
        |(1<<PropNoRecompute)
293
        |(1<<PropReadOnly)
294
        |(1<<PropTransient)
295
        |(1<<PropOutput)
296
        |(1<<PropHidden)
297
        |(1<<PropNoPersist)
298
        |(1<<Busy);
299
    // clang-format on
300

301
    status &= ~mask;
302
    status |= StatusBits.to_ulong() & mask;
303
    unsigned long oldStatus = StatusBits.to_ulong();
304
    StatusBits = decltype(StatusBits)(status);
305

306
    if(father) {
307
        static unsigned long _signalMask = (1<<ReadOnly) | (1<<Hidden);
308
        if((status & _signalMask) != (oldStatus & _signalMask))
309
            father->onPropertyStatusChanged(*this,oldStatus);
310
    }
311
}
312

313
void Property::setStatus(Status pos, bool on) {
314
    auto bits = StatusBits;
315
    bits.set(pos,on);
316
    setStatusValue(bits.to_ulong());
317
}
318

319
bool Property::isSame(const Property &other) const {
320
    if(&other == this)
321
        return true;
322
    if(other.getTypeId() != getTypeId() || getMemSize() != other.getMemSize())
323
        return false;
324

325
    Base::StringWriter writer,writer2;
326
    Save(writer);
327
    other.Save(writer2);
328
    return writer.getString() == writer2.getString();
329
}
330

331
//**************************************************************************
332
//**************************************************************************
333
// PropertyListsBase
334
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
335

336
void PropertyListsBase::_setPyObject(PyObject *value) {
337
    std::vector<int> indices;
338
    std::vector<PyObject *> vals;
339
    Py::Object pySeq;
340

341
    if (PyDict_Check(value)) {
342
        Py::Dict dict(value);
343
        auto size = dict.size();
344
        vals.reserve(size);
345
        indices.reserve(size);
346
        int listSize = getSize();
347
        for(auto it=dict.begin();it!=dict.end();++it) {
348
            const auto &item = *it;
349
            PyObject *key = item.first.ptr();
350
            if(!PyLong_Check(key))
351
                throw Base::TypeError("expect key type to be integer");
352
            long idx = PyLong_AsLong(key);
353
            if(idx<-1 || idx>listSize)
354
                throw Base::ValueError("index out of bound");
355
            if(idx==-1 || idx==listSize) {
356
                idx = listSize;
357
                ++listSize;
358
            }
359
            indices.push_back(idx);
360
            vals.push_back(item.second.ptr());
361
        }
362
    } else {
363
        if (PySequence_Check(value))
364
            pySeq = value;
365
        else {
366
            PyObject *iter = PyObject_GetIter(value);
367
            if(iter) {
368
                Py::Object pyIter(iter,true);
369
                pySeq = Py::asObject(PySequence_Fast(iter,""));
370
            } else {
371
                PyErr_Clear();
372
                vals.push_back(value);
373
            }
374
        }
375
        if(!pySeq.isNone()) {
376
            Py::Sequence seq(pySeq);
377
            vals.reserve(seq.size());
378
            for(auto it=seq.begin();it!=seq.end();++it)
379
                vals.push_back((*it).ptr());
380
        }
381
    }
382
    setPyValues(vals,indices);
383
}
384

385

386
//**************************************************************************
387
//**************************************************************************
388
// PropertyLists
389
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
390

391
TYPESYSTEM_SOURCE_ABSTRACT(App::PropertyLists , App::Property)
392

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

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

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

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