diff --git a/src/Base/Writer.cpp b/src/Base/Writer.cpp index 2b3645f0e..9d0d048c6 100644 --- a/src/Base/Writer.cpp +++ b/src/Base/Writer.cpp @@ -202,6 +202,8 @@ void Writer::decInd(void) indBuf[indent] = '\0'; } +// ---------------------------------------------------------------------------- + ZipWriter::ZipWriter(const char* FileName) : ZipStream(FileName) { @@ -245,3 +247,53 @@ ZipWriter::~ZipWriter() { ZipStream.close(); } + +// ---------------------------------------------------------------------------- + +FileWriter::FileWriter(const char* DirName) : DirName(DirName) +{ +} + +FileWriter::~FileWriter() +{ +} + +void FileWriter::putNextEntry(const char* file) +{ + std::string fileName = DirName + "/" + file; + this->FileStream.open(fileName.c_str(), std::ios::out); +} + +bool FileWriter::shouldWrite(const Base::Persistence *) const +{ + return true; +} + +void FileWriter::writeFiles(void) +{ + // use a while loop because it is possible that while + // processing the files new ones can be added + size_t index = 0; + this->FileStream.close(); + while (index < FileList.size()) { + FileEntry entry = FileList.begin()[index]; + + if (shouldWrite(entry.Object)) { + std::string filePath = entry.FileName; + std::string::size_type pos = 0; + while ((pos = filePath.find("/", pos)) != std::string::npos) { + std::string dirName = DirName + "/" + filePath.substr(0, pos); + pos++; + Base::FileInfo fi(dirName); + fi.createDirectory(); + } + + std::string fileName = DirName + "/" + entry.FileName; + this->FileStream.open(fileName.c_str(), std::ios::out | std::ios::binary); + entry.Object->SaveDocFile(*this); + this->FileStream.close(); + } + + index++; + } +} diff --git a/src/Base/Writer.h b/src/Base/Writer.h index af795a43a..fa867d06f 100644 --- a/src/Base/Writer.h +++ b/src/Base/Writer.h @@ -130,11 +130,10 @@ protected: */ class BaseExport ZipWriter : public Writer { - public: ZipWriter(const char* FileName); ZipWriter(std::ostream&); - ~ZipWriter(); + virtual ~ZipWriter(); virtual void writeFiles(void); @@ -159,13 +158,40 @@ class BaseExport StringWriter : public Writer public: virtual std::ostream &Stream(void){return StrStream;} - std::string getString(void){return StrStream.str();} - virtual void writeFiles(void){assert(0);} + std::string getString(void) const {return StrStream.str();} + virtual void writeFiles(void){} private: std::stringstream StrStream; }; +/*! The FileWriter class + This class writes out the data into files into a given directory name. + \see Base::Persistence + \author Werner Mayer + */ +class BaseExport FileWriter : public Writer +{ +public: + FileWriter(const char* DirName); + virtual ~FileWriter(); + + void putNextEntry(const char* file); + virtual void writeFiles(void); + + virtual std::ostream &Stream(void){return FileStream;} + /*! + This method can be re-implemented in sub-classes to avoid + to write out certain objects. The default implementation + always returns true. + */ + virtual bool shouldWrite(const Base::Persistence *Object) const; + +private: + std::string DirName; + std::ofstream FileStream; +}; + } //namespace Base diff --git a/src/Gui/AutoSaver.cpp b/src/Gui/AutoSaver.cpp index a9023f67a..c645a3acb 100644 --- a/src/Gui/AutoSaver.cpp +++ b/src/Gui/AutoSaver.cpp @@ -28,6 +28,7 @@ # include # include # include +# include #endif #include "AutoSaver.h" @@ -38,9 +39,11 @@ #include #include +#include "Document.h" #include "WaitCursor.h" #include "Widgets.h" #include "MainWindow.h" +#include "ViewProvider.h" using namespace Gui; @@ -69,11 +72,11 @@ void AutoSaver::setTimeout(int ms) timeout = Base::clamp(ms, 0, 3600000); // between 0 and 60 min // go through the attached documents and apply the new timeout - for (std::map::iterator it = timerMap.begin(); it != timerMap.end(); ++it) { - if (it->second > 0) - killTimer(it->second); + for (std::map::iterator it = saverMap.begin(); it != saverMap.end(); ++it) { + if (it->second->timerId > 0) + killTimer(it->second->timerId); int id = timeout > 0 ? startTimer(timeout) : 0; - it->second = id; + it->second->timerId = id; } } @@ -81,21 +84,24 @@ void AutoSaver::slotCreateDocument(const App::Document& Doc) { std::string name = Doc.getName(); int id = timeout > 0 ? startTimer(timeout) : 0; - timerMap[name] = id; + AutoSaveProperty* as = new AutoSaveProperty(&Doc); + as->timerId = id; + saverMap.insert(std::make_pair(name, as)); } void AutoSaver::slotDeleteDocument(const App::Document& Doc) { std::string name = Doc.getName(); - std::map::iterator it = timerMap.find(name); - if (it != timerMap.end()) { - if (it->second > 0) - killTimer(it->second); - timerMap.erase(it); + std::map::iterator it = saverMap.find(name); + if (it != saverMap.end()) { + if (it->second->timerId > 0) + killTimer(it->second->timerId); + delete it->second; + saverMap.erase(it); } } -void AutoSaver::saveDocument(const std::string& name) +void AutoSaver::saveDocument(const std::string& name, const std::set& data) { Gui::WaitCursor wc; App::Document* doc = App::GetApplication().getDocument(name.c_str()); @@ -168,10 +174,11 @@ void AutoSaver::saveDocument(const std::string& name) void AutoSaver::timerEvent(QTimerEvent * event) { int id = event->timerId(); - for (std::map::iterator it = timerMap.begin(); it != timerMap.end(); ++it) { - if (it->second == id) { + for (std::map::iterator it = saverMap.begin(); it != saverMap.end(); ++it) { + if (it->second->timerId == id) { try { - saveDocument(it->first); + saveDocument(it->first, it->second->objects); + it->second->objects.clear(); break; } catch (...) { @@ -181,4 +188,65 @@ void AutoSaver::timerEvent(QTimerEvent * event) } } +// ---------------------------------------------------------------------------- + +AutoSaveProperty::AutoSaveProperty(const App::Document* doc) : timerId(-1) +{ + document = const_cast(doc)->signalChangedObject.connect + (boost::bind(&AutoSaveProperty::slotChangePropertyData, this, _2)); +} + +AutoSaveProperty::~AutoSaveProperty() +{ + document.disconnect(); +} + +void AutoSaveProperty::slotChangePropertyData(const App::Property& prop) +{ + std::stringstream str; + str << static_cast(&prop) << std::ends; + std::string address = str.str(); + this->objects.insert(address); +} + +// ---------------------------------------------------------------------------- + +RecoveryWriter::RecoveryWriter(const char* DirName) + : Base::FileWriter(DirName) +{ +} + +RecoveryWriter::~RecoveryWriter() +{ +} + +void RecoveryWriter::setModifiedData(const std::set& m) +{ + data = m; +} + +bool RecoveryWriter::shouldWrite(const Base::Persistence *object) const +{ + // Property files of a view provider can always be written because + // these are rather small files. + if (object->isDerivedFrom(App::Property::getClassTypeId())) { + const App::Property* prop = static_cast(object); + const App::PropertyContainer* parent = prop->getContainer(); + if (parent && parent->isDerivedFrom(Gui::ViewProvider::getClassTypeId())) + return true; + } + else if (object->isDerivedFrom(Gui::Document::getClassTypeId())) { + return true; + } + + // These are the addresses of touched properties of a document object. + std::stringstream str; + str << static_cast(object) << std::ends; + std::string address = str.str(); + + std::set::const_iterator it = data.find(address); + return (it != data.end()); +} + + #include "moc_AutoSaver.cpp" diff --git a/src/Gui/AutoSaver.h b/src/Gui/AutoSaver.h index 4f723354f..b97f8da70 100644 --- a/src/Gui/AutoSaver.h +++ b/src/Gui/AutoSaver.h @@ -25,14 +25,33 @@ #define GUI_AUTOSAVER_H #include +#include #include +#include #include +#include namespace App { class Document; +class Property; } namespace Gui { +class ViewProvider; + +class AutoSaveProperty +{ +public: + AutoSaveProperty(const App::Document* doc); + ~AutoSaveProperty(); + int timerId; + std::set objects; + +private: + void slotChangePropertyData(const App::Property&); + typedef boost::BOOST_SIGNALS_NAMESPACE::connection Connection; + Connection document; +}; /*! The class AutoSaver is used to automatically save a document to a temporary file. @@ -58,11 +77,29 @@ protected: void slotCreateDocument(const App::Document& Doc); void slotDeleteDocument(const App::Document& Doc); void timerEvent(QTimerEvent * event); - void saveDocument(const std::string&); + void saveDocument(const std::string&, const std::set&); private: int timeout; /*!< Timeout in milliseconds */ - std::map timerMap; + std::map saverMap; +}; + +class RecoveryWriter : public Base::FileWriter +{ +public: + RecoveryWriter(const char* DirName); + virtual ~RecoveryWriter(); + void setModifiedData(const std::set &); + + /*! + This method can be re-implemented in sub-classes to avoid + to write out certain objects. The default implementation + always returns true. + */ + virtual bool shouldWrite(const Base::Persistence *) const; + +private: + std::set data; }; } //namespace Gui