/*************************************************************************** * Copyright (c) 2009 Werner Mayer * * * * 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 #endif #include "DynamicProperty.h" #include "Property.h" #include "PropertyContainer.h" #include "Application.h" #include "ExtensionContainer.h" #include #include #include #include #include using namespace App; DynamicProperty::DynamicProperty(PropertyContainer* p) : pc(p) { } DynamicProperty::~DynamicProperty() { } void DynamicProperty::getPropertyList(std::vector &List) const { // get the properties of the base class first and insert the dynamic properties afterwards if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) static_cast(this->pc)->ExtensionContainer::getPropertyList(List); else this->pc->PropertyContainer::getPropertyList(List); for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) List.push_back(it->second.property); } void DynamicProperty::getPropertyMap(std::map &Map) const { // get the properties of the base class first and insert the dynamic properties afterwards if (this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) static_cast(this->pc)->ExtensionContainer::getPropertyMap(Map); else this->pc->PropertyContainer::getPropertyMap(Map); for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) Map[it->first] = it->second.property; } Property *DynamicProperty::getPropertyByName(const char* name) const { std::map::const_iterator it = props.find(name); if (it != props.end()) return it->second.property; if(this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) return static_cast(this->pc)->ExtensionContainer::getPropertyByName(name); return this->pc->PropertyContainer::getPropertyByName(name); } Property *DynamicProperty::getDynamicPropertyByName(const char* name) const { std::map::const_iterator it = props.find(name); if (it != props.end()) return it->second.property; return 0; } std::vector DynamicProperty::getDynamicPropertyNames() const { std::vector names; for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) { names.push_back(it->first); } return names; } void DynamicProperty::addDynamicProperties(const PropertyContainer* cont) { std::vector names = cont->getDynamicPropertyNames(); for (std::vector::iterator it = names.begin(); it != names.end(); ++it) { App::Property* prop = cont->getDynamicPropertyByName(it->c_str()); if (prop) { addDynamicProperty( prop->getTypeId().getName(), prop->getName(), prop->getGroup(), prop->getDocumentation(), prop->getType(), cont->isReadOnly(prop), cont->isHidden(prop)); } } } const char* DynamicProperty::getPropertyName(const Property* prop) const { for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) { if (it->second.property == prop) return it->first.c_str(); } if(this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) return static_cast(this->pc)->ExtensionContainer::getPropertyName(prop); return this->pc->PropertyContainer::getPropertyName(prop); } unsigned int DynamicProperty::getMemSize (void) const { std::map Map; getPropertyMap(Map); std::map::const_iterator It; unsigned int size = 0; for (It = Map.begin(); It != Map.end();++It) size += It->second->getMemSize(); return size; } short DynamicProperty::getPropertyType(const Property* prop) const { for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) { if (it->second.property == prop) { short attr = it->second.attr; if (it->second.hidden) attr |= Prop_Hidden; if (it->second.readonly) attr |= Prop_ReadOnly; return attr; } } if(this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) return static_cast(this->pc)->ExtensionContainer::getPropertyType(prop); return this->pc->PropertyContainer::getPropertyType(prop); } short DynamicProperty::getPropertyType(const char *name) const { std::map::const_iterator it = props.find(name); if (it != props.end()) { short attr = it->second.attr; if (it->second.hidden) attr |= Prop_Hidden; if (it->second.readonly) attr |= Prop_ReadOnly; return attr; } if(this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) return static_cast(this->pc)->ExtensionContainer::getPropertyType(name); return this->pc->PropertyContainer::getPropertyType(name); } const char* DynamicProperty::getPropertyGroup(const Property* prop) const { for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) { if (it->second.property == prop) return it->second.group.c_str(); } if(this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) return static_cast(this->pc)->ExtensionContainer::getPropertyGroup(prop); return this->pc->PropertyContainer::getPropertyGroup(prop); } const char* DynamicProperty::getPropertyGroup(const char *name) const { std::map::const_iterator it = props.find(name); if (it != props.end()) return it->second.group.c_str(); if(this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) return static_cast(this->pc)->ExtensionContainer::getPropertyGroup(name); return this->pc->PropertyContainer::getPropertyGroup(name); } const char* DynamicProperty::getPropertyDocumentation(const Property* prop) const { for (std::map::const_iterator it = props.begin(); it != props.end(); ++it) { if (it->second.property == prop) return it->second.doc.c_str(); } if(this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) return static_cast(this->pc)->ExtensionContainer::getPropertyDocumentation(prop); return this->pc->PropertyContainer::getPropertyDocumentation(prop); } const char* DynamicProperty::getPropertyDocumentation(const char *name) const { std::map::const_iterator it = props.find(name); if (it != props.end()) return it->second.doc.c_str(); if(this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) return static_cast(this->pc)->ExtensionContainer::getPropertyDocumentation(name); return this->pc->PropertyContainer::getPropertyDocumentation(name); } Property* DynamicProperty::addDynamicProperty(const char* type, const char* name, const char* group, const char* doc, short attr, bool ro, bool hidden) { Base::BaseClass* base = static_cast(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(base); std::string ObjectName; if (name && *name != '\0') ObjectName = getUniquePropertyName(name); else ObjectName = getUniquePropertyName(type); pcProperty->setContainer(this->pc); PropData data; data.property = pcProperty; data.group = (group ? group : ""); data.doc = (doc ? doc : ""); data.attr = attr; data.readonly = ro; data.hidden = hidden; props[ObjectName] = data; GetApplication().signalAppendDynamicProperty(*pcProperty); return pcProperty; } bool DynamicProperty::removeDynamicProperty(const char* name) { std::map::iterator it = props.find(name); if (it != props.end()) { GetApplication().signalRemoveDynamicProperty(*it->second.property); delete it->second.property; props.erase(it); return true; } return false; } std::string DynamicProperty::getUniquePropertyName(const char *Name) const { std::string CleanName = Base::Tools::getIdentifier(Name); // name in use? std::map objectProps; getPropertyMap(objectProps); std::map::const_iterator pos; pos = objectProps.find(CleanName); if (pos == objectProps.end()) { // if not, name is OK return CleanName; } else { std::vector names; names.reserve(objectProps.size()); for (pos = objectProps.begin();pos != objectProps.end();++pos) { names.push_back(pos->first); } return Base::Tools::getUniqueName(CleanName, names); } } std::string DynamicProperty::encodeAttribute(const std::string& str) const { std::string tmp; for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) { if (*it == '<') tmp += "<"; else if (*it == '"') tmp += """; else if (*it == '\'') tmp += "'"; else if (*it == '&') tmp += "&"; else if (*it == '>') tmp += ">"; else if (*it == '\r') tmp += " "; else if (*it == '\n') tmp += " "; else tmp += *it; } return tmp; } void DynamicProperty::Save (Base::Writer &writer) const { //extenions must be saved first, as they need to be read and initialised before properties (as //they have their own properties which they need to handle on restore) if(this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) static_cast(this->pc)->saveExtensions(writer); std::map Map; getPropertyMap(Map); writer.incInd(); // indentation for 'Properties Count' writer.Stream() << writer.ind() << "" << std::endl; std::map::iterator it; for (it = Map.begin(); it != Map.end(); ++it) { writer.incInd(); // indentation for 'Property name' // check whether a static or dynamic property std::map::const_iterator pt = props.find(it->first); if (pt == props.end()) { writer.Stream() << writer.ind() << "first << "\" type=\"" << it->second->getTypeId().getName() << "\">" << std::endl; } else { writer.Stream() << writer.ind() << "first << "\" type=\"" << it->second->getTypeId().getName() << "\" group=\"" << encodeAttribute(pt->second.group) << "\" doc=\"" << encodeAttribute(pt->second.doc) << "\" attr=\"" << pt->second.attr << "\" ro=\"" << pt->second.readonly << "\" hide=\"" << pt->second.hidden << "\">" << std::endl; } writer.incInd(); // indentation for the actual property try { // We must make sure to handle all exceptions accordingly so that // the project file doesn't get invalidated. In the error case this // means to proceed instead of aborting the write operation. // Don't write transient properties if (!(getPropertyType(it->second) & Prop_Transient)) it->second->Save(writer); } catch (const Base::Exception &e) { Base::Console().Error("%s\n", e.what()); } catch (const std::exception &e) { Base::Console().Error("%s\n", e.what()); } catch (const char* e) { Base::Console().Error("%s\n", e); } #ifndef FC_DEBUG catch (...) { Base::Console().Error("DynamicProperty::Save: Unknown C++ exception thrown. Try to continue...\n"); } #endif writer.decInd(); // indentation for the actual property writer.Stream() << writer.ind() << "" << std::endl; writer.decInd(); // indentation for 'Property name' } writer.Stream() << writer.ind() << "" << std::endl; writer.decInd(); // indentation for 'Properties Count' } void DynamicProperty::Restore(Base::XMLReader &reader) { //first all extensions must be initialised so that they can handle their properties if(this->pc->isDerivedFrom(App::ExtensionContainer::getClassTypeId())) static_cast(this->pc)->restoreExtensions(reader); reader.readElement("Properties"); int Cnt = reader.getAttributeAsInteger("Count"); for (int i=0 ;i