Skip to content
Permalink
Browse files

fixes 0003373: 'Save a copy' of a document with a spreadsheet mark th…

…e document as touched
  • Loading branch information
wwmayer committed Sep 26, 2018
1 parent ff0cacc commit dd492d74848a1583b8014d8893d037b93140c798
Showing with 96 additions and 98 deletions.
  1. +94 −97 src/App/Document.cpp
  2. +2 −1 src/App/Document.h
@@ -1604,19 +1604,10 @@ bool Document::saveAs(const char* file)
return save();
}

bool Document::saveCopy(const char* file)
bool Document::saveCopy(const char* file) const
{
std::string originalFileName = this->FileName.getStrValue();
std::string originalLabel = this->Label.getStrValue();
Base::FileInfo fi(file);
if (this->FileName.getStrValue() != file) {
this->FileName.setValue(file);
this->Label.setValue(fi.fileNamePure());
this->Uid.touch(); // this forces a rename of the transient directory
bool result = save();
this->FileName.setValue(originalFileName);
this->Label.setValue(originalLabel);
this->Uid.touch();
bool result = saveToFile(file);
return result;
}
return false;
@@ -1625,13 +1616,9 @@ bool Document::saveCopy(const char* file)
// Save the document under the name it has been opened
bool Document::save (void)
{
auto hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document");
int compression = hGrp->GetInt("CompressionLevel",3);
compression = Base::clamp<int>(compression, Z_NO_COMPRESSION, Z_BEST_COMPRESSION);

if (*(FileName.getValue()) != '\0') {
// Save the name of the tip object in order to handle in Restore()
if(Tip.getValue()) {
if (Tip.getValue()) {
TipName.setValue(Tip.getValue()->getNameInDocument());
}

@@ -1645,103 +1632,113 @@ bool Document::save (void)
("User parameter:BaseApp/Preferences/Document")->GetASCII("prefAuthor","");
LastModifiedBy.setValue(Author.c_str());
}
// make a tmp. file where to save the project data first and then rename to
// the actual file name. This may be useful if overwriting an existing file
// fails so that the data of the work up to now isn't lost.
std::string uuid = Base::Uuid::createUuid();
std::string fn = FileName.getValue();
fn += "."; fn += uuid;
Base::FileInfo tmp(fn);

// open extra scope to close ZipWriter properly
{
Base::ofstream file(tmp, std::ios::out | std::ios::binary);
Base::ZipWriter writer(file);

writer.setComment("FreeCAD Document");
writer.setLevel(compression);
writer.putNextEntry("Document.xml");

if (hGrp->GetBool("SaveBinaryBrep", false))
writer.setMode("BinaryBrep");

Document::Save(writer);

// Special handling for Gui document.
signalSaveDocument(writer);
return saveToFile(FileName.getValue());
}

// write additional files
writer.writeFiles();
return false;
}

if (writer.hasErrors()) {
throw Base::FileException("Failed to write all data to file", tmp);
}
bool Document::saveToFile(const char* filename) const
{
auto hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Document");
int compression = hGrp->GetInt("CompressionLevel",3);
compression = Base::clamp<int>(compression, Z_NO_COMPRESSION, Z_BEST_COMPRESSION);

GetApplication().signalSaveDocument(*this);
}

// if saving the project data succeeded rename to the actual file name
Base::FileInfo fi(FileName.getValue());
if (fi.exists()) {
bool backup = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetBool("CreateBackupFiles",true);
int count_bak = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetInt("CountBackupFiles",1);
if (backup) {
int nSuff = 0;
std::string fn = fi.fileName();
Base::FileInfo di(fi.dirPath());
std::vector<Base::FileInfo> backup;
std::vector<Base::FileInfo> files = di.getDirectoryContent();
for (std::vector<Base::FileInfo>::iterator it = files.begin(); it != files.end(); ++it) {
std::string file = it->fileName();
if (file.substr(0,fn.length()) == fn) {
// starts with the same file name
std::string suf(file.substr(fn.length()));
if (suf.size() > 0) {
std::string::size_type nPos = suf.find_first_not_of("0123456789");
if (nPos==std::string::npos) {
// store all backup files
backup.push_back(*it);
nSuff = std::max<int>(nSuff, std::atol(suf.c_str()));
}
// make a tmp. file where to save the project data first and then rename to
// the actual file name. This may be useful if overwriting an existing file
// fails so that the data of the work up to now isn't lost.
std::string uuid = Base::Uuid::createUuid();
std::string fn = filename;
fn += "."; fn += uuid;
Base::FileInfo tmp(fn);

// open extra scope to close ZipWriter properly
{
Base::ofstream file(tmp, std::ios::out | std::ios::binary);
Base::ZipWriter writer(file);

writer.setComment("FreeCAD Document");
writer.setLevel(compression);
writer.putNextEntry("Document.xml");

if (hGrp->GetBool("SaveBinaryBrep", false))
writer.setMode("BinaryBrep");

Document::Save(writer);

// Special handling for Gui document.
signalSaveDocument(writer);

// write additional files
writer.writeFiles();

if (writer.hasErrors()) {
throw Base::FileException("Failed to write all data to file", tmp);
}

GetApplication().signalSaveDocument(*this);
}

// if saving the project data succeeded rename to the actual file name
Base::FileInfo fi(filename);
if (fi.exists()) {
bool backup = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetBool("CreateBackupFiles",true);
int count_bak = App::GetApplication().GetParameterGroupByPath
("User parameter:BaseApp/Preferences/Document")->GetInt("CountBackupFiles",1);
if (backup) {
int nSuff = 0;
std::string fn = fi.fileName();
Base::FileInfo di(fi.dirPath());
std::vector<Base::FileInfo> backup;
std::vector<Base::FileInfo> files = di.getDirectoryContent();
for (std::vector<Base::FileInfo>::iterator it = files.begin(); it != files.end(); ++it) {
std::string file = it->fileName();
if (file.substr(0,fn.length()) == fn) {
// starts with the same file name
std::string suf(file.substr(fn.length()));
if (suf.size() > 0) {
std::string::size_type nPos = suf.find_first_not_of("0123456789");
if (nPos==std::string::npos) {
// store all backup files
backup.push_back(*it);
nSuff = std::max<int>(nSuff, std::atol(suf.c_str()));
}
}
}
}

if (!backup.empty() && (int)backup.size() >= count_bak) {
// delete the oldest backup file we found
Base::FileInfo del = backup.front();
for (std::vector<Base::FileInfo>::iterator it = backup.begin(); it != backup.end(); ++it) {
if (it->lastModified() < del.lastModified())
del = *it;
}

del.deleteFile();
fn = del.filePath();
}
else {
// create a new backup file
std::stringstream str;
str << fi.filePath() << (nSuff + 1);
fn = str.str();
if (!backup.empty() && (int)backup.size() >= count_bak) {
// delete the oldest backup file we found
Base::FileInfo del = backup.front();
for (std::vector<Base::FileInfo>::iterator it = backup.begin(); it != backup.end(); ++it) {
if (it->lastModified() < del.lastModified())
del = *it;
}

if (fi.renameFile(fn.c_str()) == false)
Base::Console().Warning("Cannot rename project file to backup file\n");
del.deleteFile();
fn = del.filePath();
}
else {
fi.deleteFile();
// create a new backup file
std::stringstream str;
str << fi.filePath() << (nSuff + 1);
fn = str.str();
}
}
if (tmp.renameFile(FileName.getValue()) == false)
Base::Console().Warning("Cannot rename file from '%s' to '%s'\n",
fn.c_str(), FileName.getValue());

return true;
if (fi.renameFile(fn.c_str()) == false)
Base::Console().Warning("Cannot rename project file to backup file\n");
}
else {
fi.deleteFile();
}
}
if (tmp.renameFile(filename) == false)
Base::Console().Warning("Cannot rename file from '%s' to '%s'\n",
fn.c_str(), filename);

return false;
return true;
}

// Open the document
@@ -156,7 +156,7 @@ class AppExport Document : public App::PropertyContainer
/// Save the document to the file in Property Path
bool save (void);
bool saveAs(const char* file);
bool saveCopy(const char* file);
bool saveCopy(const char* file) const;
/// Restore the document from the file in Property Path
void restore (void);
void exportObjects(const std::vector<App::DocumentObject*>&, std::ostream&);
@@ -364,6 +364,7 @@ class AppExport Document : public App::PropertyContainer
void breakDependency(DocumentObject* pcObject, bool clear);
std::vector<App::DocumentObject*> readObjects(Base::XMLReader& reader);
void writeObjects(const std::vector<App::DocumentObject*>&, Base::Writer &writer) const;
bool saveToFile(const char* filename) const;

void onChanged(const Property* prop);
/// callback from the Document objects before property will be changed

0 comments on commit dd492d7

Please sign in to comment.
You can’t perform that action at this time.