1
/***************************************************************************
2
* Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net> *
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., 59 Temple Place, *
19
* Suite 330, Boston, MA 02111-1307, USA *
21
***************************************************************************/
24
#include "PreCompiled.h"
26
#include <Base/Reader.h>
27
#include <Base/Tools.h>
28
#include <Base/Writer.h>
30
#include "DynamicProperty.h"
31
#include "Application.h"
33
#include "PropertyContainer.h"
36
FC_LOG_LEVEL_INIT("Property",true,true)
42
DynamicProperty::DynamicProperty() = default;
44
DynamicProperty::~DynamicProperty()
49
void DynamicProperty::clear() {
50
auto &index = props.get<0>();
56
void DynamicProperty::getPropertyList(std::vector<Property*> &List) const
58
for (auto &v : props.get<0>())
59
List.push_back(v.property);
62
void DynamicProperty::getPropertyNamedList(std::vector<std::pair<const char*, Property*> > &List) const
64
for (auto &v : props.get<0>())
65
List.emplace_back(v.getName(),v.property);
68
void DynamicProperty::getPropertyMap(std::map<std::string,Property*> &Map) const
70
for (auto &v : props.get<0>())
71
Map[v.name] = v.property;
74
Property *DynamicProperty::getDynamicPropertyByName(const char* name) const
76
auto &index = props.get<0>();
77
auto it = index.find(name);
78
if (it != index.end())
83
std::vector<std::string> DynamicProperty::getDynamicPropertyNames() const
85
std::vector<std::string> names;
86
auto &index = props.get<0>();
87
names.reserve(index.size());
89
names.push_back(v.name);
93
short DynamicProperty::getPropertyType(const Property* prop) const
95
return prop?prop->getType():0;
98
short DynamicProperty::getPropertyType(const char *name) const
100
auto &index = props.get<0>();
101
auto it = index.find(name);
102
if (it != index.end()) {
103
short attr = it->attr;
107
attr |= Prop_ReadOnly;
113
const char* DynamicProperty::getPropertyGroup(const Property* prop) const
115
auto &index = props.get<1>();
116
auto it = index.find(const_cast<Property*>(prop));
118
return it->group.c_str();
122
const char* DynamicProperty::getPropertyGroup(const char *name) const
124
auto &index = props.get<0>();
125
auto it = index.find(name);
126
if (it != index.end())
127
return it->group.c_str();
131
const char* DynamicProperty::getPropertyDocumentation(const Property* prop) const
133
auto &index = props.get<1>();
134
auto it = index.find(const_cast<Property*>(prop));
136
return it->doc.c_str();
140
const char* DynamicProperty::getPropertyDocumentation(const char *name) const
142
auto &index = props.get<0>();
143
auto it = index.find(name);
144
if (it != index.end())
145
return it->doc.c_str();
149
Property* DynamicProperty::addDynamicProperty(PropertyContainer &pc, const char* type,
150
const char* name, const char* group, const char* doc, short attr, bool ro, bool hidden)
157
static ParameterGrp::handle hGrp = GetApplication().GetParameterGroupByPath(
158
"User parameter:BaseApp/Preferences/Document");
159
if(hGrp->GetBool("AutoNameDynamicProperty",false)) {
160
if(!name || !name[0])
162
_name = getUniquePropertyName(pc,name);
164
FC_WARN(pc.getFullName() << " rename dynamic property from '"
165
<< name << "' to '" << _name << "'");
167
name = _name.c_str();
169
name = "<null>"; // setting a bad name to trigger exception
171
auto prop = pc.getPropertyByName(name);
172
if(prop && prop->getContainer()==&pc)
173
FC_THROWM(Base::NameError, "Property " << pc.getFullName() << '.' << name << " already exists");
175
if(Base::Tools::getIdentifier(name) != name)
176
FC_THROWM(Base::NameError, "Invalid property name '" << name << "'");
178
Base::Type propType = Base::Type::getTypeIfDerivedFrom(type, App::Property::getClassTypeId(), true);
179
if (propType.isBad()) {
180
FC_THROWM(Base::TypeError, "Invalid type "
181
<< type << " for property " << pc.getFullName() << '.' << name);
184
void* propInstance = propType.createInstance();
186
FC_THROWM(Base::RuntimeError, "Failed to create property "
187
<< pc.getFullName() << '.' << name << " of type " << type);
190
Property* pcProperty = static_cast<Property*>(propInstance);
192
auto res = props.get<0>().emplace(pcProperty,name, nullptr, group, doc, attr, ro, hidden);
194
pcProperty->setContainer(&pc);
195
pcProperty->myName = res.first->name.c_str();
198
attr |= Prop_ReadOnly;
202
pcProperty->syncType(attr);
203
pcProperty->StatusBits.set((size_t)Property::PropDynamic);
205
GetApplication().signalAppendDynamicProperty(*pcProperty);
210
bool DynamicProperty::addProperty(Property *prop)
212
if(!prop || !prop->hasName())
214
auto &index = props.get<0>();
215
if(index.count(prop->getName()))
217
index.emplace(prop,std::string(),prop->getName(),
218
prop->getGroup(),prop->getDocumentation(),prop->getType(),false,false);
222
bool DynamicProperty::removeProperty(const Property *prop)
224
auto &index = props.get<1>();
225
auto it = index.find(const_cast<Property*>(prop));
226
if (it != index.end()) {
233
bool DynamicProperty::removeDynamicProperty(const char* name)
235
auto &index = props.get<0>();
236
auto it = index.find(name);
237
if (it != index.end()) {
238
if(it->property->testStatus(Property::LockDynamic))
239
throw Base::RuntimeError("property is locked");
240
else if(!it->property->testStatus(Property::PropDynamic))
241
throw Base::RuntimeError("property is not dynamic");
242
Property *prop = it->property;
243
GetApplication().signalRemoveDynamicProperty(*prop);
245
// Handle possible recursive calls of removeDynamicProperty
247
Property::destroy(prop);
249
// memory of myName has been freed
250
prop->myName = nullptr;
258
std::string DynamicProperty::getUniquePropertyName(PropertyContainer &pc, const char *Name) const
260
std::string CleanName = Base::Tools::getIdentifier(Name);
263
std::map<std::string,Property*> objectProps;
264
pc.getPropertyMap(objectProps);
265
auto pos = objectProps.find(CleanName);
267
if (pos == objectProps.end()) {
268
// if not, name is OK
272
std::vector<std::string> names;
273
names.reserve(objectProps.size());
274
for (pos = objectProps.begin();pos != objectProps.end();++pos) {
275
names.push_back(pos->first);
277
return Base::Tools::getUniqueName(CleanName, names);
281
void DynamicProperty::save(const Property *prop, Base::Writer &writer) const
283
auto &index = props.get<1>();
284
auto it = index.find(const_cast<Property*>(prop));
285
if(it != index.end()) {
287
writer.Stream() << "\" group=\"" << Base::Persistence::encodeAttribute(data.group)
288
<< "\" doc=\"" << Base::Persistence::encodeAttribute(data.doc)
289
<< "\" attr=\"" << data.attr << "\" ro=\"" << data.readonly
290
<< "\" hide=\"" << data.hidden;
294
Property *DynamicProperty::restore(PropertyContainer &pc,
295
const char *PropName, const char *TypeName, Base::XMLReader &reader)
297
if (!reader.hasAttribute("group"))
301
bool readonly = false, hidden = false;
302
const char *group=nullptr, *doc=nullptr, *attr=nullptr, *ro=nullptr, *hide=nullptr;
303
group = reader.getAttribute("group");
304
if (reader.hasAttribute("doc"))
305
doc = reader.getAttribute("doc");
306
if (reader.hasAttribute("attr")) {
307
attr = reader.getAttribute("attr");
309
std::istringstream str(attr);
313
if (reader.hasAttribute("ro")) {
314
ro = reader.getAttribute("ro");
315
if (ro) readonly = (ro[0]-48) != 0;
317
if (reader.hasAttribute("hide")) {
318
hide = reader.getAttribute("hide");
319
if (hide) hidden = (hide[0]-48) != 0;
322
return addDynamicProperty(pc,TypeName, PropName, group, doc, attribute, readonly, hidden);
325
DynamicProperty::PropData DynamicProperty::getDynamicPropertyData(const Property *prop) const
327
auto &index = props.get<1>();
328
auto it = index.find(const_cast<Property*>(prop));
329
if(it != index.end())
334
bool DynamicProperty::changeDynamicProperty(const Property *prop, const char *group, const char *doc) {
335
auto &index = props.get<1>();
336
auto it = index.find(const_cast<Property*>(prop));
337
if (it == index.end())
346
const char *DynamicProperty::getPropertyName(const Property *prop) const
348
auto &index = props.get<1>();
349
auto it = index.find(const_cast<Property*>(prop));
350
if(it != index.end())
351
return it->getName();