diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 14cc2ed69b..5897da0b8f 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -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(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,105 +1632,115 @@ 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); - - // 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.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 backup; - std::vector files = di.getDirectoryContent(); - for (std::vector::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(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::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 (fi.renameFile(fn.c_str()) == false) - Base::Console().Warning("Cannot rename project file to backup file\n"); - } - else { - fi.deleteFile(); - } - } - if (tmp.renameFile(FileName.getValue()) == false) - Base::Console().Warning("Cannot rename file from '%s' to '%s'\n", - fn.c_str(), FileName.getValue()); - - return true; + return saveToFile(FileName.getValue()); } return false; } +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(compression, Z_NO_COMPRESSION, Z_BEST_COMPRESSION); + + // 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 backup; + std::vector files = di.getDirectoryContent(); + for (std::vector::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(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::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 (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 true; +} + // Open the document void Document::restore (void) { diff --git a/src/App/Document.h b/src/App/Document.h index 7f3235675b..46b70192c3 100644 --- a/src/App/Document.h +++ b/src/App/Document.h @@ -156,7 +156,7 @@ public: /// 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&, std::ostream&); @@ -364,6 +364,7 @@ protected: void breakDependency(DocumentObject* pcObject, bool clear); std::vector readObjects(Base::XMLReader& reader); void writeObjects(const std::vector&, 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