+ implement FileWriter class based on files and a specialized sub-class for recovery purposes

This commit is contained in:
wmayer 2015-09-17 21:37:47 +02:00
parent 300e176eb3
commit bb05d17596
4 changed files with 203 additions and 20 deletions

View File

@ -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++;
}
}

View File

@ -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

View File

@ -28,6 +28,7 @@
# include <QFile>
# include <QTextStream>
# include <boost/bind.hpp>
# include <sstream>
#endif
#include "AutoSaver.h"
@ -38,9 +39,11 @@
#include <App/Application.h>
#include <App/Document.h>
#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<int>(ms, 0, 3600000); // between 0 and 60 min
// go through the attached documents and apply the new timeout
for (std::map<std::string, int>::iterator it = timerMap.begin(); it != timerMap.end(); ++it) {
if (it->second > 0)
killTimer(it->second);
for (std::map<std::string, AutoSaveProperty*>::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<std::string, int>::iterator it = timerMap.find(name);
if (it != timerMap.end()) {
if (it->second > 0)
killTimer(it->second);
timerMap.erase(it);
std::map<std::string, AutoSaveProperty*>::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<std::string>& 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<std::string, int>::iterator it = timerMap.begin(); it != timerMap.end(); ++it) {
if (it->second == id) {
for (std::map<std::string, AutoSaveProperty*>::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<App::Document*>(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<const void *>(&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<std::string>& 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<const App::Property*>(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<const void *>(object) << std::ends;
std::string address = str.str();
std::set<std::string>::const_iterator it = data.find(address);
return (it != data.end());
}
#include "moc_AutoSaver.cpp"

View File

@ -25,14 +25,33 @@
#define GUI_AUTOSAVER_H
#include <QObject>
#include <Base/Writer.h>
#include <map>
#include <set>
#include <string>
#include <boost/signals.hpp>
namespace App {
class Document;
class Property;
}
namespace Gui {
class ViewProvider;
class AutoSaveProperty
{
public:
AutoSaveProperty(const App::Document* doc);
~AutoSaveProperty();
int timerId;
std::set<std::string> 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<std::string>&);
private:
int timeout; /*!< Timeout in milliseconds */
std::map<std::string, int> timerMap;
std::map<std::string, AutoSaveProperty*> saverMap;
};
class RecoveryWriter : public Base::FileWriter
{
public:
RecoveryWriter(const char* DirName);
virtual ~RecoveryWriter();
void setModifiedData(const std::set<std::string> &);
/*!
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<std::string> data;
};
} //namespace Gui