diff --git a/src/App/CMakeLists.txt b/src/App/CMakeLists.txt index 238c89b2d..f95b73139 100644 --- a/src/App/CMakeLists.txt +++ b/src/App/CMakeLists.txt @@ -77,7 +77,8 @@ SET(Document_CPP_SRCS Plane.cpp Transactions.cpp VRMLObject.cpp - MaterialObject.cpp + MaterialObject.cpp + MergeDocuments.cpp ) SET(Document_HPP_SRCS @@ -99,7 +100,8 @@ SET(Document_HPP_SRCS Plane.h Transactions.h VRMLObject.h - MaterialObject.h + MaterialObject.h + MergeDocuments.h ) SET(Document_SRCS ${Document_CPP_SRCS} diff --git a/src/App/DocumentPy.xml b/src/App/DocumentPy.xml index 3a11e634d..4eb38bfc5 100644 --- a/src/App/DocumentPy.xml +++ b/src/App/DocumentPy.xml @@ -33,6 +33,11 @@ Restore the document from disk + + + Merges this document with another project file + + Export the dependencies of the objects as graph diff --git a/src/App/DocumentPyImp.cpp b/src/App/DocumentPyImp.cpp index 8167c5493..e377eaf70 100644 --- a/src/App/DocumentPyImp.cpp +++ b/src/App/DocumentPyImp.cpp @@ -31,6 +31,7 @@ #include #include "DocumentObject.h" #include "DocumentObjectPy.h" +#include "MergeDocuments.h" // inclusion of the generated files (generated By DocumentPy.xml) #include "DocumentPy.h" @@ -135,6 +136,22 @@ PyObject* DocumentPy::restore(PyObject * args) Py_Return; } +PyObject* DocumentPy::mergeProject(PyObject * args) +{ + char* filename; + if (!PyArg_ParseTuple(args, "s", &filename)) // convert args: Python->C + return NULL; // NULL triggers exception + + PY_TRY { + Base::FileInfo fi(filename); + Base::ifstream str(fi, std::ios::in | std::ios::binary); + App::Document* doc = getDocumentPtr(); + MergeDocuments md(doc); + md.importObjects(str); + Py_Return; + } PY_CATCH; +} + PyObject* DocumentPy::exportGraphviz(PyObject * args) { char* fn=0; diff --git a/src/App/MergeDocuments.cpp b/src/App/MergeDocuments.cpp new file mode 100644 index 000000000..3f5198b29 --- /dev/null +++ b/src/App/MergeDocuments.cpp @@ -0,0 +1,161 @@ +/*************************************************************************** + * Copyright (c) 2010 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 +# include +#endif +#include "MergeDocuments.h" +#include +#include +#include +#include +#include + +using namespace App; + +namespace App { + +class XMLMergeReader : public Base::XMLReader +{ +public: + XMLMergeReader(std::map& name, const char* FileName, std::istream& str) + : Base::XMLReader(FileName, str), nameMap(name) + {} + + void addName(const char* s1, const char* s2) + { + nameMap[s1] = s2; + } + const char* getName(const char* name) const + { + std::map::const_iterator it = nameMap.find(name); + if (it != nameMap.end()) + return it->second.c_str(); + else + return name; + } + bool doNameMapping() const + { + return true; + } +protected: + void startElement(const XMLCh* const uri, const XMLCh* const localname, + const XMLCh* const qname, + const XERCES_CPP_NAMESPACE_QUALIFIER Attributes& attrs) + { + Base::XMLReader::startElement(uri, localname, qname, attrs); + if (LocalName == "Property") + propertyStack.push(std::make_pair(AttrMap["name"],AttrMap["type"])); + + if (!propertyStack.empty()) { + // replace the stored object name with the real one + if (LocalName == "Link" || LocalName == "LinkSub" || (LocalName == "String" && propertyStack.top().first == "Label")) { + for (std::map::iterator it = AttrMap.begin(); it != AttrMap.end(); ++it) { + std::map::const_iterator jt = nameMap.find(it->second); + if (jt != nameMap.end()) + it->second = jt->second; + } + } + } + } + + void endElement(const XMLCh* const uri, const XMLCh *const localname, const XMLCh *const qname) + { + Base::XMLReader::endElement(uri, localname, qname); + if (LocalName == "Property") + propertyStack.pop(); + } + +private: + std::map& nameMap; + typedef std::pair PropertyTag; + std::stack propertyStack; +}; +} + +MergeDocuments::MergeDocuments(App::Document* doc) : appdoc(doc) +{ + connectExport = doc->signalExportObjects.connect + (boost::bind(&MergeDocuments::exportObject, this, _1, _2)); + connectImport = doc->signalImportObjects.connect + (boost::bind(&MergeDocuments::importObject, this, _1, _2)); +} + +MergeDocuments::~MergeDocuments() +{ + connectExport.disconnect(); + connectImport.disconnect(); +} + +unsigned int MergeDocuments::getMemSize (void) const +{ + return 0; +} + +std::vector +MergeDocuments::importObjects(std::istream& input) +{ + this->nameMap.clear(); + this->stream = new zipios::ZipInputStream(input); + XMLMergeReader reader(this->nameMap,"", *stream); + std::vector objs = appdoc->importObjects(reader); + + delete this->stream; + this->stream = 0; + + return objs; +} + +void MergeDocuments::importObject(const std::vector& o, Base::XMLReader & r) +{ + objects = o; + Restore(r); + r.readFiles(*this->stream); +} + +void MergeDocuments::exportObject(const std::vector& o, Base::Writer & w) +{ + objects = o; + Save(w); +} + +void MergeDocuments::Save (Base::Writer & w) const +{ + // Save view provider stuff +} + +void MergeDocuments::Restore(Base::XMLReader &r) +{ + // Restore view provider stuff +} + +void MergeDocuments::SaveDocFile (Base::Writer & w) const +{ + // Save view provider stuff +} + +void MergeDocuments::RestoreDocFile(Base::Reader & r) +{ + // Restore view provider stuff +} diff --git a/src/App/MergeDocuments.h b/src/App/MergeDocuments.h new file mode 100644 index 000000000..f11236b9d --- /dev/null +++ b/src/App/MergeDocuments.h @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (c) 2010 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 * + * * + ***************************************************************************/ + + +#ifndef APP_MERGEDOCUMENTS_H +#define APP_MERGEDOCUMENTS_H + +#include +#include + +namespace zipios { +class ZipInputStream; +} + +namespace App { +class Document; +class DocumentObject; +class AppExport MergeDocuments : public Base::Persistence +{ +public: + MergeDocuments(App::Document* doc); + ~MergeDocuments(); + unsigned int getMemSize (void) const; + std::vector importObjects(std::istream&); + void importObject(const std::vector& o, Base::XMLReader & r); + void exportObject(const std::vector& o, Base::Writer & w); + void Save (Base::Writer & w) const; + void Restore(Base::XMLReader &r); + void SaveDocFile (Base::Writer & w) const; + void RestoreDocFile(Base::Reader & r); + +private: + zipios::ZipInputStream* stream; + App::Document* appdoc; + std::vector objects; + std::map nameMap; + typedef boost::signals::connection Connection; + Connection connectExport; + Connection connectImport; +}; + +} // namespace App + +#endif // APP_MERGEDOCUMENTS_H diff --git a/src/Gui/Document.cpp b/src/Gui/Document.cpp index 015c79239..d448f3600 100644 --- a/src/Gui/Document.cpp +++ b/src/Gui/Document.cpp @@ -853,7 +853,8 @@ void Document::exportObjects(const std::vector& obj, Base: writer.Stream() << "" << std::endl; } -void Document::importObjects(const std::vector& obj, Base::Reader& reader) +void Document::importObjects(const std::vector& obj, Base::Reader& reader, + const std::map& nameMapping) { // We must create an XML parser to read from the input stream Base::XMLReader xmlReader("GuiDocument.xml", reader); @@ -874,15 +875,12 @@ void Document::importObjects(const std::vector& obj, Base: // thus we try to match by type. This should work because the order of // objects should not have changed xmlReader.readElement("ViewProvider"); - std::string type = xmlReader.getAttribute("type"); - ViewProvider* pObj = getViewProvider(*it); - while (pObj && type != pObj->getTypeId().getName()) { - if (it != obj.end()) { - ++it; - pObj = getViewProvider(*it); - } - } - if (pObj && type == pObj->getTypeId().getName()) + std::string name = xmlReader.getAttribute("name"); + std::map::const_iterator jt = nameMapping.find(name); + if (jt != nameMapping.end()) + name = jt->second; + Gui::ViewProvider* pObj = this->getViewProviderByName(name.c_str()); + if (pObj) pObj->Restore(xmlReader); xmlReader.readEndElement("ViewProvider"); if (it == obj.end()) @@ -892,6 +890,10 @@ void Document::importObjects(const std::vector& obj, Base: } xmlReader.readEndElement("Document"); + + // In the file GuiDocument.xml new data files might be added + if (!xmlReader.getFilenames().empty()) + xmlReader.readFiles(static_cast(reader.getStream())); } void Document::addRootObjectsToGroup(const std::vector& obj, App::DocumentObjectGroup* grp) diff --git a/src/Gui/Document.h b/src/Gui/Document.h index 38fbc772e..9005e9056 100644 --- a/src/Gui/Document.h +++ b/src/Gui/Document.h @@ -124,7 +124,8 @@ public: /// This method is used to restore large amounts of data from a binary file. virtual void RestoreDocFile(Base::Reader &reader); void exportObjects(const std::vector&, Base::Writer&); - void importObjects(const std::vector&, Base::Reader&); + void importObjects(const std::vector&, Base::Reader&, + const std::map& nameMapping); /// Add all root objects of the given array to a group void addRootObjectsToGroup(const std::vector&, App::DocumentObjectGroup*); //@} diff --git a/src/Gui/MergeDocuments.cpp b/src/Gui/MergeDocuments.cpp index 430843129..878113e4c 100644 --- a/src/Gui/MergeDocuments.cpp +++ b/src/Gui/MergeDocuments.cpp @@ -164,44 +164,7 @@ void MergeDocuments::SaveDocFile (Base::Writer & w) const document->exportObjects(objects, w); } -void MergeDocuments::RestoreDocFile(Base::Reader & reader) +void MergeDocuments::RestoreDocFile(Base::Reader & r) { - std::vector obj = objects; - // We must create an XML parser to read from the input stream - Base::XMLReader xmlReader("GuiDocument.xml", reader); - xmlReader.readElement("Document"); - long scheme = xmlReader.getAttributeAsInteger("SchemaVersion"); - - // At this stage all the document objects and their associated view providers exist. - // Now we must restore the properties of the view providers only. - // - // SchemeVersion "1" - if (scheme == 1) { - // read the viewproviders itself - xmlReader.readElement("ViewProviderData"); - int Cnt = xmlReader.getAttributeAsInteger("Count"); - std::vector::const_iterator it = obj.begin(); - for (int i=0;igetViewProviderByName(name.c_str()); - //Gui::ViewProvider* pObj = document->getViewProvider(*it); - if (pObj) - pObj->Restore(xmlReader); - xmlReader.readEndElement("ViewProvider"); - if (it == obj.end()) - break; - } - xmlReader.readEndElement("ViewProviderData"); - } - - xmlReader.readEndElement("Document"); - - // In the file GuiDocument.xml new data files might be added - if (!xmlReader.getFilenames().empty()) - xmlReader.readFiles(static_cast(reader.getStream())); + document->importObjects(objects, r, nameMap); }