Files
create/src/App/DynamicProperty.cpp
Zheng, Lei d70ddf692e App: make deleting dynamic property safer
Dynamic property can be removed at any time, even during triggering of
onChanged() signal of the removing property. This patch introduced
static function Property::destroy() to make it safer by queueing any
removed property, and only deleting them when no onChanged() call is
active.
2020-03-21 15:43:03 +01:00

306 lines
9.6 KiB
C++

/***************************************************************************
* Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <algorithm>
#endif
#include "DynamicProperty.h"
#include "Property.h"
#include "PropertyContainer.h"
#include "Application.h"
#include "ExtensionContainer.h"
#include <Base/Reader.h>
#include <Base/Writer.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Tools.h>
FC_LOG_LEVEL_INIT("DynamicProperty",true,true)
using namespace App;
DynamicProperty::DynamicProperty()
{
}
DynamicProperty::~DynamicProperty()
{
clear();
}
void DynamicProperty::clear() {
auto &index = props.get<0>();
for(auto &v : index)
delete v.property;
index.clear();
}
void DynamicProperty::getPropertyList(std::vector<Property*> &List) const
{
for (auto &v : props.get<0>())
List.push_back(v.property);
}
void DynamicProperty::getPropertyMap(std::map<std::string,Property*> &Map) const
{
for (auto &v : props.get<0>())
Map[v.name] = v.property;
}
Property *DynamicProperty::getDynamicPropertyByName(const char* name) const
{
auto &index = props.get<0>();
auto it = index.find(name);
if (it != index.end())
return it->property;
return 0;
}
std::vector<std::string> DynamicProperty::getDynamicPropertyNames() const
{
std::vector<std::string> names;
auto &index = props.get<0>();
names.reserve(index.size());
for(auto &v : index)
names.push_back(v.name);
return names;
}
short DynamicProperty::getPropertyType(const Property* prop) const
{
return prop?prop->getType():0;
}
short DynamicProperty::getPropertyType(const char *name) const
{
auto &index = props.get<0>();
auto it = index.find(name);
if (it != index.end()) {
short attr = it->attr;
if (it->hidden)
attr |= Prop_Hidden;
if (it->readonly)
attr |= Prop_ReadOnly;
return attr;
}
return 0;
}
const char* DynamicProperty::getPropertyGroup(const Property* prop) const
{
auto &index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if(it!=index.end())
return it->group.c_str();
return 0;
}
const char* DynamicProperty::getPropertyGroup(const char *name) const
{
auto &index = props.get<0>();
auto it = index.find(name);
if (it != index.end())
return it->group.c_str();
return 0;
}
const char* DynamicProperty::getPropertyDocumentation(const Property* prop) const
{
auto &index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if(it!=index.end())
return it->doc.c_str();
return 0;
}
const char* DynamicProperty::getPropertyDocumentation(const char *name) const
{
auto &index = props.get<0>();
auto it = index.find(name);
if (it != index.end())
return it->doc.c_str();
return 0;
}
Property* DynamicProperty::addDynamicProperty(PropertyContainer &pc, const char* type,
const char* name, const char* group, const char* doc, short attr, bool ro, bool hidden)
{
Base::BaseClass* base = static_cast<Base::BaseClass*>(Base::Type::createInstanceByName(type,true));
if (!base)
return 0;
if (!base->getTypeId().isDerivedFrom(Property::getClassTypeId())) {
delete base;
std::stringstream str;
str << "'" << type << "' is not a property type";
throw Base::ValueError(str.str());
}
// get unique name
Property* pcProperty = static_cast<Property*>(base);
if (!name || !name[0])
name = type;
auto res = props.get<0>().emplace(pcProperty,
getUniquePropertyName(pc,name), nullptr, group, doc, attr, ro, hidden);
pcProperty->setContainer(&pc);
pcProperty->myName = res.first->name.c_str();
if(ro) attr |= Prop_ReadOnly;
if(hidden) attr |= Prop_Hidden;
pcProperty->syncType(attr);
pcProperty->StatusBits.set((size_t)Property::PropDynamic);
GetApplication().signalAppendDynamicProperty(*pcProperty);
return pcProperty;
}
bool DynamicProperty::addProperty(Property *prop)
{
if(!prop || !prop->getName())
return false;
auto &index = props.get<0>();
if(index.count(prop->getName()))
return false;
index.emplace(prop,std::string(),prop->getName(),
prop->getGroup(),prop->getDocumentation(),prop->getType(),false,false);
return true;
}
bool DynamicProperty::removeProperty(const Property *prop)
{
auto &index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if (it != index.end()) {
index.erase(it);
return true;
}
return false;
}
bool DynamicProperty::removeDynamicProperty(const char* name)
{
auto &index = props.get<0>();
auto it = index.find(name);
if (it != index.end()) {
if(it->property->testStatus(Property::LockDynamic))
throw Base::RuntimeError("property is locked");
else if(!it->property->testStatus(Property::PropDynamic))
throw Base::RuntimeError("property is not dynamic");
Property *prop = it->property;
GetApplication().signalRemoveDynamicProperty(*prop);
Property::destroy(prop);
index.erase(it);
return true;
}
return false;
}
std::string DynamicProperty::getUniquePropertyName(PropertyContainer &pc, const char *Name) const
{
std::string CleanName = Base::Tools::getIdentifier(Name);
// name in use?
std::map<std::string,Property*> objectProps;
pc.getPropertyMap(objectProps);
auto pos = objectProps.find(CleanName);
if (pos == objectProps.end()) {
// if not, name is OK
return CleanName;
}
else {
std::vector<std::string> names;
names.reserve(objectProps.size());
for (pos = objectProps.begin();pos != objectProps.end();++pos) {
names.push_back(pos->first);
}
return Base::Tools::getUniqueName(CleanName, names);
}
}
void DynamicProperty::save(const Property *prop, Base::Writer &writer) const
{
auto &index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if(it != index.end()) {
auto &data = *it;
writer.Stream() << "\" group=\"" << Base::Persistence::encodeAttribute(data.group)
<< "\" doc=\"" << Base::Persistence::encodeAttribute(data.doc)
<< "\" attr=\"" << data.attr << "\" ro=\"" << data.readonly
<< "\" hide=\"" << data.hidden;
}
}
Property *DynamicProperty::restore(PropertyContainer &pc,
const char *PropName, const char *TypeName, Base::XMLReader &reader)
{
if (!reader.hasAttribute("group"))
return 0;
short attribute = 0;
bool readonly = false, hidden = false;
const char *group=0, *doc=0, *attr=0, *ro=0, *hide=0;
group = reader.getAttribute("group");
if (reader.hasAttribute("doc"))
doc = reader.getAttribute("doc");
if (reader.hasAttribute("attr")) {
attr = reader.getAttribute("attr");
if (attr) attribute = attr[0]-48;
}
if (reader.hasAttribute("ro")) {
ro = reader.getAttribute("ro");
if (ro) readonly = (ro[0]-48) != 0;
}
if (reader.hasAttribute("hide")) {
hide = reader.getAttribute("hide");
if (hide) hidden = (hide[0]-48) != 0;
}
return addDynamicProperty(pc,TypeName, PropName, group, doc, attribute, readonly, hidden);
}
DynamicProperty::PropData DynamicProperty::getDynamicPropertyData(const Property *prop) const
{
auto &index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if(it != index.end())
return *it;
return PropData();
}
const char *DynamicProperty::getPropertyName(const Property *prop) const
{
auto &index = props.get<1>();
auto it = index.find(const_cast<Property*>(prop));
if(it != index.end())
return it->getName();
return 0;
}