MergeDocuments.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) 2010 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 #include "PreCompiled.h"
00024 #ifndef _PreComp_
00025 # include <stack>
00026 # include <boost/bind.hpp>
00027 #endif
00028 #include "MergeDocuments.h"
00029 #include <Base/Console.h>
00030 #include <Base/Reader.h>
00031 #include <Base/Writer.h>
00032 #include <App/Document.h>
00033 #include <App/DocumentObject.h>
00034 #include <Gui/Application.h>
00035 #include <Gui/Document.h>
00036 #include <Gui/ViewProvider.h>
00037 
00038 using namespace Gui;
00039 
00040 namespace Gui {
00041 
00042 class XMLMergeReader : public Base::XMLReader
00043 {
00044 public:
00045     XMLMergeReader(const std::map<std::string, std::string>& name, const char* FileName, std::istream& str)
00046       : Base::XMLReader(FileName, str), nameMap(name)
00047     {}
00048 
00049 protected:
00050     void startElement(const XMLCh* const uri, const XMLCh* const localname,
00051                       const XMLCh* const qname,
00052                       const XERCES_CPP_NAMESPACE_QUALIFIER Attributes& attrs)
00053     {
00054         Base::XMLReader::startElement(uri, localname, qname, attrs);
00055         if (LocalName == "Property")
00056             propertyStack.push(std::make_pair(AttrMap["name"],AttrMap["type"]));
00057 
00058         if (!propertyStack.empty()) {
00059             // replace the stored object name with the real one
00060             if (LocalName == "Link" || (LocalName == "String" && propertyStack.top().first == "Label")) {
00061                 for (std::map<std::string, std::string>::iterator it = AttrMap.begin(); it != AttrMap.end(); ++it) {
00062                     std::map<std::string, std::string>::const_iterator jt = nameMap.find(it->second);
00063                     if (jt != nameMap.end())
00064                         it->second = jt->second;
00065                 }
00066             }
00067         }
00068     }
00069 
00070     void endElement(const XMLCh* const uri, const XMLCh *const localname, const XMLCh *const qname)
00071     {
00072         Base::XMLReader::endElement(uri, localname, qname);
00073         if (LocalName == "Property")
00074             propertyStack.pop();
00075     }
00076 
00077 private:
00078     const std::map<std::string, std::string>& nameMap;
00079     typedef std::pair<std::string, std::string> PropertyTag;
00080     std::stack<PropertyTag> propertyStack;
00081 };
00082 }
00083 
00084 MergeDocuments::MergeDocuments(App::Document* doc) : appdoc(doc)
00085 {
00086     connectExport = doc->signalExportObjects.connect
00087         (boost::bind(&MergeDocuments::exportObject, this, _1, _2));
00088     connectImport = doc->signalImportObjects.connect
00089         (boost::bind(&MergeDocuments::importObject, this, _1, _2));
00090     document = Gui::Application::Instance->getDocument(doc);
00091 }
00092 
00093 MergeDocuments::~MergeDocuments()
00094 {
00095     connectExport.disconnect();
00096     connectImport.disconnect();
00097 }
00098 
00099 unsigned int MergeDocuments::getMemSize (void) const
00100 {
00101     return 0;
00102 }
00103 
00104 std::vector<App::DocumentObject*>
00105 MergeDocuments::importObjects(std::istream& input)
00106 {
00107     //std::map<std::string, std::string> nameMap;
00108     std::vector<App::DocumentObject*> objs;
00109     zipios::ZipInputStream zipstream(input);
00110     XMLMergeReader reader(nameMap,"<memory>", zipstream);
00111 
00112     int i,Cnt;
00113     reader.readElement("Document");
00114     long scheme = reader.getAttributeAsInteger("SchemaVersion");
00115     reader.DocumentSchema = scheme;
00116 
00117     // read the object types
00118     nameMap.clear();
00119     reader.readElement("Objects");
00120     Cnt = reader.getAttributeAsInteger("Count");
00121     for (i=0 ;i<Cnt ;i++) {
00122         reader.readElement("Object");
00123         std::string type = reader.getAttribute("type");
00124         std::string name = reader.getAttribute("name");
00125         std::string docn = name;
00126 
00127         // remove number from end to avoid lengthy names
00128         size_t lastpos = docn.length()-1;
00129         while (docn[lastpos] >= 48 && docn[lastpos] <= 57)
00130             lastpos--;
00131         docn = docn.substr(0, lastpos+1);
00132 
00133         try {
00134             App::DocumentObject* o = appdoc->addObject(type.c_str(),docn.c_str());
00135             objs.push_back(o);
00136             // use this name for the later access because an object with
00137             // the given name may already exist
00138             nameMap[name] = o->getNameInDocument();
00139         }
00140         catch (Base::Exception&) {
00141             Base::Console().Message("Cannot create object '%s'\n", name.c_str());
00142         }
00143     }
00144     reader.readEndElement("Objects");
00145 
00146     // read the features itself
00147     reader.readElement("ObjectData");
00148     Cnt = reader.getAttributeAsInteger("Count");
00149     for (i=0 ;i<Cnt ;i++) {
00150         reader.readElement("Object");
00151         std::string name = nameMap[reader.getAttribute("name")];
00152         App::DocumentObject* pObj = appdoc->getObject(name.c_str());
00153         if (pObj) { // check if this feature has been registered
00154 //            pObj->StatusBits.set(4);
00155             pObj->Restore(reader);
00156 //            pObj->StatusBits.reset(4);
00157         }
00158         reader.readEndElement("Object");
00159     }
00160     reader.readEndElement("ObjectData");
00161 
00162     reader.readEndElement("Document");
00163     appdoc->signalImportObjects(objs, reader);
00164     reader.readFiles(zipstream);
00165     // reset all touched
00166     for (std::vector<App::DocumentObject*>::iterator it= objs.begin();it!=objs.end();++it)
00167         (*it)->purgeTouched();
00168     return objs;
00169 }
00170 
00171 void MergeDocuments::importObject(const std::vector<App::DocumentObject*>& o, Base::XMLReader & r)
00172 {
00173     objects = o;
00174     for (std::vector<App::DocumentObject*>::iterator it = objects.begin(); it != objects.end(); ++it) {
00175         Gui::ViewProvider* vp = document->getViewProvider(*it);
00176         if (vp) vp->hide();
00177     }
00178     Restore(r);
00179 }
00180 
00181 void MergeDocuments::exportObject(const std::vector<App::DocumentObject*>& o, Base::Writer & w)
00182 {
00183     objects = o;
00184     Save(w);
00185 }
00186 
00187 void MergeDocuments::Save (Base::Writer & w) const
00188 {
00189     w.addFile("GuiDocument.xml", this);
00190 }
00191 
00192 void MergeDocuments::Restore(Base::XMLReader &r)
00193 {
00194     r.addFile("GuiDocument.xml", this);
00195 }
00196 
00197 void MergeDocuments::SaveDocFile (Base::Writer & w) const
00198 {
00199     document->exportObjects(objects, w);
00200 }
00201 
00202 void MergeDocuments::RestoreDocFile(Base::Reader & reader)
00203 {
00204     std::vector<App::DocumentObject*> obj = objects;
00205     // We must create an XML parser to read from the input stream
00206     Base::XMLReader xmlReader("GuiDocument.xml", reader);
00207     xmlReader.readElement("Document");
00208     long scheme = xmlReader.getAttributeAsInteger("SchemaVersion");
00209 
00210     // At this stage all the document objects and their associated view providers exist.
00211     // Now we must restore the properties of the view providers only.
00212     //
00213     // SchemeVersion "1"
00214     if (scheme == 1) {
00215         // read the viewproviders itself
00216         xmlReader.readElement("ViewProviderData");
00217         int Cnt = xmlReader.getAttributeAsInteger("Count");
00218         std::vector<App::DocumentObject*>::const_iterator it = obj.begin();
00219         for (int i=0;i<Cnt&&it!=obj.end();++i,++it) {
00220             // The stored name usually doesn't match with the current name anymore
00221             // thus we try to match by type. This should work because the order of
00222             // objects should not have changed
00223             xmlReader.readElement("ViewProvider");
00224             std::string name = xmlReader.getAttribute("name");
00225             name = nameMap[name];
00226             Gui::ViewProvider* pObj = document->getViewProviderByName(name.c_str());
00227             //Gui::ViewProvider* pObj = document->getViewProvider(*it);
00228             if (pObj)
00229                 pObj->Restore(xmlReader);
00230             xmlReader.readEndElement("ViewProvider");
00231             if (it == obj.end())
00232                 break;
00233         }
00234         xmlReader.readEndElement("ViewProviderData");
00235     }
00236 
00237     xmlReader.readEndElement("Document");
00238 }

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