PropertyContainer.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) Jürgen Riegel          (juergen.riegel@web.de) 2002     *
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 
00026 #ifndef _PreComp_
00027 # include <cassert>
00028 # include <algorithm>
00029 #endif
00030 
00032 #include <Base/Reader.h>
00033 #include <Base/Writer.h>
00034 #include <Base/Console.h>
00035 #include <Base/Exception.h>
00036 
00037 #include "Property.h"
00038 #include "PropertyContainer.h"
00039 #include "PropertyLinks.h"
00040 
00041 using namespace App;
00042 using namespace Base;
00043 using namespace std;
00044  
00045 TYPESYSTEM_SOURCE(App::PropertyContainer,Base::Persistence);
00046 
00047 
00048 //**************************************************************************
00049 // Construction/Destruction
00050 
00051 // here the implemataion! description should take place in the header file!
00052 PropertyContainer::PropertyContainer()
00053 {
00054     propertyData.parentPropertyData = 0;
00055 }
00056 
00057 PropertyContainer::~PropertyContainer()
00058 {
00059 
00060 }
00061 
00062 unsigned int PropertyContainer::getMemSize (void) const
00063 {
00064     std::map<std::string,Property*> Map;
00065     getPropertyMap(Map);
00066     std::map<std::string,Property*>::const_iterator It;
00067     unsigned int size = 0;
00068     for (It = Map.begin(); It != Map.end();++It)
00069         size += It->second->getMemSize();
00070     return size;
00071 }
00072 
00073 Property *PropertyContainer::getPropertyByName(const char* name) const
00074 {
00075     return getPropertyData().getPropertyByName(this,name);
00076 }
00077 
00078 void PropertyContainer::getPropertyMap(std::map<std::string,Property*> &Map) const
00079 {
00080     getPropertyData().getPropertyMap(this,Map);
00081 }
00082 
00083 void PropertyContainer::getPropertyList(std::vector<Property*> &List) const
00084 {
00085     getPropertyData().getPropertyList(this,List);
00086 }
00087 
00088 void PropertyContainer::setPropertyStatus(unsigned char bit,bool value)
00089 {
00090     std::vector<Property*> List;
00091     getPropertyList(List);
00092     for(std::vector<Property*>::const_iterator it=List.begin();it!=List.end();++it)
00093         (**it).StatusBits.set(bit,value);
00094 }
00095 
00096 short PropertyContainer::getPropertyType(const Property* prop) const 
00097 {
00098     return getPropertyData().getType(this,prop);
00099 }
00100 
00101 short PropertyContainer::getPropertyType(const char *name) const 
00102 {
00103     return getPropertyData().getType(this,name);
00104 }
00105 
00106 const char* PropertyContainer::getPropertyGroup(const Property* prop) const
00107 {
00108     return getPropertyData().getGroup(this,prop);
00109 }
00110 
00111 const char* PropertyContainer::getPropertyGroup(const char *name) const
00112 {
00113     return getPropertyData().getGroup(this,name);
00114 }
00115 
00116 const char* PropertyContainer::getPropertyDocumentation(const Property* prop) const
00117 {
00118     return getPropertyData().getDocumentation(this,prop);
00119 }
00120 
00121 const char* PropertyContainer::getPropertyDocumentation(const char *name) const
00122 {
00123     return getPropertyData().getDocumentation(this,name);
00124 }
00125 
00126 bool PropertyContainer::isReadOnly(const Property* prop) const
00127 {
00128     return (getPropertyData().getType(this,prop) & Prop_ReadOnly) == Prop_ReadOnly;
00129 }
00130 
00131 bool PropertyContainer::isReadOnly(const char *name) const
00132 {
00133     return (getPropertyData().getType(this,name) & Prop_ReadOnly) == Prop_ReadOnly;
00134 }
00135 
00136 bool PropertyContainer::isHidden(const Property* prop) const
00137 {
00138     return (getPropertyData().getType(this,prop) & Prop_Hidden) == Prop_Hidden;
00139 }
00140 
00141 bool PropertyContainer::isHidden(const char *name) const
00142 {
00143     return (getPropertyData().getType(this,name) & Prop_Hidden) == Prop_Hidden;
00144 }
00145 
00146 const char* PropertyContainer::getName(const Property* prop)const
00147 {
00148     return getPropertyData().getName(this,prop);
00149 }
00150 
00151 
00152 const PropertyData * PropertyContainer::getPropertyDataPtr(void){return &propertyData;} 
00153 const PropertyData & PropertyContainer::getPropertyData(void) const{return propertyData;} 
00154 
00155 PropertyData PropertyContainer::propertyData;
00156 
00160 template <class TCLASS>
00161 class PropertyAttribute : public std::binary_function<TCLASS, typename App::PropertyType, bool>
00162 {
00163 public:
00164     PropertyAttribute(const PropertyContainer* c) : cont(c) {}
00165     bool operator () (const TCLASS& prop, typename App::PropertyType attr) const
00166     { return (cont->getPropertyType(prop.second) & attr) == attr; }
00167 private:
00168     const PropertyContainer* cont;
00169 };
00170 
00171 void PropertyContainer::Save (Base::Writer &writer) const 
00172 {
00173     std::map<std::string,Property*> Map;
00174     getPropertyMap(Map);
00175   
00176     // ignore the properties we won't store
00177     size_t ct = std::count_if(Map.begin(), Map.end(), std::bind2nd(PropertyAttribute
00178         <std::pair<std::string,Property*> >(this), Prop_Transient));
00179     size_t size = Map.size() - ct;
00180 
00181     writer.incInd(); // indention for 'Properties Count'
00182     writer.Stream() << writer.ind() << "<Properties Count=\"" << size << "\">" << endl;
00183     std::map<std::string,Property*>::iterator it;
00184     for (it = Map.begin(); it != Map.end(); ++it)
00185     {
00186         // Don't write transient properties 
00187         if (!(getPropertyType(it->second) & Prop_Transient))
00188         {
00189             writer.incInd(); // indention for 'Property name'
00190             writer.Stream() << writer.ind() << "<Property name=\"" << it->first << "\" type=\"" 
00191                             << it->second->getTypeId().getName() << "\">" << endl;;
00192             writer.incInd(); // indention for the actual property
00193             try {
00194                 // We must make sure to handle all exceptions accordingly so that
00195                 // the project file doesn't get invalidated. In the error case this
00196                 // means to proceed instead of aborting the write operation.
00197                 it->second->Save(writer);
00198             }
00199             catch (const Base::Exception &e) {
00200                 Base::Console().Error("%s\n", e.what());
00201             }
00202             catch (const std::exception &e) {
00203                 Base::Console().Error("%s\n", e.what());
00204             }
00205             catch (const char* e) {
00206                 Base::Console().Error("%s\n", e);
00207             }
00208 #ifndef FC_DEBUG
00209             catch (...) {
00210                 Base::Console().Error("PropertyContainer::Save: Unknown C++ exception thrown. Try to continue...\n");
00211             }
00212 #endif
00213             writer.decInd(); // indention for the actual property
00214             writer.Stream() << writer.ind() << "</Property>" << endl;    
00215             writer.decInd(); // indention for 'Property name'
00216         }
00217     }
00218     writer.Stream() << writer.ind() << "</Properties>" << endl;
00219     writer.decInd(); // indention for 'Properties Count'
00220 }
00221 
00222 void PropertyContainer::Restore(Base::XMLReader &reader)
00223 {
00224     reader.readElement("Properties");
00225     int Cnt = reader.getAttributeAsInteger("Count");
00226 
00227     for (int i=0 ;i<Cnt ;i++) {
00228         reader.readElement("Property");
00229         const char* PropName = reader.getAttribute("name");
00230         const char* TypeName = reader.getAttribute("type");
00231         Property* prop = getPropertyByName(PropName);
00232         // NOTE: We must also check the type of the current property because a
00233         // subclass of PropertyContainer might change the type of a property but
00234         // not its name. In this case we would force to read-in a wrong property
00235         // type and the behaviour would be undefined.
00236         try {
00237             if (prop && strcmp(prop->getTypeId().getName(), TypeName) == 0)
00238                 prop->Restore(reader);
00239         }
00240         catch (const Base::XMLParseException&) {
00241             throw; // re-throw
00242         }
00243         catch (const Base::Exception &e) {
00244             Base::Console().Error("%s\n", e.what());
00245         }
00246         catch (const std::exception &e) {
00247             Base::Console().Error("%s\n", e.what());
00248         }
00249         catch (const char* e) {
00250             Base::Console().Error("%s\n", e);
00251         }
00252 #ifndef FC_DEBUG
00253         catch (...) {
00254             Base::Console().Error("PropertyContainer::Restore: Unknown C++ exception thrown");
00255         }
00256 #endif
00257 
00258         reader.readEndElement("Property");
00259     }
00260     reader.readEndElement("Properties");
00261 }
00262 
00263 void PropertyData::addProperty(const PropertyContainer *container,const char* PropName, Property *Prop, const char* PropertyGroup , PropertyType Type, const char* PropertyDocu)
00264 {
00265   bool IsIn = false;
00266   for (vector<PropertySpec>::const_iterator It = propertyData.begin(); It != propertyData.end(); ++It)
00267     if(strcmp(It->Name,PropName)==0)
00268       IsIn = true;
00269 
00270   if( !IsIn )
00271   {
00272     PropertySpec temp;
00273     temp.Name   = PropName;
00274     temp.Offset = (short) ((char*)Prop - (char*)container);
00275     temp.Group  = PropertyGroup;
00276     temp.Type   = Type;
00277     temp.Docu   = PropertyDocu;
00278     propertyData.push_back(temp);
00279   }
00280 }
00281 
00282 const PropertyData::PropertySpec *PropertyData::findProperty(const PropertyContainer *container,const char* PropName) const
00283 {
00284   for (vector<PropertyData::PropertySpec>::const_iterator It = propertyData.begin(); It != propertyData.end(); ++It)
00285     if(strcmp(It->Name,PropName)==0)
00286       return &(*It);
00287 
00288   if(parentPropertyData)
00289       return parentPropertyData->findProperty(container,PropName);
00290  
00291   return 0;
00292 }
00293 
00294 const PropertyData::PropertySpec *PropertyData::findProperty(const PropertyContainer *container,const Property* prop) const
00295 {
00296   const int diff = (int) ((char*)prop - (char*)container);
00297 
00298   for (vector<PropertyData::PropertySpec>::const_iterator It = propertyData.begin(); It != propertyData.end(); ++It)
00299     if(diff == It->Offset)
00300       return &(*It);
00301   
00302   if(parentPropertyData)
00303       return parentPropertyData->findProperty(container,prop);
00304 
00305   return 0;
00306 }
00307 
00308 const char* PropertyData::getName(const PropertyContainer *container,const Property* prop) const
00309 {
00310   const PropertyData::PropertySpec* Spec = findProperty(container,prop);
00311 
00312   if(Spec)
00313     return Spec->Name;
00314   else
00315     return 0;
00316   /*
00317 
00318   for(std::map<std::string,PropertySpec>::const_iterator pos = propertyData.begin();pos != propertyData.end();++pos)
00319     if(pos->second.Offset == diff)
00320       return pos->first.c_str();
00321 
00322   if(parentPropertyData)
00323     return parentPropertyData->getName(container,prop);
00324 
00325   return 0;
00326   */
00327 }
00328 
00329 short PropertyData::getType(const PropertyContainer *container,const Property* prop) const
00330 {
00331   const PropertyData::PropertySpec* Spec = findProperty(container,prop);
00332 
00333   if(Spec)
00334     return Spec->Type;
00335   else
00336     return 0;
00337 
00338   /*
00339   const int diff = (int) ((char*)prop - (char*)container);
00340 
00341   for(std::map<std::string,PropertySpec>::const_iterator pos = propertyData.begin();pos != propertyData.end();++pos)
00342     if(pos->second.Offset == diff)
00343       return pos->second.Type;
00344 
00345   if(parentPropertyData)
00346     return parentPropertyData->getType(container,prop);
00347 
00348   return 0;
00349   */
00350 }
00351 
00352 short PropertyData::getType(const PropertyContainer *container,const char* name) const
00353 {
00354   const PropertyData::PropertySpec* Spec = findProperty(container,name);
00355 
00356   if(Spec)
00357     return Spec->Type;
00358   else
00359     return 0;
00360 }
00361 
00362 const char* PropertyData::getGroup(const PropertyContainer *container,const Property* prop) const
00363 {
00364   const PropertyData::PropertySpec* Spec = findProperty(container,prop);
00365 
00366   if(Spec)
00367     return Spec->Group;
00368   else
00369     return 0;
00370 
00371   /*
00372   const int diff = (int) ((char*)prop - (char*)container);
00373 
00374   for(std::map<std::string,PropertySpec>::const_iterator pos = propertyData.begin();pos != propertyData.end();++pos)
00375     if(pos->second.Offset == diff)
00376       return pos->second.Group;
00377 
00378   if(parentPropertyData)
00379     return parentPropertyData->getGroup(container,prop);
00380 
00381   return 0;
00382   */
00383 }
00384 
00385 const char* PropertyData::getGroup(const PropertyContainer *container,const char* name) const
00386 {
00387   const PropertyData::PropertySpec* Spec = findProperty(container,name);
00388 
00389   if(Spec)
00390     return Spec->Group;
00391   else
00392     return 0;
00393 }
00394 
00395 const char* PropertyData::getDocumentation(const PropertyContainer *container,const Property* prop) const
00396 {
00397   const PropertyData::PropertySpec* Spec = findProperty(container,prop);
00398 
00399   if(Spec)
00400     return Spec->Docu;
00401   else
00402     return 0;
00403 }
00404 
00405 const char* PropertyData::getDocumentation(const PropertyContainer *container,const char* name) const
00406 {
00407   const PropertyData::PropertySpec* Spec = findProperty(container,name);
00408 
00409   if(Spec)
00410     return Spec->Docu;
00411   else
00412     return 0;
00413 }
00414 
00415 
00416 
00417 Property *PropertyData::getPropertyByName(const PropertyContainer *container,const char* name) const 
00418 {
00419   const PropertyData::PropertySpec* Spec = findProperty(container,name);
00420 
00421   if(Spec)
00422     return (Property *) (Spec->Offset + (char *)container);
00423   else
00424     return 0;
00425 /*
00426   std::map<std::string,PropertySpec>::const_iterator pos = propertyData.find(name);
00427 
00428   if(pos != propertyData.end())
00429   {
00430     // calculate propterty by offset
00431     return (Property *) (pos->second.Offset + (char *)container);
00432   }else{
00433     if(parentPropertyData)
00434       return parentPropertyData->getPropertyByName(container,name);
00435     else
00436       return 0;
00437   }*/
00438 }
00439 
00440 void PropertyData::getPropertyMap(const PropertyContainer *container,std::map<std::string,Property*> &Map) const
00441 {
00442   for (vector<PropertyData::PropertySpec>::const_iterator It = propertyData.begin(); It != propertyData.end(); ++It)
00443     Map[It->Name] = (Property *) (It->Offset + (char *)container);
00444 /*
00445   std::map<std::string,PropertySpec>::const_iterator pos;
00446 
00447   for(pos = propertyData.begin();pos != propertyData.end();++pos)
00448   {
00449     Map[pos->first] = (Property *) (pos->second.Offset + (char *)container);
00450   }
00451   */
00452 
00453   if(parentPropertyData)
00454     parentPropertyData->getPropertyMap(container,Map);
00455 
00456 }
00457 
00458 void PropertyData::getPropertyList(const PropertyContainer *container,std::vector<Property*> &List) const
00459 {
00460   for (vector<PropertyData::PropertySpec>::const_iterator It = propertyData.begin(); It != propertyData.end(); ++It)
00461     List.push_back((Property *) (It->Offset + (char *)container) );
00462 
00463 /*  std::map<std::string,PropertySpec>::const_iterator pos;
00464 
00465   for(pos = propertyData.begin();pos != propertyData.end();++pos)
00466   {
00467     List.push_back((Property *) (pos->second.Offset + (char *)container) );
00468   }*/
00469   if(parentPropertyData)
00470     parentPropertyData->getPropertyList(container,List);
00471 
00472 }
00473 
00474 
00475 

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