> 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
 
 

Reply via email to