00001 /*************************************************************************** 00002 * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) * 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 #endif 00028 00029 #include <Base/Writer.h> 00030 00031 #include "Document.h" 00032 #include "DocumentObject.h" 00033 #include "DocumentObjectPy.h" 00034 #include "PropertyLinks.h" 00035 #define new DEBUG_CLIENTBLOCK 00036 using namespace App; 00037 00038 00039 PROPERTY_SOURCE(App::DocumentObject, App::PropertyContainer) 00040 00041 DocumentObjectExecReturn *DocumentObject::StdReturn = 0; 00042 00043 //=========================================================================== 00044 // DocumentObject 00045 //=========================================================================== 00046 00047 DocumentObject::DocumentObject(void) 00048 : _pDoc(0),pcNameInDocument(0) 00049 { 00050 // define Label of type 'Output' to avoid being marked as touched after relabeling 00051 ADD_PROPERTY_TYPE(Label,("Unnamed"),"Base",Prop_Output,"User name of the object (UTF8)"); 00052 } 00053 00054 DocumentObject::~DocumentObject(void) 00055 { 00056 if (!PythonObject.is(Py::_None())){ 00057 // Remark: The API of Py::Object has been changed to set whether the wrapper owns the passed 00058 // Python object or not. In the constructor we forced the wrapper to own the object so we need 00059 // not to dec'ref the Python object any more. 00060 // But we must still invalidate the Python object because it need not to be 00061 // destructed right now because the interpreter can own several references to it. 00062 Base::PyObjectBase* obj = (Base::PyObjectBase*)PythonObject.ptr(); 00063 // Call before decrementing the reference counter, otherwise a heap error can occur 00064 obj->setInvalid(); 00065 } 00066 } 00067 00068 namespace App { 00069 class ObjectExecution 00070 { 00071 public: 00072 ObjectExecution(DocumentObject* o) : obj(o) 00073 { obj->StatusBits.set(3); } 00074 ~ObjectExecution() 00075 { obj->StatusBits.reset(3); } 00076 private: 00077 DocumentObject* obj; 00078 }; 00079 } 00080 00081 App::DocumentObjectExecReturn *DocumentObject::recompute(void) 00082 { 00083 // set/unset the execution bit 00084 ObjectExecution exe(this); 00085 return this->execute(); 00086 } 00087 00088 DocumentObjectExecReturn *DocumentObject::execute(void) 00089 { 00090 return DocumentObject::StdReturn; 00091 } 00092 00093 short DocumentObject::mustExecute(void) const 00094 { 00095 return (isTouched() ? 1 : 0); 00096 } 00097 00098 const char* DocumentObject::getStatusString(void) const 00099 { 00100 if (isError()) { 00101 const char* text = getDocument()->getErrorDescription(this); 00102 return text ? text : "Error"; 00103 } 00104 else if (isTouched()) 00105 return "Touched"; 00106 else 00107 return "Valid"; 00108 } 00109 00110 const char *DocumentObject::getNameInDocument(void) const 00111 { 00112 // Note: It can happen that we query the internal name of an object even if it is not 00113 // part of a document (anymore). This is the case e.g. if we have a reference in Python 00114 // to an object that has been removed from the document. In this case we should rather 00115 // return 0. 00116 //assert(pcNameInDocument); 00117 if (!pcNameInDocument) return 0; 00118 return pcNameInDocument->c_str(); 00119 } 00120 00121 std::vector<DocumentObject*> DocumentObject::getOutList(void) const 00122 { 00123 std::vector<Property*> List; 00124 std::vector<DocumentObject*> ret; 00125 getPropertyList(List); 00126 for (std::vector<Property*>::const_iterator It = List.begin();It != List.end(); ++It) { 00127 if ((*It)->isDerivedFrom(PropertyLinkList::getClassTypeId())) { 00128 const std::vector<DocumentObject*> &OutList = static_cast<PropertyLinkList*>(*It)->getValues(); 00129 for (std::vector<DocumentObject*>::const_iterator It2 = OutList.begin();It2 != OutList.end(); ++It2) { 00130 if (*It2) 00131 ret.push_back(*It2); 00132 } 00133 } 00134 else if ((*It)->isDerivedFrom(PropertyLinkSubList::getClassTypeId())) { 00135 const std::vector<DocumentObject*> &OutList = static_cast<PropertyLinkSubList*>(*It)->getValues(); 00136 for (std::vector<DocumentObject*>::const_iterator It2 = OutList.begin();It2 != OutList.end(); ++It2) { 00137 if (*It2) 00138 ret.push_back(*It2); 00139 } 00140 } 00141 else if ((*It)->isDerivedFrom(PropertyLink::getClassTypeId())) { 00142 if (static_cast<PropertyLink*>(*It)->getValue()) 00143 ret.push_back(static_cast<PropertyLink*>(*It)->getValue()); 00144 } 00145 else if ((*It)->isDerivedFrom(PropertyLinkSub::getClassTypeId())) { 00146 if (static_cast<PropertyLinkSub*>(*It)->getValue()) 00147 ret.push_back(static_cast<PropertyLinkSub*>(*It)->getValue()); 00148 } 00149 } 00150 return ret; 00151 } 00152 00153 std::vector<App::DocumentObject*> DocumentObject::getInList(void) const 00154 { 00155 if (_pDoc) 00156 return _pDoc->getInList(this); 00157 else 00158 return std::vector<App::DocumentObject*>(); 00159 } 00160 00161 void DocumentObject::onLostLinkToObject(DocumentObject*) 00162 { 00163 00164 } 00165 00166 App::Document *DocumentObject::getDocument(void) const 00167 { 00168 return _pDoc; 00169 } 00170 00171 void DocumentObject::setDocument(App::Document* doc) 00172 { 00173 _pDoc=doc; 00174 } 00175 00176 void DocumentObject::onBeforeChange(const Property* prop) 00177 { 00178 if (_pDoc) 00179 _pDoc->onBeforeChangeProperty(this,prop); 00180 } 00181 00183 void DocumentObject::onChanged(const Property* prop) 00184 { 00185 if (_pDoc) 00186 _pDoc->onChangedProperty(this,prop); 00187 if (prop->getType() & Prop_Output) 00188 return; 00189 // set object touched 00190 StatusBits.set(0); 00191 } 00192 00193 PyObject *DocumentObject::getPyObject(void) 00194 { 00195 if (PythonObject.is(Py::_None())) { 00196 // ref counter is set to 1 00197 PythonObject = Py::Object(new DocumentObjectPy(this),true); 00198 } 00199 return Py::new_reference_to(PythonObject); 00200 } 00201 00202 std::vector<PyObject *> DocumentObject::getPySubObjects(const std::vector<std::string>&) const 00203 { 00204 // default implementation returns nothing 00205 return std::vector<PyObject *>(); 00206 } 00207 00208 void DocumentObject::touch(void) 00209 { 00210 StatusBits.set(0); 00211 } 00212 00213 void DocumentObject::Save (Base::Writer &writer) const 00214 { 00215 writer.ObjectName = this->getNameInDocument(); 00216 App::PropertyContainer::Save(writer); 00217 }