DynamicProperty.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net>     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 #ifndef _PreComp_
00026 # include <algorithm>
00027 #endif
00028 
00029 #include "DynamicProperty.h"
00030 #include "Property.h"
00031 #include "PropertyContainer.h"
00032 #include <Base/Reader.h>
00033 #include <Base/Writer.h>
00034 #include <Base/Console.h>
00035 #include <Base/Exception.h>
00036 #include <Base/Tools.h>
00037 
00038 
00039 using namespace App;
00040 
00041 
00042 DynamicProperty::DynamicProperty(PropertyContainer* p) : pc(p)
00043 {
00044 }
00045 
00046 DynamicProperty::~DynamicProperty()
00047 {
00048 }
00049 
00050 void DynamicProperty::getPropertyList(std::vector<Property*> &List) const
00051 {
00052     // get the properties of the base class first and insert the dynamic properties afterwards
00053     this->pc->PropertyContainer::getPropertyList(List);
00054     for (std::map<std::string,PropData>::const_iterator it = props.begin(); it != props.end(); ++it)
00055         List.push_back(it->second.property);
00056 }
00057 
00058 void DynamicProperty::getPropertyMap(std::map<std::string,Property*> &Map) const
00059 {
00060     // get the properties of the base class first and insert the dynamic properties afterwards
00061     this->pc->PropertyContainer::getPropertyMap(Map);
00062     for (std::map<std::string,PropData>::const_iterator it = props.begin(); it != props.end(); ++it)
00063         Map[it->first] = it->second.property;
00064 }
00065 
00066 Property *DynamicProperty::getPropertyByName(const char* name) const
00067 {
00068     std::map<std::string,PropData>::const_iterator it = props.find(name);
00069     if (it != props.end())
00070         return it->second.property;
00071     return this->pc->PropertyContainer::getPropertyByName(name);
00072 }
00073 
00074 Property *DynamicProperty::getDynamicPropertyByName(const char* name) const
00075 {
00076     std::map<std::string,PropData>::const_iterator it = props.find(name);
00077     if (it != props.end())
00078         return it->second.property;
00079     return 0;
00080 }
00081 
00082 std::vector<std::string> DynamicProperty::getDynamicPropertyNames() const
00083 {
00084     std::vector<std::string> names;
00085     for (std::map<std::string,PropData>::const_iterator it = props.begin(); it != props.end(); ++it) {
00086         names.push_back(it->first);
00087     }
00088     return names;
00089 }
00090 
00091 void DynamicProperty::addDynamicProperties(const PropertyContainer* cont)
00092 {
00093     std::vector<std::string> names = cont->getDynamicPropertyNames();
00094     for (std::vector<std::string>::iterator it = names.begin(); it != names.end(); ++it) {
00095         App::Property* prop = cont->getDynamicPropertyByName(it->c_str());
00096         if (prop) {
00097             addDynamicProperty(
00098                 prop->getTypeId().getName(),
00099                 prop->getName(),
00100                 prop->getGroup(),
00101                 prop->getDocumentation(),
00102                 prop->getType(),
00103                 cont->isReadOnly(prop),
00104                 cont->isHidden(prop));
00105         }
00106     }
00107 }
00108 
00109 const char* DynamicProperty::getName(const Property* prop) const
00110 {
00111     for (std::map<std::string,PropData>::const_iterator it = props.begin(); it != props.end(); ++it) {
00112         if (it->second.property == prop)
00113             return it->first.c_str();
00114     }
00115     return this->pc->PropertyContainer::getName(prop);
00116 }
00117 
00118 unsigned int DynamicProperty::getMemSize (void) const
00119 {
00120     std::map<std::string,Property*> Map;
00121     getPropertyMap(Map);
00122     std::map<std::string,Property*>::const_iterator It;
00123     unsigned int size = 0;
00124     for (It = Map.begin(); It != Map.end();++It)
00125         size += It->second->getMemSize();
00126     return size;
00127 }
00128 
00129 short DynamicProperty::getPropertyType(const Property* prop) const
00130 {
00131     for (std::map<std::string,PropData>::const_iterator it = props.begin(); it != props.end(); ++it) {
00132         if (it->second.property == prop)
00133             return it->second.attr;
00134     }
00135     return this->pc->PropertyContainer::getPropertyType(prop);
00136 }
00137 
00138 short DynamicProperty::getPropertyType(const char *name) const
00139 {
00140     std::map<std::string,PropData>::const_iterator it = props.find(name);
00141     if (it != props.end())
00142         return it->second.attr;
00143     return this->pc->PropertyContainer::getPropertyType(name);
00144 }
00145 
00146 const char* DynamicProperty::getPropertyGroup(const Property* prop) const
00147 {
00148     for (std::map<std::string,PropData>::const_iterator it = props.begin(); it != props.end(); ++it) {
00149         if (it->second.property == prop)
00150             return it->second.group.c_str();
00151     }
00152     return this->pc->PropertyContainer::getPropertyGroup(prop);
00153 }
00154 
00155 const char* DynamicProperty::getPropertyGroup(const char *name) const
00156 {
00157     std::map<std::string,PropData>::const_iterator it = props.find(name);
00158     if (it != props.end())
00159         return it->second.group.c_str();
00160     return this->pc->PropertyContainer::getPropertyGroup(name);
00161 }
00162 
00163 const char* DynamicProperty::getPropertyDocumentation(const Property* prop) const
00164 {
00165     for (std::map<std::string,PropData>::const_iterator it = props.begin(); it != props.end(); ++it) {
00166         if (it->second.property == prop)
00167             return it->second.doc.c_str();
00168     }
00169     return this->pc->PropertyContainer::getPropertyDocumentation(prop);
00170 }
00171 
00172 const char* DynamicProperty::getPropertyDocumentation(const char *name) const
00173 {
00174     std::map<std::string,PropData>::const_iterator it = props.find(name);
00175     if (it != props.end())
00176         return it->second.doc.c_str();
00177     return this->pc->PropertyContainer::getPropertyDocumentation(name);
00178 }
00179 
00180 bool DynamicProperty::isReadOnly(const Property* prop) const
00181 {
00182     for (std::map<std::string,PropData>::const_iterator it = props.begin(); it != props.end(); ++it) {
00183         if (it->second.property == prop)
00184             return it->second.readonly;
00185     }
00186     return this->pc->PropertyContainer::isReadOnly(prop);
00187 }
00188 
00189 bool DynamicProperty::isReadOnly(const char *name) const
00190 {
00191     std::map<std::string,PropData>::const_iterator it = props.find(name);
00192     if (it != props.end())
00193         return it->second.readonly;
00194     return this->pc->PropertyContainer::isReadOnly(name);
00195 }
00196 
00197 bool DynamicProperty::isHidden(const Property* prop) const
00198 {
00199     for (std::map<std::string,PropData>::const_iterator it = props.begin(); it != props.end(); ++it) {
00200         if (it->second.property == prop)
00201             return it->second.hidden;
00202     }
00203     return this->pc->PropertyContainer::isHidden(prop);
00204 }
00205 
00206 bool DynamicProperty::isHidden(const char *name) const
00207 {
00208     std::map<std::string,PropData>::const_iterator it = props.find(name);
00209     if (it != props.end())
00210         return it->second.hidden;
00211     return this->pc->PropertyContainer::isHidden(name);
00212 }
00213 
00214 Property* DynamicProperty::addDynamicProperty(const char* type, const char* name, const char* group,
00215                                               const char* doc, short attr, bool ro, bool hidden)
00216 {
00217     Base::BaseClass* base = static_cast<Base::BaseClass*>(Base::Type::createInstanceByName(type,true));
00218     if (!base)
00219         return 0;
00220     if (!base->getTypeId().isDerivedFrom(Property::getClassTypeId())) {
00221         delete base;
00222         std::stringstream str;
00223         str << "'" << type << "' is not a property type";
00224         throw Base::Exception(str.str());
00225     }
00226 
00227     // get unique name
00228     Property* pcProperty = static_cast<Property*>(base);
00229     std::string ObjectName;
00230     if (name && *name != '\0')
00231         ObjectName = getUniquePropertyName(name);
00232     else
00233         ObjectName = getUniquePropertyName(type);
00234 
00235     pcProperty->setContainer(this->pc);
00236     PropData data;
00237     data.property = pcProperty;
00238     data.group = (group ? group : "");
00239     data.doc = (doc ? doc : "");
00240     data.attr = attr;
00241     data.readonly = ro;
00242     data.hidden = hidden;
00243     props[ObjectName] = data;
00244 
00245     return pcProperty;
00246 }
00247 
00248 std::string DynamicProperty::getUniquePropertyName(const char *Name) const
00249 {
00250     std::string CleanName = Base::Tools::getIdentifier(Name);
00251 
00252     // name in use?
00253     std::map<std::string,Property*> objectProps;
00254     getPropertyMap(objectProps);
00255     std::map<std::string,Property*>::const_iterator pos;
00256     pos = objectProps.find(CleanName);
00257 
00258     if (pos == objectProps.end()) {
00259         // if not, name is OK
00260         return CleanName;
00261     }
00262     else {
00263         std::vector<std::string> names;
00264         names.reserve(objectProps.size());
00265         for (pos = objectProps.begin();pos != objectProps.end();++pos) {
00266             names.push_back(pos->first);
00267         }
00268         return Base::Tools::getUniqueName(CleanName, names);
00269     }
00270 }
00271 
00272 std::string DynamicProperty::encodeAttribute(const std::string& str) const
00273 {
00274     std::string tmp;
00275     for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) {
00276         if (*it == '<')
00277             tmp += "&lt;";
00278         else if (*it == '"')
00279             tmp += "&quot;";
00280         else if (*it == '&')
00281             tmp += "&amp;";
00282         else if (*it == '>')
00283             tmp += "&gt;";
00284         else if (*it == '\n')
00285             tmp += " ";
00286         else
00287             tmp += *it;
00288     }
00289 
00290     return tmp;
00291 }
00292 
00293 void DynamicProperty::Save (Base::Writer &writer) const 
00294 {
00295     std::map<std::string,Property*> Map;
00296     getPropertyMap(Map);
00297 
00298     writer.incInd(); // indention for 'Properties Count'
00299     writer.Stream() << writer.ind() << "<Properties Count=\"" << Map.size() << "\">" << std::endl;
00300     std::map<std::string,Property*>::iterator it;
00301     for (it = Map.begin(); it != Map.end(); ++it)
00302     {
00303         writer.incInd(); // indention for 'Property name'
00304         // check whether a static or dynamic property
00305         std::map<std::string,PropData>::const_iterator pt = props.find(it->first);
00306         if (pt == props.end()) {
00307             writer.Stream() << writer.ind() << "<Property name=\"" << it->first << "\" type=\"" 
00308                             << it->second->getTypeId().getName() << "\">" << std::endl;
00309         }
00310         else {
00311             writer.Stream() << writer.ind() << "<Property name=\"" << it->first
00312                             << "\" type=\"" << it->second->getTypeId().getName()
00313                             << "\" group=\"" << encodeAttribute(pt->second.group)
00314                             << "\" doc=\"" << encodeAttribute(pt->second.doc)
00315                             << "\" attr=\"" << pt->second.attr << "\" ro=\"" << pt->second.readonly
00316                             << "\" hide=\"" << pt->second.hidden << "\">" << std::endl;
00317         }
00318 
00319         writer.incInd(); // indention for the actual property
00320         try {
00321             // We must make sure to handle all exceptions accordingly so that
00322             // the project file doesn't get invalidated. In the error case this
00323             // means to proceed instead of aborting the write operation.
00324             it->second->Save(writer);
00325         }
00326         catch (const Base::Exception &e) {
00327             Base::Console().Error("%s\n", e.what());
00328         }
00329         catch (const std::exception &e) {
00330             Base::Console().Error("%s\n", e.what());
00331         }
00332         catch (const char* e) {
00333             Base::Console().Error("%s\n", e);
00334         }
00335 #ifndef FC_DEBUG
00336         catch (...) {
00337             Base::Console().Error("DynamicProperty::Save: Unknown C++ exception thrown. Try to continue...\n");
00338         }
00339 #endif
00340         writer.decInd(); // indention for the actual property
00341         writer.Stream() << writer.ind() << "</Property>" << std::endl;
00342         writer.decInd(); // indention for 'Property name'
00343     }
00344     writer.Stream() << writer.ind() << "</Properties>" << std::endl;
00345     writer.decInd(); // indention for 'Properties Count'
00346 }
00347 
00348 void DynamicProperty::Restore(Base::XMLReader &reader)
00349 {
00350     reader.readElement("Properties");
00351     int Cnt = reader.getAttributeAsInteger("Count");
00352 
00353     for (int i=0 ;i<Cnt ;i++) {
00354         reader.readElement("Property");
00355         const char* PropName = reader.getAttribute("name");
00356         const char* TypeName = reader.getAttribute("type");
00357         Property* prop = getPropertyByName(PropName);
00358         try {
00359             if (!prop) {
00360                 short attribute = 0;
00361                 bool readonly = false, hidden = false;
00362                 const char *group=0, *doc=0, *attr=0, *ro=0, *hide=0;
00363                 if (reader.hasAttribute("group"))
00364                     group = reader.getAttribute("group");
00365                 if (reader.hasAttribute("doc"))
00366                     doc = reader.getAttribute("doc");
00367                 if (reader.hasAttribute("attr")) {
00368                     attr = reader.getAttribute("attr");
00369                     if (attr) attribute = attr[0]-48;
00370                 }
00371                 if (reader.hasAttribute("ro")) {
00372                     ro = reader.getAttribute("ro");
00373                     if (ro) readonly = (ro[0]-48) != 0;
00374                 }
00375                 if (reader.hasAttribute("hide")) {
00376                     hide = reader.getAttribute("hide");
00377                     if (hide) hidden = (hide[0]-48) != 0;
00378                 }
00379                 prop = addDynamicProperty(TypeName, PropName, group, doc, attribute, readonly, hidden);
00380             }
00381         }
00382         catch(const Base::Exception& e) {
00383             // only handle this exception type
00384             Base::Console().Warning(e.what());
00385         }
00386 
00387         //NOTE: We must also check the type of the current property because a subclass of
00388         //PropertyContainer might change the type of a property but not its name. In this
00389         //case we would force to read-in a wrong property type and the behaviour would be
00390         //undefined.
00391         if (prop && strcmp(prop->getTypeId().getName(), TypeName) == 0)
00392             prop->Restore(reader);
00393         else if (prop)
00394             Base::Console().Warning("%s: Overread data for property %s of type %s, expected type is %s\n",
00395                 pc->getTypeId().getName(), prop->getName(), prop->getTypeId().getName(), TypeName);
00396         else
00397             Base::Console().Warning("%s: No property found with name %s and type %s\n",
00398                 pc->getTypeId().getName(), PropName, TypeName);
00399         reader.readEndElement("Property");
00400     }
00401 
00402     reader.readEndElement("Properties");
00403 }

Generated on Wed Nov 23 19:00:10 2011 for FreeCAD by  doxygen 1.6.1