00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00052 #include "PreCompiled.h"
00053
00054 #ifndef _PreComp_
00055 # include <sstream>
00056 # include <climits>
00057 #endif
00058
00059 #include <boost/graph/topological_sort.hpp>
00060 #include <boost/graph/depth_first_search.hpp>
00061 #include <boost/graph/dijkstra_shortest_paths.hpp>
00062 #include <boost/graph/visitors.hpp>
00063 #include <boost/graph/graphviz.hpp>
00064 #include <boost/bind.hpp>
00065
00066
00067 #include "Document.h"
00068 #include "DocumentPy.h"
00069 #include "Application.h"
00070 #include "DocumentObject.h"
00071 #include "PropertyLinks.h"
00072
00073 #include <Base/Console.h>
00074 #include <Base/Exception.h>
00075 #include <Base/FileInfo.h>
00076 #include <Base/TimeInfo.h>
00077 #include <Base/Interpreter.h>
00078 #include <Base/Reader.h>
00079 #include <Base/Writer.h>
00080 #include <Base/Stream.h>
00081 #include <Base/FileInfo.h>
00082 #include <Base/Tools.h>
00083 #include <Base/Uuid.h>
00084
00085 #include <zipios++/zipios-config.h>
00086 #include <zipios++/zipfile.h>
00087 #include <zipios++/zipinputstream.h>
00088 #include <zipios++/zipoutputstream.h>
00089 #include <zipios++/meta-iostreams.h>
00090
00091 #include "Application.h"
00092 #include "Transactions.h"
00093
00094 using Base::Console;
00095 using Base::streq;
00096 using Base::Writer;
00097 using namespace App;
00098 using namespace std;
00099 using namespace boost;
00100 using namespace zipios;
00101
00102 #ifdef MemDebugOn
00103 # define new DEBUG_CLIENTBLOCK
00104 #endif
00105
00106 #if FC_DEBUG
00107 # define FC_LOGFEATUREUPDATE
00108 #endif
00109
00110
00111 typedef boost::adjacency_list <
00112 boost::vecS,
00113 boost::vecS,
00114 boost::directedS,
00115 boost::no_property,
00116 boost::no_property,
00117 boost::no_property,
00118 boost::listS
00119 > DependencyList;
00120 typedef boost::graph_traits<DependencyList> Traits;
00121 typedef Traits::vertex_descriptor Vertex;
00122 typedef Traits::edge_descriptor Edge;
00123
00124 namespace App {
00125
00126
00127 struct DocumentP
00128 {
00129
00130 std::vector<DocumentObject*> objectArray;
00131 std::map<std::string,DocumentObject*> objectMap;
00132 DocumentObject* activeObject;
00133 Transaction *activeUndoTransaction;
00134 Transaction *activeTransaction;
00135 int iTransactionMode;
00136 int iTransactionCount;
00137 std::map<int,Transaction*> mTransactions;
00138 std::map<Vertex,DocumentObject*> vertexMap;
00139 bool rollback;
00140 bool closable;
00141 int iUndoMode;
00142 unsigned int UndoMemSize;
00143 unsigned int UndoMaxStackSize;
00144
00145 DocumentP() {
00146 activeObject = 0;
00147 activeUndoTransaction = 0;
00148 activeTransaction = 0;
00149 iTransactionMode = 0;
00150 iTransactionCount = 0;
00151 rollback = false;
00152 closable = true;
00153 iUndoMode = 0;
00154 UndoMemSize = 0;
00155 UndoMaxStackSize = 20;
00156 }
00157 };
00158
00159 }
00160
00161 PROPERTY_SOURCE(App::Document, App::PropertyContainer)
00162
00163 void Document::writeDependencyGraphViz(std::ostream &out)
00164 {
00165
00166
00167
00168
00169
00170 out << "digraph G {" << endl;
00171 out << "\tordering=out;" << endl;
00172 out << "\tnode [shape = box];" << endl;
00173
00174 for (std::map<std::string,DocumentObject*>::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) {
00175 out << "\t" << It->first << ";" <<endl;
00176 std::vector<DocumentObject*> OutList = It->second->getOutList();
00177 for (std::vector<DocumentObject*>::const_iterator It2=OutList.begin();It2!=OutList.end();++It2)
00178 if (*It2)
00179 out << "\t" << It->first << "->" << (*It2)->getNameInDocument() << ";" <<endl;
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 out << "}" << endl;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 bool Document::checkOnCycle(void)
00209 {
00210
00211
00212
00213
00214
00215
00216 return false;
00217 }
00218
00219 bool Document::undo(void)
00220 {
00221 if (d->iUndoMode) {
00222 if (d->activeUndoTransaction)
00223 commitTransaction();
00224 else
00225 assert(mUndoTransactions.size()!=0);
00226
00227
00228 d->activeUndoTransaction = new Transaction();
00229 d->activeUndoTransaction->Name = mUndoTransactions.back()->Name;
00230
00231
00232 mUndoTransactions.back()->apply(*this,false);
00233
00234
00235 mRedoTransactions.push_back(d->activeUndoTransaction);
00236 d->activeUndoTransaction = 0;
00237
00238 delete mUndoTransactions.back();
00239 mUndoTransactions.pop_back();
00240 }
00241
00242 return false;
00243 }
00244
00245 bool Document::redo(void)
00246 {
00247 if (d->iUndoMode) {
00248 if (d->activeUndoTransaction)
00249 commitTransaction();
00250
00251 assert(mRedoTransactions.size()!=0);
00252
00253
00254 d->activeUndoTransaction = new Transaction();
00255 d->activeUndoTransaction->Name = mRedoTransactions.back()->Name;
00256
00257
00258 mRedoTransactions.back()->apply(*this,true);
00259 mUndoTransactions.push_back(d->activeUndoTransaction);
00260 d->activeUndoTransaction = 0;
00261
00262 delete mRedoTransactions.back();
00263 mRedoTransactions.pop_back();
00264 }
00265
00266 return false;
00267 }
00268
00269 std::vector<std::string> Document::getAvailableUndoNames() const
00270 {
00271 std::vector<std::string> vList;
00272 if (d->activeUndoTransaction)
00273 vList.push_back(d->activeUndoTransaction->Name);
00274 for (std::list<Transaction*>::const_reverse_iterator It=mUndoTransactions.rbegin();It!=mUndoTransactions.rend();++It)
00275 vList.push_back((**It).Name);
00276 return vList;
00277 }
00278
00279 std::vector<std::string> Document::getAvailableRedoNames() const
00280 {
00281 std::vector<std::string> vList;
00282 for (std::list<Transaction*>::const_reverse_iterator It=mRedoTransactions.rbegin();It!=mRedoTransactions.rend();++It)
00283 vList.push_back((**It).Name);
00284 return vList;
00285 }
00286
00287 void Document::openTransaction(const char* name)
00288 {
00289 if (d->iUndoMode) {
00290 if (d->activeUndoTransaction)
00291 commitTransaction();
00292 _clearRedos();
00293
00294 d->activeUndoTransaction = new Transaction();
00295 if (name)
00296 d->activeUndoTransaction->Name = name;
00297 }
00298 }
00299
00300 void Document::_clearRedos()
00301 {
00302 while (!mRedoTransactions.empty()) {
00303 delete mRedoTransactions.back();
00304 mRedoTransactions.pop_back();
00305 }
00306 }
00307
00308 void Document::commitTransaction()
00309 {
00310 if (d->activeUndoTransaction) {
00311 mUndoTransactions.push_back(d->activeUndoTransaction);
00312 d->activeUndoTransaction = 0;
00313
00314 if(mUndoTransactions.size() > d->UndoMaxStackSize){
00315 delete mUndoTransactions.front();
00316 mUndoTransactions.pop_front();
00317 }
00318 }
00319 }
00320
00321 void Document::abortTransaction()
00322 {
00323 if (d->activeUndoTransaction) {
00324 d->rollback = true;
00325
00326 d->activeUndoTransaction->apply(*this,false);
00327 d->rollback = false;
00328
00329
00330 delete d->activeUndoTransaction;
00331 d->activeUndoTransaction = 0;
00332 }
00333 }
00334
00335 void Document::clearUndos()
00336 {
00337 if (d->activeUndoTransaction)
00338 commitTransaction();
00339
00340
00341
00342
00343
00344
00345
00346 while (!mUndoTransactions.empty()) {
00347 delete mUndoTransactions.front();
00348 mUndoTransactions.pop_front();
00349 }
00350
00351
00352
00353
00354
00355 _clearRedos();
00356 }
00357
00358 int Document::getAvailableUndos() const
00359 {
00360 if (d->activeUndoTransaction)
00361 return static_cast<int>(mUndoTransactions.size() + 1);
00362 else
00363 return static_cast<int>(mUndoTransactions.size());
00364 }
00365
00366 int Document::getAvailableRedos() const
00367 {
00368 return static_cast<int>(mRedoTransactions.size());
00369 }
00370
00371 void Document::setUndoMode(int iMode)
00372 {
00373 if (d->iUndoMode && !iMode)
00374 clearUndos();
00375
00376 d->iUndoMode = iMode;
00377 }
00378
00379 int Document::getUndoMode(void) const
00380 {
00381 return d->iUndoMode;
00382 }
00383
00384 unsigned int Document::getUndoMemSize (void) const
00385 {
00386 return d->UndoMemSize;
00387 }
00388
00389 void Document::setUndoLimit(unsigned int UndoMemSize)
00390 {
00391 d->UndoMemSize = UndoMemSize;
00392 }
00393
00394 void Document::setMaxUndoStackSize(unsigned int UndoMaxStackSize)
00395 {
00396 d->UndoMaxStackSize = UndoMaxStackSize;
00397 }
00398
00399 unsigned int Document::getMaxUndoStackSize(void)const
00400 {
00401 return d->UndoMaxStackSize;
00402 }
00403
00404 void Document::onChanged(const Property* prop)
00405 {
00406
00407 if (prop == &Label)
00408 App::GetApplication().signalRelabelDocument(*this);
00409 }
00410
00411 void Document::onBeforeChangeProperty(const DocumentObject *Who, const Property *What)
00412 {
00413 if (d->activeUndoTransaction && !d->rollback)
00414 d->activeUndoTransaction->addObjectChange(Who,What);
00415 }
00416
00417 void Document::onChangedProperty(const DocumentObject *Who, const Property *What)
00418 {
00419 if (d->activeTransaction && !d->rollback)
00420 d->activeTransaction->addObjectChange(Who,What);
00421 signalChangedObject(*Who, *What);
00422 }
00423
00424 void Document::setTransactionMode(int iMode)
00425 {
00426
00427
00428
00429
00430
00431
00432 d->iTransactionMode = iMode;
00433 }
00434
00435 #if 0
00437 int Document::beginTransaction(void)
00438 {
00439 if (activTransaction)
00440 endTransaction();
00441
00442 iTransactionCount++;
00443
00444 activTransaction = new Transaction(iTransactionCount);
00445 d->mTransactions[iTransactionCount] = activTransaction;
00446
00447 return iTransactionCount;
00448 }
00449
00451 void Document::rollbackTransaction(void)
00452 {
00453
00454 assert(0);
00455 endTransaction();
00456 }
00457
00459 int Document::endTransaction(void)
00460 {
00461 activTransaction = 0;
00462 return iTransactionCount;
00463 }
00464
00466 const Transaction *Document::getTransaction(int pos) const
00467 {
00468 if (pos == -1)
00469 return activTransaction;
00470 else {
00471 std::map<int,Transaction*>::const_iterator Pos(d->mTransactions.find(pos));
00472 if (Pos != d->mTransactions.end())
00473 return Pos->second;
00474 else
00475 return 0;
00476 }
00477 }
00478 #endif
00479
00480
00481
00482
00483 Document::Document(void)
00484 {
00485
00486
00487
00488
00489
00490
00491 DocumentPythonObject = Py::Object(new DocumentPy(this), true);
00492 d = new DocumentP;
00493
00494 #ifdef FC_LOGUPDATECHAIN
00495 Console().Log("+App::Document: %p\n",this);
00496 #endif
00497
00498 ADD_PROPERTY_TYPE(Label,("Unnamed"),0,Prop_None,"The name of the document");
00499 ADD_PROPERTY_TYPE(FileName,(""),0,Prop_None,"The path to the file where the document is saved to");
00500 ADD_PROPERTY_TYPE(CreatedBy,(""),0,Prop_None,"The creator of the document");
00501 ADD_PROPERTY_TYPE(CreationDate,(Base::TimeInfo::currentDateTimeString()),0,Prop_ReadOnly,"Date of creation");
00502 ADD_PROPERTY_TYPE(LastModifiedBy,(""),0,Prop_None,0);
00503 ADD_PROPERTY_TYPE(LastModifiedDate,("Unknown"),0,Prop_ReadOnly,"Date of last modification");
00504 ADD_PROPERTY_TYPE(Company,(""),0,Prop_None,"Additional tag to save the the name of the company");
00505 ADD_PROPERTY_TYPE(Comment,(""),0,Prop_None,"Additional tag to save a comment");
00506
00507 Base::Uuid id;
00508 ADD_PROPERTY_TYPE(Id,(id.UuidStr),0,Prop_None,"UUID of the document");
00509
00510
00511 std::string basePath = Base::FileInfo::getTempPath() + GetApplication().getExecutableName();
00512 Base::FileInfo TransDir(basePath + "_Doc_" + id.UuidStr);
00513 if (!TransDir.exists())
00514 TransDir.createDirectory();
00515 ADD_PROPERTY_TYPE(TransientDir,(TransDir.filePath().c_str()),0,Prop_Transient,
00516 "Transient directory, where the files live while the document is open");
00517 }
00518
00519 Document::~Document()
00520 {
00521 #ifdef FC_LOGUPDATECHAIN
00522 Console().Log("-App::Document: %s %p\n",getName(), this);
00523 #endif
00524
00525 clearUndos();
00526
00527 std::map<std::string,DocumentObject*>::iterator it;
00528
00529 #ifdef FC_LOGUPDATECHAIN
00530 Console().Log("-Delete Features of %s \n",getName());
00531 #endif
00532
00533 d->objectArray.clear();
00534 for (it = d->objectMap.begin(); it != d->objectMap.end(); ++it) {
00535 delete(it->second);
00536 }
00537
00538
00539
00540
00541
00542
00543 Base::PyObjectBase* doc = (Base::PyObjectBase*)DocumentPythonObject.ptr();
00544
00545 doc->setInvalid();
00546
00547
00548 Base::FileInfo TransDir(TransientDir.getValue());
00549 TransDir.deleteDirectoryRecursive();
00550 delete d;
00551 }
00552
00553
00554
00555
00556
00557 void Document::Save (Base::Writer &writer) const
00558 {
00559 writer.Stream() << "<?xml version='1.0' encoding='utf-8'?>" << endl
00560 << "<!--" << endl
00561 << " FreeCAD Document, see http://free-cad.sourceforge.net for more information..." << endl
00562 << "-->" << endl;
00563
00564 writer.Stream() << "<Document SchemaVersion=\"4\">" << endl;
00565
00566 PropertyContainer::Save(writer);
00567
00568
00569 writer.incInd();
00570 writer.Stream() << writer.ind() << "<Objects Count=\"" << d->objectArray.size() <<"\">" << endl;
00571
00572 writer.incInd();
00573 std::vector<DocumentObject*>::const_iterator it;
00574 for (it = d->objectArray.begin(); it != d->objectArray.end(); ++it) {
00575 writer.Stream() << writer.ind() << "<Object "
00576 << "type=\"" << (*it)->getTypeId().getName() << "\" "
00577 << "name=\"" << (*it)->getNameInDocument() << "\" "
00578 << "/>" << endl;
00579 }
00580
00581 writer.decInd();
00582 writer.Stream() << writer.ind() << "</Objects>" << endl;
00583
00584
00585 writer.Stream() << writer.ind() << "<ObjectData Count=\"" << d->objectArray.size() <<"\">" << endl;
00586
00587 writer.incInd();
00588 for (it = d->objectArray.begin(); it != d->objectArray.end(); ++it) {
00589 writer.Stream() << writer.ind() << "<Object name=\"" << (*it)->getNameInDocument() << "\">" << endl;
00590 (*it)->Save(writer);
00591 writer.Stream() << writer.ind() << "</Object>" << endl;
00592 }
00593
00594 writer.decInd();
00595 writer.Stream() << writer.ind() << "</ObjectData>" << endl;
00596 writer.decInd();
00597 writer.Stream() << "</Document>" << endl;
00598 }
00599
00600 void Document::Restore(Base::XMLReader &reader)
00601 {
00602 int i,Cnt;
00603 reader.readElement("Document");
00604 long scheme = reader.getAttributeAsInteger("SchemaVersion");
00605 reader.DocumentSchema = scheme;
00606
00607
00608
00609
00610
00611
00612
00613
00614 std::string FilePath = FileName.getValue();
00615 std::string DocLabel = Label.getValue();
00616
00617
00618 Base::FileInfo TransDir(TransientDir.getValue());
00619 TransDir.deleteDirectoryRecursive();
00620
00621
00622
00623 PropertyContainer::Restore(reader);
00624
00625
00626
00627 FileName.setValue(FilePath.c_str());
00628 Label.setValue(DocLabel.c_str());
00629
00630
00631 std::string basePath = Base::FileInfo::getTempPath() + GetApplication().getExecutableName();
00632 Base::FileInfo TransDirNew(basePath + "_Doc_" + Id.getValue());
00633 if(!TransDirNew.exists())
00634 TransDirNew.createDirectory();
00635 TransientDir.setValue(TransDirNew.filePath());
00636
00637
00638
00639 if ( scheme == 2 ) {
00640
00641 reader.readElement("Features");
00642 Cnt = reader.getAttributeAsInteger("Count");
00643 for (i=0 ;i<Cnt ;i++) {
00644 reader.readElement("Feature");
00645 string type = reader.getAttribute("type");
00646 string name = reader.getAttribute("name");
00647
00648 try {
00649 addObject(type.c_str(),name.c_str());
00650 }
00651 catch ( Base::Exception& ) {
00652 Base::Console().Message("Cannot create object '%s'\n", name.c_str());
00653 }
00654 }
00655 reader.readEndElement("Features");
00656
00657
00658 reader.readElement("FeatureData");
00659 Cnt = reader.getAttributeAsInteger("Count");
00660 for (i=0 ;i<Cnt ;i++) {
00661 reader.readElement("Feature");
00662 string name = reader.getAttribute("name");
00663 DocumentObject* pObj = getObject(name.c_str());
00664 if (pObj) {
00665 pObj->StatusBits.set(4);
00666 pObj->Restore(reader);
00667 pObj->StatusBits.reset(4);
00668 }
00669 reader.readEndElement("Feature");
00670 }
00671 reader.readEndElement("FeatureData");
00672 }
00673 else if ( scheme >= 3 ) {
00674
00675 reader.readElement("Objects");
00676 Cnt = reader.getAttributeAsInteger("Count");
00677 for (i=0 ;i<Cnt ;i++) {
00678 reader.readElement("Object");
00679 string type = reader.getAttribute("type");
00680 string name = reader.getAttribute("name");
00681
00682 try {
00683 addObject(type.c_str(),name.c_str());
00684 }
00685 catch ( Base::Exception& ) {
00686 Base::Console().Message("Cannot create object '%s'\n", name.c_str());
00687 }
00688 }
00689 reader.readEndElement("Objects");
00690
00691
00692 reader.readElement("ObjectData");
00693 Cnt = reader.getAttributeAsInteger("Count");
00694 for (i=0 ;i<Cnt ;i++) {
00695 reader.readElement("Object");
00696 string name = reader.getAttribute("name");
00697 DocumentObject* pObj = getObject(name.c_str());
00698 if (pObj) {
00699 pObj->StatusBits.set(4);
00700 pObj->Restore(reader);
00701 pObj->StatusBits.reset(4);
00702 }
00703 reader.readEndElement("Object");
00704 }
00705 reader.readEndElement("ObjectData");
00706 }
00707
00708 reader.readEndElement("Document");
00709 }
00710
00711 void Document::exportObjects(const std::vector<App::DocumentObject*>& obj,
00712 std::ostream& out)
00713 {
00714 Base::ZipWriter writer(out);
00715 writer.putNextEntry("Document.xml");
00716 writer.Stream() << "<?xml version='1.0' encoding='utf-8'?>" << endl;
00717 writer.Stream() << "<Document SchemaVersion=\"4\">" << endl;
00718
00719 writer.Stream() << "<Properties Count=\"0\">" << endl;
00720 writer.Stream() << "</Properties>" << endl;
00721
00722
00723 writer.incInd();
00724 writer.Stream() << writer.ind() << "<Objects Count=\"" << obj.size() <<"\">" << endl;
00725
00726 writer.incInd();
00727 std::vector<DocumentObject*>::const_iterator it;
00728 for (it = obj.begin(); it != obj.end(); ++it) {
00729 writer.Stream() << writer.ind() << "<Object "
00730 << "type=\"" << (*it)->getTypeId().getName() << "\" "
00731 << "name=\"" << (*it)->getNameInDocument() << "\" "
00732 << "/>" << endl;
00733 }
00734
00735 writer.decInd();
00736 writer.Stream() << writer.ind() << "</Objects>" << endl;
00737
00738
00739 writer.Stream() << writer.ind() << "<ObjectData Count=\"" << obj.size() <<"\">" << endl;
00740
00741 writer.incInd();
00742 for (it = obj.begin(); it != obj.end(); ++it) {
00743 writer.Stream() << writer.ind() << "<Object name=\"" << (*it)->getNameInDocument() << "\">" << endl;
00744 (*it)->Save(writer);
00745 writer.Stream() << writer.ind() << "</Object>" << endl;
00746 }
00747
00748 writer.decInd();
00749 writer.Stream() << writer.ind() << "</ObjectData>" << endl;
00750 writer.decInd();
00751 writer.Stream() << "</Document>" << endl;
00752
00753
00754 signalExportObjects(obj, writer);
00755
00756
00757 writer.writeFiles();
00758 }
00759
00760 std::vector<App::DocumentObject*>
00761 Document::importObjects(std::istream& input)
00762 {
00763 std::vector<App::DocumentObject*> objs;
00764 zipios::ZipInputStream zipstream(input);
00765 Base::XMLReader reader("<memory>", zipstream);
00766
00767 int i,Cnt;
00768 reader.readElement("Document");
00769 long scheme = reader.getAttributeAsInteger("SchemaVersion");
00770 reader.DocumentSchema = scheme;
00771
00772
00773 std::map<std::string, std::string> nameMap;
00774 reader.readElement("Objects");
00775 Cnt = reader.getAttributeAsInteger("Count");
00776 for (i=0 ;i<Cnt ;i++) {
00777 reader.readElement("Object");
00778 string type = reader.getAttribute("type");
00779 string name = reader.getAttribute("name");
00780
00781 try {
00782 App::DocumentObject* o = addObject(type.c_str(),name.c_str());
00783 objs.push_back(o);
00784
00785
00786 nameMap[name] = o->getNameInDocument();
00787 }
00788 catch (Base::Exception&) {
00789 Base::Console().Message("Cannot create object '%s'\n", name.c_str());
00790 }
00791 }
00792 reader.readEndElement("Objects");
00793
00794
00795 reader.readElement("ObjectData");
00796 Cnt = reader.getAttributeAsInteger("Count");
00797 for (i=0 ;i<Cnt ;i++) {
00798 reader.readElement("Object");
00799 std::string name = nameMap[reader.getAttribute("name")];
00800 DocumentObject* pObj = getObject(name.c_str());
00801 if (pObj) {
00802 pObj->StatusBits.set(4);
00803 pObj->Restore(reader);
00804 pObj->StatusBits.reset(4);
00805 }
00806 reader.readEndElement("Object");
00807 }
00808 reader.readEndElement("ObjectData");
00809
00810 reader.readEndElement("Document");
00811 signalImportObjects(objs, reader);
00812 reader.readFiles(zipstream);
00813
00814 for (std::vector<DocumentObject*>::iterator it= objs.begin();it!=objs.end();++it)
00815 (*it)->purgeTouched();
00816 return objs;
00817 }
00818
00819 unsigned int Document::getMemSize (void) const
00820 {
00821 unsigned int size = 0;
00822
00823
00824 std::vector<DocumentObject*>::const_iterator it;
00825 for (it = d->objectArray.begin(); it != d->objectArray.end(); ++it)
00826 size += (*it)->getMemSize();
00827
00828
00829 size += PropertyContainer::getMemSize();
00830
00831
00832 size += getUndoMemSize();
00833
00834 return size;
00835 }
00836
00837
00838 bool Document::save (void)
00839 {
00840 int compression = App::GetApplication().GetParameterGroupByPath
00841 ("User parameter:BaseApp/Preferences/Document")->GetInt("CompressionLevel",3);
00842
00843 if (*(FileName.getValue()) != '\0') {
00844 LastModifiedDate.setValue(Base::TimeInfo::currentDateTimeString());
00845
00846
00847
00848 std::string uuid = Base::Uuid::CreateUuid();
00849 std::string fn = FileName.getValue();
00850 fn += "."; fn += uuid;
00851 Base::FileInfo tmp(fn);
00852
00853
00854 {
00855 Base::ofstream file(tmp, std::ios::out | std::ios::binary);
00856 Base::ZipWriter writer(file);
00857
00858 writer.setComment("FreeCAD Document");
00859 writer.setLevel(compression);
00860 writer.putNextEntry("Document.xml");
00861
00862 Document::Save(writer);
00863
00864
00865 signalSaveDocument(writer);
00866
00867
00868 writer.writeFiles();
00869
00870 GetApplication().signalSaveDocument(*this);
00871 }
00872
00873
00874 Base::FileInfo fi(FileName.getValue());
00875 if (fi.exists()) {
00876 bool backup = App::GetApplication().GetParameterGroupByPath
00877 ("User parameter:BaseApp/Preferences/Document")->GetBool("CreateBackupFiles",true);
00878 int count_bak = App::GetApplication().GetParameterGroupByPath
00879 ("User parameter:BaseApp/Preferences/Document")->GetInt("CountBackupFiles",1);
00880 if (backup) {
00881 int nSuff = 0;
00882 std::string fn = fi.fileName();
00883 Base::FileInfo di(fi.dirPath());
00884 std::vector<Base::FileInfo> backup;
00885 std::vector<Base::FileInfo> files = di.getDirectoryContent();
00886 for (std::vector<Base::FileInfo>::iterator it = files.begin(); it != files.end(); ++it) {
00887 std::string file = it->fileName();
00888 if (file.substr(0,fn.length()) == fn) {
00889
00890 std::string suf(file.substr(fn.length()));
00891 if (suf.size() > 0) {
00892 std::string::size_type nPos = suf.find_first_not_of("0123456789");
00893 if (nPos==std::string::npos) {
00894
00895 backup.push_back(*it);
00896 nSuff = std::max<int>(nSuff, std::atol(suf.c_str()));
00897 }
00898 }
00899 }
00900 }
00901
00902 if (!backup.empty() && (int)backup.size() >= count_bak) {
00903
00904 Base::FileInfo del = backup.front();
00905 for (std::vector<Base::FileInfo>::iterator it = backup.begin(); it != backup.end(); ++it) {
00906 if (it->lastModified() < del.lastModified())
00907 del = *it;
00908 }
00909
00910 del.deleteFile();
00911 fn = del.filePath();
00912 }
00913 else {
00914
00915 std::stringstream str;
00916 str << fi.filePath() << (nSuff + 1);
00917 fn = str.str();
00918 }
00919
00920 fi.renameFile(fn.c_str());
00921 }
00922 else {
00923 fi.deleteFile();
00924 }
00925 }
00926 if (tmp.renameFile(FileName.getValue()) == false)
00927 Base::Console().Warning("Cannot rename file from '%s' to '%s'\n",
00928 fn.c_str(), FileName.getValue());
00929
00930 return true;
00931 }
00932
00933 return false;
00934 }
00935
00936
00937 void Document::restore (void)
00938 {
00939
00940
00941 clearUndos();
00942 for (std::vector<DocumentObject*>::iterator obj = d->objectArray.begin(); obj != d->objectArray.end(); ++obj) {
00943 signalDeletedObject(*(*obj));
00944 delete *obj;
00945 }
00946 d->objectArray.clear();
00947 d->objectMap.clear();
00948 d->activeObject = 0;
00949
00950 Base::FileInfo fi(FileName.getValue());
00951 Base::ifstream file(fi, std::ios::in | std::ios::binary);
00952 std::streambuf* buf = file.rdbuf();
00953 std::streamoff size = buf->pubseekoff(0, std::ios::end, std::ios::in);
00954 buf->pubseekoff(0, std::ios::beg, std::ios::in);
00955 if (size < 22)
00956 throw Base::FileException("Invalid project file",FileName.getValue());
00957
00958 zipios::ZipInputStream zipstream(file);
00959 Base::XMLReader reader(FileName.getValue(), zipstream);
00960
00961 if (!reader.isValid())
00962 throw Base::FileException("Error reading compression file",FileName.getValue());
00963
00964 try {
00965 Document::Restore(reader);
00966 }
00967 catch (const Base::Exception& e) {
00968 Base::Console().Error("Invalid Document.xml: %s\n", e.what());
00969 }
00970
00971
00972
00973
00974
00975 signalRestoreDocument(reader);
00976 reader.readFiles(zipstream);
00977
00978
00979 for (std::map<std::string,DocumentObject*>::iterator It= d->objectMap.begin();It!=d->objectMap.end();++It)
00980 It->second->purgeTouched();
00981
00982 GetApplication().signalRestoreDocument(*this);
00983 }
00984
00985 bool Document::isSaved() const
00986 {
00987 std::string name = FileName.getValue();
00988 return !name.empty();
00989 }
00990
01004 const char* Document::getName() const
01005 {
01006 return GetApplication().getDocumentName(this);
01007 }
01008
01010 void Document::purgeTouched()
01011 {
01012 for (std::vector<DocumentObject*>::iterator It = d->objectArray.begin();It != d->objectArray.end();++It)
01013 (*It)->purgeTouched();
01014 }
01015
01016 bool Document::isTouched() const
01017 {
01018 for (std::vector<DocumentObject*>::const_iterator It = d->objectArray.begin();It != d->objectArray.end();++It)
01019 if ((*It)->isTouched())
01020 return true;
01021 return false;
01022 }
01023
01024 vector<DocumentObject*> Document::getTouched(void) const
01025 {
01026 vector<DocumentObject*> result;
01027
01028 for (std::vector<DocumentObject*>::const_iterator It = d->objectArray.begin();It != d->objectArray.end();++It)
01029 if ((*It)->isTouched())
01030 result.push_back(*It);
01031
01032 return result;
01033 }
01034
01035 void Document::setClosable(bool c)
01036 {
01037 d->closable = c;
01038 }
01039
01040 bool Document::isClosable() const
01041 {
01042 return d->closable;
01043 }
01044
01045 int Document::countObjects(void) const
01046 {
01047 return static_cast<int>(d->objectArray.size());
01048 }
01049
01050 std::vector<App::DocumentObject*> Document::getInList(const DocumentObject* me) const
01051 {
01052
01053 std::vector<App::DocumentObject*> result;
01054
01055 for (std::map<std::string,DocumentObject*>::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) {
01056
01057 std::vector<DocumentObject*> OutList = It->second->getOutList();
01058 for (std::vector<DocumentObject*>::const_iterator It2=OutList.begin();It2!=OutList.end();++It2)
01059 if (*It2 && *It2 == me)
01060
01061 result.push_back(It->second);
01062 }
01063 return result;
01064 }
01065
01066 void Document::recompute()
01067 {
01068
01069 for( std::vector<App::DocumentObjectExecReturn*>::iterator it=_RecomputeLog.begin();it!=_RecomputeLog.end();++it)
01070 delete *it;
01071 _RecomputeLog.clear();
01072
01073 DependencyList DepList;
01074 std::map<DocumentObject*,Vertex> VertexObjectList;
01075
01076
01077 for (std::map<std::string,DocumentObject*>::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It)
01078
01079 VertexObjectList[It->second] = add_vertex(DepList);
01080
01081 for (std::map<std::string,DocumentObject*>::const_iterator It = d->objectMap.begin(); It != d->objectMap.end();++It) {
01082 std::vector<DocumentObject*> OutList = It->second->getOutList();
01083 for (std::vector<DocumentObject*>::const_iterator It2=OutList.begin();It2!=OutList.end();++It2)
01084 if (*It2)
01085 add_edge(VertexObjectList[It->second],VertexObjectList[*It2],DepList);
01086 }
01087
01088 std::list<Vertex> make_order;
01089 DependencyList::out_edge_iterator j, jend;
01090
01091 try {
01092
01093 boost::topological_sort(DepList, std::front_inserter(make_order));
01094 }
01095 catch (const std::exception& e) {
01096 std::cerr << "Document::recompute: " << e.what() << std::endl;
01097 return;
01098 }
01099
01100
01101 for (std::map<DocumentObject*,Vertex>::const_iterator It1= VertexObjectList.begin();It1 != VertexObjectList.end(); ++It1)
01102 d->vertexMap[It1->second] = It1->first;
01103
01104 #ifdef FC_LOGFEATUREUPDATE
01105 std::clog << "make ordering: " << std::endl;
01106 #endif
01107
01108 for (std::list<Vertex>::reverse_iterator i = make_order.rbegin();i != make_order.rend(); ++i) {
01109 DocumentObject* Cur = d->vertexMap[*i];
01110 if (!Cur) continue;
01111 #ifdef FC_LOGFEATUREUPDATE
01112 std::clog << Cur->getNameInDocument() << " dep on: " ;
01113 #endif
01114 bool NeedUpdate = false;
01115
01116
01117 if (Cur->mustExecute() == 1)
01118 NeedUpdate = true;
01119 else {
01120
01121 for (boost::tie(j, jend) = out_edges(*i, DepList); j != jend; ++j) {
01122 DocumentObject* Test = d->vertexMap[target(*j, DepList)];
01123 if (!Test) continue;
01124 #ifdef FC_LOGFEATUREUPDATE
01125 std::clog << Test->getNameInDocument() << ", " ;
01126 #endif
01127 if (Test->isTouched()) {
01128 NeedUpdate = true;
01129 break;
01130 }
01131 }
01132 #ifdef FC_LOGFEATUREUPDATE
01133 std::clog << std::endl;
01134 #endif
01135 }
01136
01137 if (NeedUpdate) {
01138 #ifdef FC_LOGFEATUREUPDATE
01139 std::clog << "Recompute" << std::endl;
01140 #endif
01141 if (_recomputeFeature(Cur)) {
01142
01143 d->vertexMap.clear();
01144 return;
01145 }
01146 }
01147 }
01148
01149
01150 for (std::map<Vertex,DocumentObject*>::iterator it = d->vertexMap.begin(); it != d->vertexMap.end(); ++it) {
01151 if (it->second)
01152 it->second->purgeTouched();
01153 }
01154 d->vertexMap.clear();
01155 }
01156
01157 const char * Document::getErrorDescription(const App::DocumentObject*Obj) const
01158 {
01159 for (std::vector<App::DocumentObjectExecReturn*>::const_iterator it=_RecomputeLog.begin();it!=_RecomputeLog.end();++it)
01160 if ((*it)->Which == Obj)
01161 return (*it)->Why.c_str();
01162 return 0;
01163 }
01164
01165
01166 bool Document::_recomputeFeature(DocumentObject* Feat)
01167 {
01168 #ifdef FC_LOGFEATUREUPDATE
01169 std::clog << "Solv: Executing Feature: " << Feat->getNameInDocument() << std::endl;;
01170 #endif
01171
01172 DocumentObjectExecReturn *returnCode = 0;
01173 try {
01174 returnCode = Feat->recompute();
01175 }
01176 catch(Base::AbortException &e){
01177 e.ReportException();
01178 _RecomputeLog.push_back(new DocumentObjectExecReturn("User abort",Feat));
01179 Feat->setError();
01180 return true;
01181 }
01182 catch (const Base::MemoryException& e) {
01183 Base::Console().Error("Memory exception in feature '%s' thrown: %s\n",Feat->getNameInDocument(),e.what());
01184 _RecomputeLog.push_back(new DocumentObjectExecReturn("Out of memory exception",Feat));
01185 Feat->setError();
01186 return true;
01187 }
01188 catch (Base::Exception &e) {
01189 e.ReportException();
01190 _RecomputeLog.push_back(new DocumentObjectExecReturn(e.what(),Feat));
01191 Feat->setError();
01192 return false;
01193 }
01194 catch (std::exception &e) {
01195 Base::Console().Warning("exception in Feature \"%s\" thrown: %s\n",Feat->getNameInDocument(),e.what());
01196 _RecomputeLog.push_back(new DocumentObjectExecReturn(e.what(),Feat));
01197 Feat->setError();
01198 return false;
01199 }
01200 #ifndef FC_DEBUG
01201 catch (...) {
01202 Base::Console().Error("App::Document::_RecomputeFeature(): Unknown exception in Feature \"%s\" thrown\n",Feat->getNameInDocument());
01203 _RecomputeLog.push_back(new DocumentObjectExecReturn("Unknown exeption!"));
01204 Feat->setError();
01205 return true;
01206 }
01207 #endif
01208
01209
01210 if (returnCode == DocumentObject::StdReturn) {
01211 Feat->resetError();
01212 }
01213 else {
01214 returnCode->Which = Feat;
01215 _RecomputeLog.push_back(returnCode);
01216 Base::Console().Error("%s\n",returnCode->Why.c_str());
01217 Feat->setError();
01218 }
01219 return false;
01220 }
01221
01222 void Document::recomputeFeature(DocumentObject* Feat)
01223 {
01224
01225 for( std::vector<App::DocumentObjectExecReturn*>::iterator it=_RecomputeLog.begin();it!=_RecomputeLog.end();++it)
01226 delete *it;
01227 _RecomputeLog.clear();
01228
01229 _recomputeFeature(Feat);
01230 }
01231
01232 DocumentObject * Document::addObject(const char* sType, const char* pObjectName)
01233 {
01234 Base::BaseClass* base = static_cast<Base::BaseClass*>(Base::Type::createInstanceByName(sType,true));
01235
01236 string ObjectName;
01237 if (!base)
01238 return 0;
01239 if (!base->getTypeId().isDerivedFrom(App::DocumentObject::getClassTypeId())) {
01240 delete base;
01241 std::stringstream str;
01242 str << "'" << sType << "' is not a document object type";
01243 throw Base::Exception(str.str());
01244 }
01245
01246 App::DocumentObject* pcObject = static_cast<App::DocumentObject*>(base);
01247 pcObject->setDocument(this);
01248
01249
01250 if(!d->rollback){
01251
01252 if (d->activeTransaction)
01253 d->activeTransaction->addObjectNew(pcObject);
01254
01255 if (d->activeUndoTransaction)
01256 d->activeUndoTransaction->addObjectDel(pcObject);
01257 }
01258
01259
01260 if (pObjectName && pObjectName[0] != '\0')
01261 ObjectName = getUniqueObjectName(pObjectName);
01262 else
01263 ObjectName = getUniqueObjectName(sType);
01264
01265
01266 d->activeObject = pcObject;
01267
01268
01269 d->objectMap[ObjectName] = pcObject;
01270
01271 pcObject->pcNameInDocument = &(d->objectMap.find(ObjectName)->first);
01272
01273 d->objectArray.push_back(pcObject);
01274
01275
01276
01277 pcObject->Label.setValue( ObjectName );
01278
01279
01280 pcObject->StatusBits.set(2);
01281 signalNewObject(*pcObject);
01282 signalActivatedObject(*pcObject);
01283
01284
01285 return pcObject;
01286 }
01287
01288 void Document::_addObject(DocumentObject* pcObject, const char* pObjectName)
01289 {
01290 d->objectMap[pObjectName] = pcObject;
01291 d->objectArray.push_back(pcObject);
01292
01293 pcObject->pcNameInDocument = &(d->objectMap.find(pObjectName)->first);
01294
01295
01296 if(!d->rollback){
01297
01298 if (d->activeTransaction)
01299 d->activeTransaction->addObjectNew(pcObject);
01300
01301 if (d->activeUndoTransaction)
01302 d->activeUndoTransaction->addObjectDel(pcObject);
01303 }
01304
01305 signalNewObject(*pcObject);
01306 }
01307
01309 void Document::remObject(const char* sName)
01310 {
01311 std::map<std::string,DocumentObject*>::iterator pos = d->objectMap.find(sName);
01312
01313
01314 if (pos == d->objectMap.end())
01315 return;
01316
01317 if (d->activeObject == pos->second)
01318 d->activeObject = 0;
01319
01320 signalDeletedObject(*(pos->second));
01321 if (!d->vertexMap.empty()) {
01322
01323 for (std::map<Vertex,DocumentObject*>::iterator it = d->vertexMap.begin(); it != d->vertexMap.end(); ++it) {
01324 if (it->second == pos->second) {
01325 it->second = 0;
01326 break;
01327 }
01328 }
01329 }
01330
01331
01332 breakDependency(pos->second, true);
01333
01334
01335 if(!d->rollback){
01336
01337
01338 if (d->activeTransaction)
01339 d->activeTransaction->addObjectDel(pos->second);
01340
01341
01342 if (d->activeUndoTransaction) {
01343
01344 d->activeUndoTransaction->addObjectNew(pos->second);
01345
01346
01347 }
01348 else
01349
01350 delete pos->second;
01351 }
01352
01353 for (std::vector<DocumentObject*>::iterator obj = d->objectArray.begin(); obj != d->objectArray.end(); ++obj) {
01354 if (*obj == pos->second) {
01355 d->objectArray.erase(obj);
01356 break;
01357 }
01358 }
01359
01360
01361
01362 d->objectMap.erase(pos);
01363 }
01364
01366 void Document::_remObject(DocumentObject* pcObject)
01367 {
01368 std::map<std::string,DocumentObject*>::iterator pos = d->objectMap.find(pcObject->getNameInDocument());
01369
01370 if (d->activeObject == pcObject)
01371 d->activeObject = 0;
01372
01373 signalDeletedObject(*pcObject);
01374
01375
01376 if(!d->rollback){
01377
01378 if (d->activeTransaction)
01379 d->activeTransaction->addObjectDel(pcObject);
01380
01381
01382 if (d->activeUndoTransaction)
01383 d->activeUndoTransaction->addObjectNew(pcObject);
01384 }
01385
01386 d->objectMap.erase(pos);
01388
01389
01390 for (std::vector<DocumentObject*>::iterator it = d->objectArray.begin(); it != d->objectArray.end(); ++it) {
01391 if (*it == pcObject) {
01392 d->objectArray.erase(it);
01393 break;
01394 }
01395 }
01396 }
01397
01398 void Document::breakDependency(DocumentObject* pcObject, bool clear)
01399 {
01400
01401 for (std::map<std::string,DocumentObject*>::iterator it = d->objectMap.begin(); it != d->objectMap.end(); ++it) {
01402 std::map<std::string,App::Property*> Map;
01403 it->second->getPropertyMap(Map);
01404
01405 for (std::map<std::string,App::Property*>::iterator pt = Map.begin(); pt != Map.end(); ++pt) {
01406 if (pt->second->getTypeId().isDerivedFrom(PropertyLink::getClassTypeId())) {
01407 PropertyLink* link = static_cast<PropertyLink*>(pt->second);
01408 if (link->getValue() == pcObject)
01409 link->setValue(0);
01410 else if (link->getContainer() == pcObject && clear)
01411 link->setValue(0);
01412 }
01413 else if (pt->second->getTypeId().isDerivedFrom(PropertyLinkSub::getClassTypeId())) {
01414 PropertyLinkSub* link = static_cast<PropertyLinkSub*>(pt->second);
01415 if (link->getValue() == pcObject)
01416 link->setValue(0);
01417 else if (link->getContainer() == pcObject && clear)
01418 link->setValue(0);
01419 }
01420 else if (pt->second->getTypeId().isDerivedFrom(PropertyLinkList::getClassTypeId())) {
01421 PropertyLinkList* link = static_cast<PropertyLinkList*>(pt->second);
01422 if (link->getContainer() == pcObject && clear) {
01423 link->setValues(std::vector<DocumentObject*>());
01424 }
01425 else {
01426
01427 std::vector<DocumentObject*> linked = link->getValues();
01428 for (std::vector<DocumentObject*>::iterator fIt = linked.begin(); fIt != linked.end(); ++fIt) {
01429 if ((*fIt) == pcObject) {
01430
01431 linked.erase(fIt);
01432 link->setValues(linked);
01433 break;
01434 }
01435 }
01436 }
01437 }
01438 }
01439 }
01440 }
01441
01442 DocumentObject* Document::_copyObject(DocumentObject* obj, std::map<DocumentObject*,
01443 DocumentObject*>& copy_map, bool recursive)
01444 {
01445 if (!obj) return 0;
01446
01447 std::string objname = obj->getNameInDocument();
01448 size_t lastpos = objname.length()-1;
01449 while (objname[lastpos] >= 48 && objname[lastpos] <= 57)
01450 lastpos--;
01451 objname = objname.substr(0, lastpos+1);
01452 DocumentObject* copy = addObject(obj->getTypeId().getName(),objname.c_str());
01453 if (!copy) return 0;
01454 copy->addDynamicProperties(obj);
01455
01456 copy_map[obj] = copy;
01457
01458 std::map<std::string,App::Property*> props;
01459 copy->getPropertyMap(props);
01460 for (std::map<std::string,App::Property*>::iterator it = props.begin(); it != props.end(); ++it) {
01461 App::Property* prop = obj->getPropertyByName(it->first.c_str());
01462 if (prop && prop->getTypeId() == it->second->getTypeId()) {
01463 if (prop->getTypeId() == PropertyLink::getClassTypeId()) {
01464 DocumentObject* link = static_cast<PropertyLink*>(prop)->getValue();
01465 std::map<DocumentObject*, DocumentObject*>::iterator pt = copy_map.find(link);
01466 if (pt != copy_map.end()) {
01467
01468 static_cast<PropertyLink*>(it->second)->setValue(pt->second);
01469 }
01470 else if (recursive) {
01471 DocumentObject* link_copy = _copyObject(link, copy_map, recursive);
01472 copy_map[link] = link_copy;
01473 static_cast<PropertyLink*>(it->second)->setValue(link_copy);
01474 }
01475 else if (link && link->getDocument() == this) {
01476
01477 }
01478 }
01479 else if (prop->getTypeId() == PropertyLinkList::getClassTypeId()) {
01480 std::vector<DocumentObject*> links = static_cast<PropertyLinkList*>(prop)->getValues();
01481 if (recursive) {
01482 std::vector<DocumentObject*> links_copy;
01483 for (std::vector<DocumentObject*>::iterator jt = links.begin(); jt != links.end(); ++jt) {
01484 std::map<DocumentObject*, DocumentObject*>::iterator pt = copy_map.find(*jt);
01485 if (pt != copy_map.end()) {
01486
01487 links_copy.push_back(pt->second);
01488 }
01489 else {
01490 links_copy.push_back(_copyObject(*jt, copy_map, recursive));
01491 copy_map[*jt] = links_copy.back();
01492 }
01493 }
01494 static_cast<PropertyLinkList*>(it->second)->setValues(links_copy);
01495 }
01496 else {
01497 std::vector<DocumentObject*> links_ref;
01498
01499
01500
01501
01502 static_cast<PropertyLinkList*>(it->second)->setValues(links_ref);
01503 }
01504 }
01505 else {
01506 std::auto_ptr<Property> data(prop->Copy());
01507 if (data.get()) {
01508 it->second->Paste(*data);
01509 }
01510 }
01511 }
01512 }
01513
01514
01515 copy->purgeTouched();
01516 return copy;
01517 }
01518
01519 DocumentObject* Document::copyObject(DocumentObject* obj, bool recursive)
01520 {
01521 std::map<DocumentObject*, DocumentObject*> copy_map;
01522 DocumentObject* copy = _copyObject(obj, copy_map, recursive);
01523 return copy;
01524 }
01525
01526 DocumentObject* Document::moveObject(DocumentObject* obj, bool recursive)
01527 {
01528 Document* that = obj->getDocument();
01529 if (that == this)
01530 return 0;
01531
01532
01533 that->breakDependency(obj, false);
01534 std::string objname = getUniqueObjectName(obj->getNameInDocument());
01535 that->_remObject(obj);
01536 this->_addObject(obj, objname.c_str());
01537 obj->setDocument(this);
01538
01539 std::map<std::string,App::Property*> props;
01540 obj->getPropertyMap(props);
01541 for (std::map<std::string,App::Property*>::iterator it = props.begin(); it != props.end(); ++it) {
01542 if (it->second->getTypeId() == PropertyLink::getClassTypeId()) {
01543 DocumentObject* link = static_cast<PropertyLink*>(it->second)->getValue();
01544 if (recursive) {
01545 moveObject(link, recursive);
01546 static_cast<PropertyLink*>(it->second)->setValue(link);
01547 }
01548 else {
01549 static_cast<PropertyLink*>(it->second)->setValue(0);
01550 }
01551 }
01552 else if (it->second->getTypeId() == PropertyLinkList::getClassTypeId()) {
01553 std::vector<DocumentObject*> links = static_cast<PropertyLinkList*>(it->second)->getValues();
01554 if (recursive) {
01555 for (std::vector<DocumentObject*>::iterator jt = links.begin(); jt != links.end(); ++jt)
01556 moveObject(*jt, recursive);
01557 static_cast<PropertyLinkList*>(it->second)->setValues(links);
01558 }
01559 else {
01560 static_cast<PropertyLinkList*>(it->second)->setValues(std::vector<DocumentObject*>());
01561 }
01562 }
01563 }
01564
01565 return obj;
01566 }
01567
01568 DocumentObject * Document::getActiveObject(void) const
01569 {
01570 return d->activeObject;
01571 }
01572
01573 DocumentObject * Document::getObject(const char *Name) const
01574 {
01575 std::map<std::string,DocumentObject*>::const_iterator pos;
01576
01577 pos = d->objectMap.find(Name);
01578
01579 if (pos != d->objectMap.end())
01580 return pos->second;
01581 else
01582 return 0;
01583 }
01584
01585 const char * Document::getObjectName(DocumentObject *pFeat) const
01586 {
01587 std::map<std::string,DocumentObject*>::const_iterator pos;
01588
01589 for (pos = d->objectMap.begin();pos != d->objectMap.end();++pos)
01590 if (pos->second == pFeat)
01591 return pos->first.c_str();
01592
01593 return 0;
01594 }
01595
01596 std::string Document::getUniqueObjectName(const char *Name) const
01597 {
01598 if (!Name || *Name == '\0')
01599 return std::string();
01600 std::string CleanName = Base::Tools::getIdentifier(Name);
01601
01602
01603 std::map<std::string,DocumentObject*>::const_iterator pos;
01604 pos = d->objectMap.find(CleanName);
01605
01606 if (pos == d->objectMap.end()) {
01607
01608 return CleanName;
01609 }
01610 else {
01611 std::vector<std::string> names;
01612 names.reserve(d->objectMap.size());
01613 for (pos = d->objectMap.begin();pos != d->objectMap.end();++pos) {
01614 names.push_back(pos->first);
01615 }
01616 return Base::Tools::getUniqueName(CleanName, names, 3);
01617 }
01618 }
01619
01620 std::string Document::getStandardObjectName(const char *Name, int d) const
01621 {
01622 std::vector<App::DocumentObject*> mm = getObjects();
01623 std::vector<std::string> labels;
01624 labels.reserve(mm.size());
01625
01626 for (std::vector<App::DocumentObject*>::const_iterator it = mm.begin(); it != mm.end(); ++it) {
01627 std::string label = (*it)->Label.getValue();
01628 labels.push_back(label);
01629 }
01630 return Base::Tools::getUniqueName(Name, labels, d);
01631 }
01632
01633 std::vector<DocumentObject*> Document::getObjects() const
01634 {
01635 return d->objectArray;
01636 }
01637
01638 std::vector<DocumentObject*> Document::getObjectsOfType(const Base::Type& typeId) const
01639 {
01640 std::vector<DocumentObject*> Objects;
01641 for (std::vector<DocumentObject*>::const_iterator it = d->objectArray.begin(); it != d->objectArray.end(); ++it) {
01642 if ((*it)->getTypeId().isDerivedFrom(typeId))
01643 Objects.push_back(*it);
01644 }
01645 return Objects;
01646 }
01647
01648 int Document::countObjectsOfType(const Base::Type& typeId) const
01649 {
01650 int ct=0;
01651 for (std::map<std::string,DocumentObject*>::const_iterator it = d->objectMap.begin(); it != d->objectMap.end(); ++it) {
01652 if (it->second->getTypeId().isDerivedFrom(typeId))
01653 ct++;
01654 }
01655
01656 return ct;
01657 }
01658
01659 PyObject * Document::getPyObject(void)
01660 {
01661 return Py::new_reference_to(DocumentPythonObject);
01662 }