diff --git a/src/App/VRMLObject.cpp b/src/App/VRMLObject.cpp
index b4f1edae0..8e061d989 100644
--- a/src/App/VRMLObject.cpp
+++ b/src/App/VRMLObject.cpp
@@ -27,7 +27,12 @@
#endif
#include "VRMLObject.h"
+#include "Document.h"
#include "DocumentObjectPy.h"
+#include
+#include
+#include
+#include
using namespace App;
@@ -37,6 +42,8 @@ PROPERTY_SOURCE(App::VRMLObject, App::GeoFeature)
VRMLObject::VRMLObject()
{
ADD_PROPERTY_TYPE(VrmlFile,(0),"",Prop_None,"Included file with the VRML definition");
+ ADD_PROPERTY_TYPE(Urls,(""),"",static_cast(Prop_ReadOnly|Prop_Output),"Included file with the VRML definition");
+ Urls.setSize(0);
}
VRMLObject::~VRMLObject()
@@ -56,3 +63,92 @@ PyObject *VRMLObject::getPyObject()
}
return Py::new_reference_to(PythonObject);
}
+
+void VRMLObject::Save (Base::Writer &writer) const
+{
+ App::GeoFeature::Save(writer);
+
+ // if the VRML file has some inline files then store them inside the project file
+ if (Urls.getSize() > 0) {
+ const std::vector& urls = Urls.getValues();
+ writer.incInd();
+ writer.Stream() << writer.ind() << "" << std::endl;
+ writer.incInd();
+ std::string intname = this->getNameInDocument();
+ for (std::vector::const_iterator it = urls.begin(); it != urls.end(); ++it) {
+ Base::FileInfo fi(*it);
+ // make sure to put the VRML files into a sub-directory
+ std::string output = intname + "/" + fi.fileName();
+ output = writer.addFile(output.c_str(), this);
+ writer.Stream() << writer.ind() << "" << std::endl;
+ }
+ writer.decInd();
+ writer.Stream() << writer.ind() << "" << std::endl;
+ writer.decInd();
+ }
+
+ this->index = 0;
+}
+
+void VRMLObject::Restore(Base::XMLReader &reader)
+{
+ App::GeoFeature::Restore(reader);
+
+ // are there inline files
+ if (Urls.getSize() > 0) {
+ reader.readElement("UrlList");
+ int count = reader.getAttributeAsInteger("count");
+ for(int i = 0; i < count; i++) {
+ reader.readElement("Url");
+ std::string value = reader.getAttribute("value");
+ reader.addFile(value.c_str(), this);
+ }
+
+ reader.readEndElement("UrlList");
+ }
+
+ this->index = 0;
+}
+
+void VRMLObject::SaveDocFile (Base::Writer &writer) const
+{
+ // store the inline files of the VRML file
+ if (this->index < Urls.getSize()) {
+ std::string url = Urls[this->index];
+ this->index++;
+
+ Base::FileInfo fi(url);
+ Base::ifstream file(fi, std::ios::in | std::ios::binary);
+ if (file) {
+ writer.Stream() << file.rdbuf();
+ }
+ }
+}
+
+void VRMLObject::RestoreDocFile(Base::Reader &reader)
+{
+ if (this->index < Urls.getSize()) {
+ std::string path = getDocument()->TransientDir.getValue();
+ std::string url = Urls[this->index];
+ std::string intname = this->getNameInDocument();
+
+ Base::FileInfo fi(url);
+ std::string subdir = path + "/" + intname;
+ Base::FileInfo(subdir).createDirectory();
+ url = subdir + "/" + fi.fileName();
+ fi.setFile(url);
+ Urls.set1Value(this->index, url);
+ this->index++;
+
+ Base::ofstream file(fi, std::ios::out | std::ios::binary);
+ if (file) {
+ reader >> file.rdbuf();
+ file.close();
+ }
+
+ // after restoring all inline files reload the VRML file
+ if (this->index == Urls.getSize()) {
+ VrmlFile.touch();
+ }
+ }
+}
diff --git a/src/App/VRMLObject.h b/src/App/VRMLObject.h
index 311c36e97..e89707b61 100644
--- a/src/App/VRMLObject.h
+++ b/src/App/VRMLObject.h
@@ -49,9 +49,16 @@ public:
}
virtual short mustExecute(void) const;
virtual PyObject *getPyObject(void);
+ virtual void Save (Base::Writer &writer) const;
+ virtual void Restore(Base::XMLReader &reader);
+ virtual void SaveDocFile (Base::Writer &writer) const;
+ virtual void RestoreDocFile(Base::Reader &reader);
PropertyFileIncluded VrmlFile;
+ PropertyStringList Urls;
+private:
+ mutable int index;
};
} //namespace App
diff --git a/src/Gui/ViewProviderVRMLObject.cpp b/src/Gui/ViewProviderVRMLObject.cpp
index 3f5b9f5db..9fe664a58 100644
--- a/src/Gui/ViewProviderVRMLObject.cpp
+++ b/src/Gui/ViewProviderVRMLObject.cpp
@@ -26,12 +26,24 @@
#ifndef _PreComp_
# include
# include
+# include
+# include
# include
# include
# include
# include
#endif
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
#include "ViewProviderVRMLObject.h"
#include "SoFCSelection.h"
#include
@@ -81,6 +93,116 @@ std::vector ViewProviderVRMLObject::getDisplayModes(void) const
return StrList;
}
+template
+void ViewProviderVRMLObject::getResourceFile(SoNode* node, std::list& resources)
+{
+ SoSearchAction sa;
+ sa.setType(T::getClassTypeId());
+ sa.setInterest(SoSearchAction::ALL);
+ sa.setSearchingAll(true);
+ sa.apply(node);
+ const SoPathList & pathlist = sa.getPaths();
+ for (int i = 0; i < pathlist.getLength(); i++ ) {
+ SoFullPath * path = static_cast(pathlist[i]);
+ if (path->getTail()->isOfType(T::getClassTypeId())) {
+ T * tex = static_cast(path->getTail());
+ for (int j = 0; j < tex->url.getNum(); j++) {
+ this->addResource(tex->url[j], resources);
+ }
+ }
+ }
+}
+
+// Special handling for SoVRMLBackground
+template<>
+void ViewProviderVRMLObject::getResourceFile(SoNode* node, std::list& resources)
+{
+ SoSearchAction sa;
+ sa.setType(SoVRMLBackground::getClassTypeId());
+ sa.setInterest(SoSearchAction::ALL);
+ sa.setSearchingAll(true);
+ sa.apply(node);
+ const SoPathList & pathlist = sa.getPaths();
+ for (int i = 0; i < pathlist.getLength(); i++ ) {
+ SoFullPath * path = static_cast(pathlist[i]);
+ if (path->getTail()->isOfType(SoVRMLBackground::getClassTypeId())) {
+ SoVRMLBackground * vrml = static_cast(path->getTail());
+ // backUrl
+ for (int j = 0; j < vrml->backUrl.getNum(); j++) {
+ addResource(vrml->backUrl[j], resources);
+ }
+ // bottomUrl
+ for (int j = 0; j < vrml->bottomUrl.getNum(); j++) {
+ addResource(vrml->bottomUrl[j], resources);
+ }
+ // frontUrl
+ for (int j = 0; j < vrml->frontUrl.getNum(); j++) {
+ addResource(vrml->frontUrl[j], resources);
+ }
+ // leftUrl
+ for (int j = 0; j < vrml->leftUrl.getNum(); j++) {
+ addResource(vrml->leftUrl[j], resources);
+ }
+ // rightUrl
+ for (int j = 0; j < vrml->rightUrl.getNum(); j++) {
+ addResource(vrml->rightUrl[j], resources);
+ }
+ // topUrl
+ for (int j = 0; j < vrml->topUrl.getNum(); j++) {
+ addResource(vrml->topUrl[j], resources);
+ }
+ }
+ }
+}
+
+void ViewProviderVRMLObject::addResource(const SbString& url, std::list& resources)
+{
+ SbString found = SoInput::searchForFile(url, SoInput::getDirectories(), SbStringList());
+ Base::FileInfo fi(found.getString());
+ if (fi.exists()) {
+ // add the resource file if not yet listed
+ if (std::find(resources.begin(), resources.end(), found.getString()) == resources.end()) {
+ resources.push_back(found.getString());
+ }
+ }
+}
+
+void ViewProviderVRMLObject::getLocalResources(SoNode* node, std::list& resources)
+{
+ // search for SoVRMLInline files
+ SoSearchAction sa;
+ sa.setType(SoVRMLInline::getClassTypeId());
+ sa.setInterest(SoSearchAction::ALL);
+ sa.setSearchingAll(true);
+ sa.apply(node);
+
+ const SoPathList & pathlist = sa.getPaths();
+ for (int i = 0; i < pathlist.getLength(); i++ ) {
+ SoPath * path = pathlist[i];
+ SoVRMLInline * vrml = static_cast(path->getTail());
+ const SbString& url = vrml->getFullURLName();
+ if (url.getLength() > 0) {
+ // add the resource file if not yet listed
+ if (std::find(resources.begin(), resources.end(), url.getString()) == resources.end()) {
+ resources.push_back(url.getString());
+ }
+
+ // if the resource file could be loaded check if it references further resources
+ if (vrml->getChildData()) {
+ getLocalResources(vrml->getChildData(), resources);
+ }
+ }
+ }
+
+ // search for SoVRMLImageTexture, ... files
+ getResourceFile(node, resources);
+ getResourceFile(node, resources);
+ getResourceFile(node, resources);
+ getResourceFile(node, resources);
+ getResourceFile(node, resources);
+ getResourceFile(node, resources);
+}
+
void ViewProviderVRMLObject::updateData(const App::Property* prop)
{
App::VRMLObject* ivObj = static_cast(pcObject);
@@ -93,14 +215,31 @@ void ViewProviderVRMLObject::updateData(const App::Property* prop)
pcVRML->removeAllChildren();
if (!fn.isEmpty() && file.open(QFile::ReadOnly)) {
QFileInfo fi(fn);
- QByteArray path = fi.absolutePath().toUtf8();
+ QByteArray filepath = fi.absolutePath().toUtf8();
+ QByteArray subpath = filepath + "/" + ivObj->getNameInDocument();
+
// Add this to the search path in order to read inline files
- SoInput::addDirectoryFirst(path.constData());
+ SoInput::addDirectoryFirst(filepath.constData());
+ SoInput::addDirectoryFirst(subpath.constData());
+
+ // Read in the file
QByteArray buffer = file.readAll();
in.setBuffer((void *)buffer.constData(), buffer.length());
SoSeparator * node = SoDB::readAll(&in);
- if (node) pcVRML->addChild(node);
- SoInput::removeDirectory(path.constData());
+
+ if (node) {
+ pcVRML->addChild(node);
+
+ std::list urls;
+ getLocalResources(node, urls);
+ if (!urls.empty() && ivObj->Urls.getSize() == 0) {
+ std::vector res;
+ res.insert(res.end(), urls.begin(), urls.end());
+ ivObj->Urls.setValues(res);
+ }
+ }
+ SoInput::removeDirectory(filepath.constData());
+ SoInput::removeDirectory(subpath.constData());
}
}
else if (prop->isDerivedFrom(App::PropertyPlacement::getClassTypeId()) &&
diff --git a/src/Gui/ViewProviderVRMLObject.h b/src/Gui/ViewProviderVRMLObject.h
index 81022ef75..39a024491 100644
--- a/src/Gui/ViewProviderVRMLObject.h
+++ b/src/Gui/ViewProviderVRMLObject.h
@@ -26,6 +26,7 @@
#include "ViewProviderDocumentObject.h"
+class SbString;
namespace Gui
{
@@ -46,6 +47,9 @@ public:
void setDisplayMode(const char* ModeName);
std::vector getDisplayModes() const;
void updateData(const App::Property*);
+ void getLocalResources(SoNode*, std::list&);
+ void addResource(const SbString&, std::list&);
+ template void getResourceFile(SoNode*, std::list&);
protected:
SoFCSelection * pcVRML;