[tomboy] Add initial NoteDirectoryWatcher add-in for watching external changes to note files.
- From: Sanford Armstrong <sharm src gnome org>
- To: svn-commits-list gnome org
- Subject: [tomboy] Add initial NoteDirectoryWatcher add-in for watching external changes to note files.
- Date: Thu, 30 Apr 2009 12:01:20 -0400 (EDT)
commit a973685dfc6ba28cf907198296a5f16245d23aca
Author: Michael Fletcher <m fletcher theplanet ca>
Date: Wed Apr 29 19:45:29 2009 -0600
Add initial NoteDirectoryWatcher add-in for watching external changes to note files.
If you use an external process to modify you ".note" files (ie
DropBox) there is a significant risk that you will lose you note data.
Tomboy will overwrite the note on disk with its representation in
memory.
This patch will watch your ~/.tomboy directory for changes
and update Tomboy's in-memory copy of the note if the note changes.
This reduces the change of losing notes.
---
Tomboy/Addins/Makefile.am | 1 +
Tomboy/Addins/NoteDirectoryWatcher/Makefile.am | 39 ++++
.../NoteDirectoryWatcher.addin.xml | 22 ++
.../NoteDirectoryWatcherApplicationAddin.cs | 237 ++++++++++++++++++++
configure.in | 1 +
5 files changed, 300 insertions(+), 0 deletions(-)
diff --git a/Tomboy/Addins/Makefile.am b/Tomboy/Addins/Makefile.am
index 57f5f56..9520b67 100644
--- a/Tomboy/Addins/Makefile.am
+++ b/Tomboy/Addins/Makefile.am
@@ -13,5 +13,6 @@ SUBDIRS = \
SshSyncService \
StickyNoteImport \
Tasque \
+ NoteDirectoryWatcher \
WebDavSyncService
diff --git a/Tomboy/Addins/NoteDirectoryWatcher/Makefile.am b/Tomboy/Addins/NoteDirectoryWatcher/Makefile.am
new file mode 100644
index 0000000..8250fd2
--- /dev/null
+++ b/Tomboy/Addins/NoteDirectoryWatcher/Makefile.am
@@ -0,0 +1,39 @@
+include $(top_srcdir)/Makefile.include
+
+CSFLAGS = \
+ -debug \
+ -define:DEBUG \
+ -target:library
+
+ASSEMBLIES = \
+ $(LINK_TOMBOY_EXE) \
+ $(GTKSHARP_LIBS) \
+ $(LINK_MONO_ADDINS) \
+ -r:Mono.Posix
+
+ADDIN_NAME = NoteDirectoryWatcher
+TARGET = $(ADDIN_NAME).dll
+CSFILES = \
+ $(srcdir)/NoteDirectoryWatcherApplicationAddin.cs
+RESOURCES = \
+ -resource:$(srcdir)/$(ADDIN_NAME).addin.xml
+
+$(TARGET).mdb: $(TARGET)
+
+$(TARGET): $(CSFILES) $(top_builddir)/Tomboy/Tomboy.exe
+ $(CSC) -out:$@ $(CSFLAGS) $(ASSEMBLIES) $(CSFILES) $(RESOURCES)
+
+
+addinsdir = $(pkglibdir)/addins
+addins_DATA = \
+ $(TARGET) \
+ $(TARGET).mdb
+
+EXTRA_DIST = \
+ $(CSFILES) \
+ $(srcdir)/$(ADDIN_NAME).addin.xml
+
+CLEANFILES = \
+ $(TARGET).mdb \
+ $(TARGET)
+
diff --git a/Tomboy/Addins/NoteDirectoryWatcher/NoteDirectoryWatcher.addin.xml b/Tomboy/Addins/NoteDirectoryWatcher/NoteDirectoryWatcher.addin.xml
new file mode 100644
index 0000000..6bfd500
--- /dev/null
+++ b/Tomboy/Addins/NoteDirectoryWatcher/NoteDirectoryWatcher.addin.xml
@@ -0,0 +1,22 @@
+<Addin id="NoteDirectoryWatcher"
+ namespace="Tomboy"
+ name="Note Directory Watcher"
+ author="Tomboy Project"
+ description="Watch your Tomboy note directory for changes to your notes."
+ category="Tools"
+ defaultEnabled="false"
+ version="0.1">
+
+ <Runtime>
+ <Import assembly="NoteDirectoryWatcher.dll" />
+ </Runtime>
+
+ <Dependencies>
+ <Addin id="Tomboy" version="0.10" />
+ </Dependencies>
+
+ <Extension path="/Tomboy/ApplicationAddins">
+ <ApplicationAddin type="Tomboy.NoteDirectoryWatcher.NoteDirectoryWatcherApplicationAddin" />
+ </Extension>
+
+</Addin>
diff --git a/Tomboy/Addins/NoteDirectoryWatcher/NoteDirectoryWatcherApplicationAddin.cs b/Tomboy/Addins/NoteDirectoryWatcher/NoteDirectoryWatcherApplicationAddin.cs
new file mode 100644
index 0000000..6584246
--- /dev/null
+++ b/Tomboy/Addins/NoteDirectoryWatcher/NoteDirectoryWatcherApplicationAddin.cs
@@ -0,0 +1,237 @@
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+using Tomboy;
+
+namespace Tomboy.NoteDirectoryWatcher
+{
+ class NoteFileChangeRecord
+ {
+ public DateTime last_change;
+ public bool deleted;
+ public bool changed;
+ }
+
+ public class NoteDirectoryWatcherApplicationAddin : ApplicationAddin
+ {
+ private static bool VERBOSE_LOGGING = false;
+
+ private FileSystemWatcher file_system_watcher;
+ private bool initialized;
+
+ private Dictionary<string, NoteFileChangeRecord> file_change_records;
+
+ public override void Initialize ()
+ {
+ string note_path = Tomboy.DefaultNoteManager.NoteDirectoryPath;
+
+ file_change_records = new Dictionary<string, NoteFileChangeRecord>();
+
+ file_system_watcher = new FileSystemWatcher (note_path);
+
+ file_system_watcher.Changed += HandleFileSystemChangeEvent;
+ file_system_watcher.Deleted += HandleFileSystemChangeEvent;
+ file_system_watcher.Created += HandleFileSystemChangeEvent;
+ file_system_watcher.Renamed += HandleFileSystemChangeEvent;
+
+ file_system_watcher.Error += HandleFileSystemErrorEvent;
+
+ // Setting to true will starts the FileSystemWatcher.
+ file_system_watcher.EnableRaisingEvents = true;
+
+ initialized = true;
+ }
+
+ public override void Shutdown ()
+ {
+ file_system_watcher.EnableRaisingEvents = false;
+ initialized = false;
+ }
+
+ public override bool Initialized
+ {
+ get
+ {
+ return initialized;
+ }
+ }
+
+ private void HandleFileSystemErrorEvent (Object sender, ErrorEventArgs arg)
+ {
+ // TODO Rescan the local notes in case some of them have changed.
+ }
+
+ private void HandleFileSystemChangeEvent (Object sender, FileSystemEventArgs arg)
+ {
+ string note_id = GetId(arg.FullPath);
+
+ if (VERBOSE_LOGGING)
+ {
+ Logger.Debug ("{0} has {1} (note_id={2})", arg.FullPath, arg.ChangeType, note_id);
+ }
+
+ // If the note_id is long 36 characters then the file probably wasn't a note.
+ if (note_id.Length != 36)
+ {
+ if (VERBOSE_LOGGING)
+ {
+ Logger.Debug ("Ignoring change to {0}", arg.FullPath);
+ }
+
+ return;
+ }
+
+ // Record that the file has been added/changed/deleted. Adds/changes trump
+ // deletes. Record the date.
+ lock (file_change_records)
+ {
+ NoteFileChangeRecord record = null;
+
+ if (file_change_records.ContainsKey (note_id))
+ {
+ record = file_change_records[note_id];
+ }
+ else
+ {
+ record = new NoteFileChangeRecord ();
+ file_change_records[note_id] = record;
+ }
+
+ if (arg.ChangeType == WatcherChangeTypes.Changed)
+ {
+ record.changed = true;
+ record.deleted = false;
+ }
+ else if (arg.ChangeType == WatcherChangeTypes.Created)
+ {
+ record.changed = true;
+ record.deleted = false;
+ }
+ else if (arg.ChangeType == WatcherChangeTypes.Renamed)
+ {
+ record.changed = true;
+ record.deleted = false;
+ }
+ else if (arg.ChangeType == WatcherChangeTypes.Deleted)
+ {
+ if (!record.changed)
+ {
+ record.deleted = true;
+ }
+ }
+ else
+ {
+ String message = "Unexpected WatcherChangeType " + arg.ChangeType;
+ Logger.Error (message);
+ throw new Exception (message);
+ }
+
+ record.last_change = DateTime.Now;
+ }
+
+ GLib.Timeout.Add (5000, new GLib.TimeoutHandler (HandleTimeout));
+ }
+
+ private bool HandleTimeout ()
+ {
+ lock (file_change_records)
+ {
+ List<string> keysToRemove = new List<string> (file_change_records.Count);
+
+ foreach (KeyValuePair<string, NoteFileChangeRecord> pair in file_change_records)
+ {
+ if (VERBOSE_LOGGING)
+ {
+ Logger.Debug ("Handling (timeout) {0}", pair.Key);
+ }
+
+ if (DateTime.Now > pair.Value.last_change.Add (new TimeSpan (4000)) )
+ {
+ if (pair.Value.deleted)
+ {
+ DeleteNote (pair.Key);
+ }
+ else
+ {
+ AddOrUpdateNote (pair.Key);
+ }
+
+ keysToRemove.Add (pair.Key);
+ }
+ }
+
+ foreach (string note_id in keysToRemove)
+ {
+ file_change_records.Remove (note_id);
+ }
+ }
+
+ return false;
+ }
+
+ private static void DeleteNote (string note_id)
+ {
+ Logger.Debug ("Deleting {0} because file deleted.", note_id);
+
+ string note_uri = MakeUri (note_id);
+
+ Note note_to_delete = Tomboy.DefaultNoteManager.FindByUri (note_uri);
+
+ Tomboy.DefaultNoteManager.Notes.Remove (note_to_delete);
+
+ note_to_delete.Delete ();
+ }
+
+ private static void AddOrUpdateNote (string note_id)
+ {
+ string note_path = Tomboy.DefaultNoteManager.NoteDirectoryPath +
+ Path.DirectorySeparatorChar + note_id + ".note";
+
+ string note_uri = MakeUri (note_id);
+
+ Note note = Tomboy.DefaultNoteManager.FindByUri (note_uri);
+
+ if (note == null)
+ {
+ Logger.Debug ("Adding {0} because file changed.", note_id);
+ Note new_note = Note.Load (note_path, Tomboy.DefaultNoteManager);
+ Tomboy.DefaultNoteManager.Notes.Add (new_note);
+ }
+ else
+ {
+ NoteData data = NoteArchiver.Instance.ReadFile (note_path, note_uri);
+
+ // Only record changes if the note actually changes. This prevents the Addin from
+ // noticing changes from Tomboy itself.
+ if (data.Text == note.XmlContent)
+ {
+ if (VERBOSE_LOGGING)
+ {
+ Logger.Debug ("Ignoring {0} because contents identical", note_id);
+ }
+ }
+ else
+ {
+ Logger.Debug ("Updating {0} because file changed.", note_id);
+ note.XmlContent = data.Text;
+ note.Title = data.Title;
+ }
+ }
+ }
+
+ private static String MakeUri (string note_id)
+ {
+ return "note://tomboy/" + note_id;
+ }
+
+ private static string GetId (string path)
+ {
+ int last_slash = path.LastIndexOf (Path.DirectorySeparatorChar);
+ int first_period = path.IndexOf ('.', last_slash);
+
+ return path.Substring (last_slash + 1, first_period - last_slash - 1);
+ }
+ }
+}
diff --git a/configure.in b/configure.in
index ab9b951..8563e58 100644
--- a/configure.in
+++ b/configure.in
@@ -333,6 +333,7 @@ Tomboy/Addins/SshSyncService/Makefile
Tomboy/Addins/StickyNoteImport/Makefile
Tomboy/Addins/Tasque/Makefile
Tomboy/Addins/WebDavSyncService/Makefile
+Tomboy/Addins/NoteDirectoryWatcher/Makefile
test/Makefile
po/Makefile.in
])
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]