> That is ugly indeed, but you could use an enum instead of the bool and > remove the default argument. That would also be quite self documenting. And > could you please add the info about the 2 second FAT timestamp granularity > to the documentation? In 6 months nobody will remember that anymore.
All done, the eighth version is attached. Bo
Index: src/Buffer.h =================================================================== --- src/Buffer.h (revision 19374) +++ src/Buffer.h (working copy) @@ -83,6 +83,22 @@ wrongversion ///< The version of the file does not match ours }; + /// Method to check if a file is externally modified, used by + /// isExternallyModified() + /** + * timestamp is fast but inaccurate. For example, the granularity + * of timestamp on a FAT filesystem is 2 second. Also, various operations + * may touch the timestamp of a file even when its content is unchanged. + * + * checksum is accurate but slow, which can be a problem when it is + * frequently used, or used for a large file on a slow (network) file + * system. + */ + enum CheckMethod { + checksum_method, ///< Use file check sum + timestamp_method, ///< Use timestamp, and checksum if timestamp has changed + }; + /** Constructor \param file \param b optional \c false by default @@ -210,6 +226,9 @@ /// bool isDepClean(std::string const & name) const; + /// whether or not disk file has been externally modified + bool isExternallyModified(CheckMethod method) const; + /// mark the main lyx file as not needing saving void markClean() const; Index: src/LyXFunc.cpp =================================================================== --- src/LyXFunc.cpp (revision 19374) +++ src/LyXFunc.cpp (working copy) @@ -496,7 +496,8 @@ enable = buf->lyxvc().inUse(); break; case LFUN_BUFFER_RELOAD: - enable = !buf->isUnnamed() && !buf->isClean(); + enable = !buf->isUnnamed() && fs::exists(buf->fileName()) + && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method)); break; case LFUN_INSET_SETTINGS: { Index: src/Buffer.cpp =================================================================== --- src/Buffer.cpp (revision 19374) +++ src/Buffer.cpp (working copy) @@ -103,6 +103,7 @@ using std::stack; using std::vector; using std::string; +using std::time_t; namespace lyx { @@ -131,6 +132,7 @@ using support::subst; using support::tempName; using support::trim; +using support::sum; namespace Alert = frontend::Alert; namespace os = support::os; @@ -192,13 +194,18 @@ /// Container for all sort of Buffer dependant errors. map<string, ErrorList> errorLists; + + /// timestamp and checksum used to test if the file has been externally + /// modified. (Used to properly enable 'File->Revert to saved', bug 4114). + time_t timestamp_; + unsigned long checksum_; }; Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_) : lyx_clean(true), bak_clean(true), unnamed(false), read_only(readonly_), filename(file), file_fully_loaded(false), inset(params), - toc_backend(&parent) + timestamp_(0), checksum_(0), toc_backend(&parent) { inset.setAutoBreakRows(true); lyxvc.buffer(&parent); @@ -755,6 +762,9 @@ //MacroTable::localMacros().clear(); pimpl_->file_fully_loaded = true; + // save the timestamp and checksum of disk file + pimpl_->timestamp_ = fs::last_write_time(filename.toFilesystemEncoding()); + pimpl_->checksum_ = sum(filename); return success; } @@ -789,9 +799,22 @@ } } + // ask if the disk file has been externally modified (use checksum method) + if (fs::exists(encodedFilename) && isExternallyModified(checksum_method)) { + docstring const file = makeDisplayPath(fileName(), 20); + docstring text = bformat(_("Document %1$s has been externally modified. Are you sure " + "you want to overwrite this file?"), file); + int const ret = Alert::prompt(_("Overwrite modified file?"), + text, 1, 1, _("&Overwrite"), _("&Cancel")); + if (ret == 1) + return false; + } + if (writeFile(pimpl_->filename)) { markClean(); removeAutosaveFile(fileName()); + pimpl_->timestamp_ = fs::last_write_time(pimpl_->filename.toFilesystemEncoding()); + pimpl_->checksum_ = sum(pimpl_->filename); return true; } else { // Saving failed, so backup is not backup @@ -1556,6 +1579,16 @@ } +bool Buffer::isExternallyModified(CheckMethod method) const +{ + BOOST_ASSERT(fs::exists(pimpl_->filename.toFilesystemEncoding())); + // if method == timestamp, check timestamp before checksum + return (method == checksum_method + || pimpl_->timestamp_ != fs::last_write_time(pimpl_->filename.toFilesystemEncoding())) + && pimpl_->checksum_ != sum(pimpl_->filename); +} + + void Buffer::markClean() const { if (!pimpl_->lyx_clean) { Index: lib/ui/stdmenus.inc =================================================================== --- lib/ui/stdmenus.inc (revision 19374) +++ lib/ui/stdmenus.inc (working copy) @@ -41,7 +41,7 @@ Item "Save|S" "buffer-write" Item "Save As...|A" "buffer-write-as" Item "Save All|l" "buffer-write-all" - Item "Revert|R" "buffer-reload" + Item "Revert to saved|R" "buffer-reload" Submenu "Version Control|V" "file_vc" Separator Submenu "Import|I" "file_import" Index: status.15x =================================================================== --- status.15x (revision 19374) +++ status.15x (working copy) @@ -40,14 +40,18 @@ * DOCUMENT INPUT/OUTPUT +- Check if the .lyx file has been externally modified when a buffer is saved. * USER INTERFACE: - Fix loading non-lyx child documents with relative path names, change - 'Load' to 'Edit' in the child document dialog. (Bug 4107 and 4111) + 'Load' to 'Edit' in the child document dialog. (Bugs 4107 and 4111) - Fix bug 4112: Do roman numerals beyond 20. +- Enable File -> Revert when the file is externally modified, and rename + this menu item to File -> Revert to saved. (Bugs 3766 and 4114) + * DOCUMENTATION