[tomboy] Reorganize notes and config data according to OS conventions (#518585, #557288)



commit 519ce03e8fba04cb812c4e8fb352a5f4cec15413
Author: Sandy Armstrong <sanfordarmstrong gmail com>
Date:   Mon Aug 24 14:42:11 2009 -0700

    Reorganize notes and config data according to OS conventions (#518585, #557288)
    
    Allow each platform to specify its preferred directories for note files,
    configuration data, cached data, and logs. On Linux, this means following
    the XDG Base Directory Specification (bug #518585).  New default directories:
    
    Linux:
    Notes: ~/.local/share/tomboy/
    Configuration and add-ins: ~/.config/tomboy/
    Caches: ~/.cache/tomboy/
    Logs: ~/.config/tomboy/
    
    Mac (bug #557288):
    Notes: ~/Library/Application Support/Tomboy/
    Configuration and add-ins: ~/Library/Preferences/Tomboy/
    Caches: ~/Library/Caches/Tomboy/
    Logs: ~/Library/Logs/Tomboy/
    
    Windows:
    Notes: %APPDATA%\Tomboy\notes\
    Configuration and add-ins: %APPDATA%\Tomboy\config\
    Caches: %LOCALAPPDATA%\Tomboy\cache\
    Logs: %LOCALAPPDATA%\Tomboy\
    
    Notes directory can still be overridden by setting the TOMBOY_PATH env var.

 Tomboy.mdp                                     |    2 +
 Tomboy/AddinManager.cs                         |   20 ++++-
 Tomboy/Addins/Bugzilla/BugzillaLink.cs         |    7 +-
 Tomboy/Addins/Bugzilla/BugzillaNoteAddin.cs    |   21 +++++
 Tomboy/Addins/Bugzilla/BugzillaPreferences.cs  |   21 ++----
 Tomboy/GnomeApplication.cs                     |   46 +++++++++--
 Tomboy/Hyena/XdgBaseDirectorySpec.cs           |   82 +++++++++++++++++++
 Tomboy/Logger.cs                               |   11 +--
 Tomboy/MacApplication.cs                       |  102 +++++++++++++++++++++---
 Tomboy/Makefile.am                             |    2 +
 Tomboy/NativeApplication.cs                    |   10 ++-
 Tomboy/NoteManager.cs                          |  103 ++++++++++++++++++++++--
 Tomboy/Synchronization/FileSystemSyncServer.cs |    8 +-
 Tomboy/Synchronization/FuseSyncServiceAddin.cs |    8 +-
 Tomboy/Synchronization/TomboySyncClient.cs     |    4 +-
 Tomboy/Tomboy.cs                               |    6 +-
 Tomboy/Utils.cs                                |   17 ++++
 Tomboy/WindowsApplication.cs                   |   52 ++++++++++---
 Tomboy/XmlPreferencesClient.cs                 |   18 ++++-
 19 files changed, 460 insertions(+), 80 deletions(-)
---
diff --git a/Tomboy.mdp b/Tomboy.mdp
index 20565d7..deefaad 100644
--- a/Tomboy.mdp
+++ b/Tomboy.mdp
@@ -185,6 +185,8 @@
     <File name="Tomboy/Addins/WebSyncService/OAuth/Mono.Rocks/IEnumerable.cs" subtype="Code" buildaction="Compile" />
     <File name="Tomboy/Addins/WebSyncService/Api/RootInfo.cs" subtype="Code" buildaction="Compile" />
     <File name="Tomboy/gtk-sharp-beans/Global.cs" subtype="Code" buildaction="Compile" />
+    <File name="Tomboy/Hyena/XdgBaseDirectorySpec.cs" subtype="Code" buildaction="Compile" />
+    <File name="Tomboy/MacApplication.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
diff --git a/Tomboy/AddinManager.cs b/Tomboy/AddinManager.cs
index fc2efa8..d784c36 100644
--- a/Tomboy/AddinManager.cs
+++ b/Tomboy/AddinManager.cs
@@ -31,20 +31,34 @@ namespace Tomboy
 
 		public event System.EventHandler ApplicationAddinListChanged;
 
-		public AddinManager (string tomboy_conf_dir)
+		public AddinManager (string tomboy_conf_dir) : this (tomboy_conf_dir, null)
+		{
+		}
+
+		public AddinManager (string tomboy_conf_dir, string old_tomboy_conf_dir)
 		{
 			this.tomboy_conf_dir = tomboy_conf_dir;
 			app_addins = new Dictionary<string, ApplicationAddin> ();
 			note_addins = new Dictionary<Note, List<NoteAddinInfo>> ();
 			note_addin_infos = new Dictionary<string, List<NoteAddinInfo>> ();
 
-			InitializeMonoAddins ();
+			InitializeMonoAddins (old_tomboy_conf_dir);
 		}
 
-		void InitializeMonoAddins ()
+		void InitializeMonoAddins (string old_conf_dir)
 		{
 			Logger.Info ("Initializing Mono.Addins");
 
+			// Perform migration if necessary
+			if (!String.IsNullOrEmpty (old_conf_dir)) {
+				foreach (string dir_path in Directory.GetDirectories (old_conf_dir, "addin*")) {
+					string new_dir_path =
+						Path.Combine (tomboy_conf_dir, Path.GetFileName (dir_path));
+					if (!Directory.Exists (new_dir_path))
+						IOUtils.CopyDirectory (dir_path, new_dir_path);
+				}
+			}
+
 			string addins_dir = Path.Combine (tomboy_conf_dir, "addins");
 			if (!Directory.Exists (addins_dir))
 				Directory.CreateDirectory (addins_dir);
diff --git a/Tomboy/Addins/Bugzilla/BugzillaLink.cs b/Tomboy/Addins/Bugzilla/BugzillaLink.cs
index a85f510..152c979 100644
--- a/Tomboy/Addins/Bugzilla/BugzillaLink.cs
+++ b/Tomboy/Addins/Bugzilla/BugzillaLink.cs
@@ -1,4 +1,6 @@
 using System;
+using System.IO;
+
 using Tomboy;
 
 namespace Tomboy.Bugzilla
@@ -60,9 +62,8 @@ namespace Tomboy.Bugzilla
 			}
 
 			string host = uri.Host;
-			// TODO: Get this in a safer way
-			string imageDir = "~/.tomboy/BugzillaIcons/";
-			string imagePath = imageDir.Replace ("~", Environment.GetEnvironmentVariable ("HOME")) + host + ".png";
+			string imagePath = Path.Combine (BugzillaNoteAddin.ImageDirectory,
+			                                 host + ".png");
 
 			try {
 				Image = new Gdk.Pixbuf (imagePath);
diff --git a/Tomboy/Addins/Bugzilla/BugzillaNoteAddin.cs b/Tomboy/Addins/Bugzilla/BugzillaNoteAddin.cs
index 4360741..608e83a 100644
--- a/Tomboy/Addins/Bugzilla/BugzillaNoteAddin.cs
+++ b/Tomboy/Addins/Bugzilla/BugzillaNoteAddin.cs
@@ -1,5 +1,6 @@
 
 using System;
+using System.IO;
 using System.Runtime.InteropServices;
 using System.Text;
 using System.Text.RegularExpressions;
@@ -15,6 +16,26 @@ namespace Tomboy.Bugzilla
 	{
 		public const string BugzillaLinkTagName = "link:bugzilla";
 
+		private static string image_dir = null;
+
+		public static string ImageDirectory {
+			get {
+				if (image_dir == null) {
+					image_dir = Path.Combine (Services.NativeApplication.ConfigurationDirectory,
+					                          "BugzillaIcons");
+
+					// Perform migration if necessary
+					if (!Directory.Exists (ImageDirectory)) {
+						string old_image_dir = Path.Combine (Services.NativeApplication.PreOneDotZeroNoteDirectory,
+						                                     "BugzillaIcons");
+						if (Directory.Exists (old_image_dir))
+							IOUtils.CopyDirectory (old_image_dir, image_dir);
+					}
+				}
+				return image_dir;
+			}
+		}
+
 		public override void Initialize ()
 		{
 			if (!Note.TagTable.IsDynamicTagRegistered (BugzillaLinkTagName)) {
diff --git a/Tomboy/Addins/Bugzilla/BugzillaPreferences.cs b/Tomboy/Addins/Bugzilla/BugzillaPreferences.cs
index 09e14e9..d398fb2 100644
--- a/Tomboy/Addins/Bugzilla/BugzillaPreferences.cs
+++ b/Tomboy/Addins/Bugzilla/BugzillaPreferences.cs
@@ -14,15 +14,6 @@ namespace Tomboy.Bugzilla
 
 		string last_opened_dir;
 
-		static string IMAGE_DIR = "~/.tomboy/BugzillaIcons";
-		static string image_dir = null;
-
-		static BugzillaPreferences ()
-		{
-			// TODO: Get this in a safer way
-			image_dir = IMAGE_DIR.Replace ("~", Environment.GetEnvironmentVariable ("HOME"));
-		}
-
 		public BugzillaPreferences ()
 : base (false, 12)
 		{
@@ -116,14 +107,14 @@ namespace Tomboy.Bugzilla
 
 		void UpdateIconStore ()
 		{
-			// Read ~/.tomboy/BugzillaIcons/"
+			// Read ~/.config/tomboy/BugzillaIcons/"
 
-			if (!Directory.Exists (image_dir))
+			if (!Directory.Exists (BugzillaNoteAddin.ImageDirectory))
 				return;
 
 			icon_store.Clear (); // clear out the old entries
 
-			string [] icon_files = Directory.GetFiles (image_dir);
+			string [] icon_files = Directory.GetFiles (BugzillaNoteAddin.ImageDirectory);
 			foreach (string icon_file in icon_files) {
 				FileInfo file_info = new FileInfo (icon_file);
 
@@ -272,10 +263,10 @@ run_add_dialog:
 
 			FileInfo file_info = new FileInfo (file_path);
 			string ext = file_info.Extension;
-			string saved_path = System.IO.Path.Combine (image_dir, host + ext);
+			string saved_path = System.IO.Path.Combine (BugzillaNoteAddin.ImageDirectory, host + ext);
 			try {
-				if (!Directory.Exists (image_dir)) {
-					Directory.CreateDirectory (image_dir);
+				if (!Directory.Exists (BugzillaNoteAddin.ImageDirectory)) {
+					Directory.CreateDirectory (BugzillaNoteAddin.ImageDirectory);
 				}
 
 				File.Copy (file_path, saved_path);
diff --git a/Tomboy/GnomeApplication.cs b/Tomboy/GnomeApplication.cs
index cb9312e..5c1a655 100644
--- a/Tomboy/GnomeApplication.cs
+++ b/Tomboy/GnomeApplication.cs
@@ -7,17 +7,34 @@ using System.Xml;
 using Mono.Unix;
 using Mono.Unix.Native;
 
+using Hyena;
+
 namespace Tomboy
 {
 	public class GnomeApplication : INativeApplication
 	{
 		private Gnome.Program program;
-		private string confDir;
+		private static string confDir;
+		private static string dataDir;
+		private static string cacheDir;
+		private const string tomboyDirName = "tomboy";
 
-		public GnomeApplication ()
+		static GnomeApplication ()
 		{
-			confDir = Path.Combine (Environment.GetEnvironmentVariable ("HOME"),
-			                        ".tomboy");
+			dataDir = Path.Combine (XdgBaseDirectorySpec.GetUserDirectory ("XDG_DATA_HOME",
+			                                                               Path.Combine (".local", "share")),
+			                        tomboyDirName);
+			confDir = Path.Combine (XdgBaseDirectorySpec.GetUserDirectory ("XDG_CONFIG_HOME",
+			                                                               ".config"),
+			                        tomboyDirName);
+			cacheDir = Path.Combine (XdgBaseDirectorySpec.GetUserDirectory ("XDG_CACHE_HOME",
+			                                                                ".cache"),
+			                         tomboyDirName);
+
+			// NOTE: Other directories created on demand
+			//       (non-existence is an indicator that migration is needed)
+			if (!Directory.Exists (cacheDir))
+				Directory.CreateDirectory (cacheDir);
 		}
 
 		public void Initialize (string locale_dir,
@@ -152,9 +169,26 @@ namespace Tomboy
 			GtkBeans.Global.ShowUri (screen, help_uri);
 		}
 		
-		public string ConfDir {
+		public string DataDirectory {
+			get { return dataDir; }
+		}
+
+		public string ConfigurationDirectory {
+			get { return confDir; }
+		}
+
+		public string CacheDirectory {
+			get { return cacheDir; }
+		}
+
+		public string LogDirectory {
+			get { return confDir; }
+		}
+
+		public string PreOneDotZeroNoteDirectory {
 			get {
-				return confDir;
+				return Path.Combine (Environment.GetEnvironmentVariable ("HOME"),
+				                     ".tomboy");
 			}
 		}
 	}
diff --git a/Tomboy/Hyena/XdgBaseDirectorySpec.cs b/Tomboy/Hyena/XdgBaseDirectorySpec.cs
new file mode 100644
index 0000000..e92084e
--- /dev/null
+++ b/Tomboy/Hyena/XdgBaseDirectorySpec.cs
@@ -0,0 +1,82 @@
+//
+// XdgBaseDirectorySpec.cs
+//
+// Author:
+//   Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2006-2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+
+namespace Hyena
+{
+    public static class XdgBaseDirectorySpec
+    {
+        public static string GetUserDirectory (string key, string fallback)
+        {
+            string home_dir = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
+            string config_dir = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
+            
+            string env_path = Environment.GetEnvironmentVariable (key);
+            if (!String.IsNullOrEmpty (env_path)) {
+                return env_path;
+            }
+
+            string user_dirs_path = Path.Combine (config_dir, "user-dirs.dirs");
+
+            if (!File.Exists (user_dirs_path)) {
+                return Path.Combine (home_dir, fallback);
+            }
+
+            try {
+                using (StreamReader reader = new StreamReader (user_dirs_path)) {
+                    string line;
+                    while ((line = reader.ReadLine ()) != null) {
+                        line = line.Trim ();
+                        int delim_index = line.IndexOf ('=');
+                        if (delim_index > 8 && line.Substring (0, delim_index) == key) {
+                            string path = line.Substring (delim_index + 1).Trim ('"');
+                            bool relative = false;
+
+                            if (path.StartsWith ("$HOME/")) {
+                                relative = true;
+                                path = path.Substring (6);
+                            } else if (path.StartsWith ("~")) {
+                                relative = true;
+                                path = path.Substring (1);
+                            } else if (!path.StartsWith ("/")) {
+                                relative = true;
+                            }
+
+                            return relative ? Path.Combine (home_dir, path) : path;
+                        }
+                    }
+                }
+            } catch (FileNotFoundException) {
+            }
+            
+            return Path.Combine (home_dir, fallback);
+        }
+    }
+}
diff --git a/Tomboy/Logger.cs b/Tomboy/Logger.cs
index 54669c8..46314ca 100644
--- a/Tomboy/Logger.cs
+++ b/Tomboy/Logger.cs
@@ -57,17 +57,14 @@ namespace Tomboy
 		{
 			console = new ConsoleLogger ();
 
-#if WIN32
+			string logDir = Services.NativeApplication.LogDirectory;
 			string logfile = Path.Combine(
-				Services.NativeApplication.ConfDir,
+				logDir,
 				"tomboy.log");
-#else
-			string logfile = Path.Combine(
-				Environment.GetEnvironmentVariable ("HOME"),
-				".tomboy.log");
-#endif
 
 			try {
+				if (!Directory.Exists (logDir))
+					Directory.CreateDirectory (logDir);
 				log = File.CreateText (logfile);
 				log.Flush ();
 			} catch (IOException iox) {
diff --git a/Tomboy/MacApplication.cs b/Tomboy/MacApplication.cs
index 0eae103..b8a6c4a 100644
--- a/Tomboy/MacApplication.cs
+++ b/Tomboy/MacApplication.cs
@@ -24,6 +24,7 @@
 // 
 
 using System;
+using System.IO;
 using System.Runtime.InteropServices;
 using Mono.Unix;
 
@@ -134,7 +135,7 @@ namespace Tomboy
 
 	}
 	
-	public class MacApplication : WindowsApplication
+	public class MacApplication : INativeApplication
 	{
 		private const string osxMenuXml =@"
 <ui>
@@ -148,7 +149,60 @@ namespace Tomboy
   </menubar>
 </ui>
 ";
-		public override void StartMainLoop ()
+
+		private static string confDir;
+		private static string dataDir;
+		private static string cacheDir;
+		private static string logDir;
+		private const string tomboyDirName = "Tomboy";
+
+		static MacApplication ()
+		{
+			string homeDir = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
+			string libraryDir = Path.Combine (homeDir, "Library");
+
+			dataDir = Path.Combine (Path.Combine (libraryDir, "Application Support"),
+			                        tomboyDirName);
+			confDir = Path.Combine (Path.Combine (libraryDir, "Preferences"),
+			                        tomboyDirName);
+			cacheDir = Path.Combine (Path.Combine (libraryDir, "Caches"),
+			                         tomboyDirName);
+			logDir = Path.Combine (Path.Combine (libraryDir, "Logs"),
+			                       tomboyDirName);
+
+			// NOTE: Other directories created on demand
+			//       (non-existence is an indicator that migration is needed)
+			if (!Directory.Exists (cacheDir))
+				Directory.CreateDirectory (cacheDir);
+		}
+
+		#region INativeApplication implementation
+
+		public event EventHandler ExitingEvent;
+
+		public virtual void Initialize (string locale_dir, string display_name, string process_name, string[] args)
+		{
+			Gtk.Application.Init ();
+		}
+
+		public virtual void RegisterSessionManagerRestart (string executable_path, string[] args, string[] environment)
+		{
+			// Do nothing
+		}
+
+		public virtual void RegisterSignalHandlers ()
+		{
+			// Nothing yet, but need to register for native exit signals?
+		}
+
+		public virtual void Exit (int exitcode)
+		{
+			if (ExitingEvent != null)
+				ExitingEvent (null, new EventArgs ());
+			System.Environment.Exit (exitcode);
+		}
+
+		public virtual void StartMainLoop ()
 		{
 			Gtk.UIManager uiManager = Tomboy.ActionManager.UI;
 			
@@ -194,17 +248,45 @@ namespace Tomboy
 			
 			Tomboy.ActionManager ["CloseWindowAction"].Visible = false;
 			
-			base.StartMainLoop ();
+			Gtk.Application.Run ();
 		}
-			
-			[DllImport ("libc", EntryPoint="system")]
-			public static extern int system (string command);
-			
-			public override void OpenUrl (string url, Gdk.Screen screen)
-			{
-				system ("open \"" + url + "\"");
+
+		public string DataDirectory {
+			get { return dataDir; }
+		}
+
+		public string ConfigurationDirectory {
+			get { return confDir; }
+		}
+
+		public string CacheDirectory {
+			get { return cacheDir; }
+		}
+
+		public string LogDirectory {
+			get { return logDir; }
+		}
+
+		public string PreOneDotZeroNoteDirectory {
+			get {
+				return Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
+				                     "tomboy");
 			}
+		}
 
+		[DllImport ("libc", EntryPoint="system")]
+		public static extern int system (string command);
+
+		public virtual void OpenUrl (string url, Gdk.Screen screen)
+		{
+			system ("open \"" + url + "\"");
+		}
+
+		public virtual void DisplayHelp (string help_uri, Gdk.Screen screen)
+		{
+			OpenUrl ("http://library.gnome.org/users/tomboy/0.12/";, screen);
+		}
 
+		#endregion
 	}
 }
diff --git a/Tomboy/Makefile.am b/Tomboy/Makefile.am
index 16a0a46..28c14ef 100644
--- a/Tomboy/Makefile.am
+++ b/Tomboy/Makefile.am
@@ -121,6 +121,8 @@ CSFILES = 					\
 	$(srcdir)/Notebooks/*.cs		\
 	$(srcdir)/Synchronization/*.cs		\
 	\
+	$(srcdir)/Hyena/*.cs			\
+	\
 	$(GNOME_USED_CSFILES)			\
 	$(WIN_USED_CSFILES)			\
 	$(OSX_USED_CSFILES)			\
diff --git a/Tomboy/NativeApplication.cs b/Tomboy/NativeApplication.cs
index 13587aa..6a9dca9 100644
--- a/Tomboy/NativeApplication.cs
+++ b/Tomboy/NativeApplication.cs
@@ -18,7 +18,15 @@ namespace Tomboy
 		void Exit (int exitcode);
 		void StartMainLoop ();
 
-		string ConfDir { get; }
+		string PreOneDotZeroNoteDirectory { get; }
+
+		string CacheDirectory { get; }
+
+		string ConfigurationDirectory { get; }
+
+		string DataDirectory { get; }
+
+		string LogDirectory { get; }
 
 		void OpenUrl (string url, Gdk.Screen screen);
 
diff --git a/Tomboy/NoteManager.cs b/Tomboy/NoteManager.cs
index c4c6503..76c6a07 100644
--- a/Tomboy/NoteManager.cs
+++ b/Tomboy/NoteManager.cs
@@ -52,11 +52,51 @@ public NoteManager (string directory) :
 			backup_dir = backup_directory;
 			notes = new List<Note> ();
 
+			string conf_dir = Services.NativeApplication.ConfigurationDirectory;
+
+			string old_notes_dir = null;
+			bool migration_needed = false;
+
 			bool first_run = FirstRun ();
+			if (first_run) {
+				old_notes_dir = Services.NativeApplication.PreOneDotZeroNoteDirectory;
+				migration_needed = DirectoryExists (old_notes_dir);
+			}
 			CreateNotesDir ();
+			if (!Directory.Exists (conf_dir))
+				Directory.CreateDirectory (conf_dir);
+
+			if (migration_needed) {
+				// Copy notes
+				foreach (string noteFile in Directory.GetFiles (old_notes_dir, "*.note"))
+					File.Copy (noteFile, Path.Combine (notes_dir, Path.GetFileName (noteFile)));
+
+				// Copy deleted notes
+				string old_backup = Path.Combine (old_notes_dir, "Backup");
+				if (DirectoryExists (old_backup)) {
+					Directory.CreateDirectory (backup_dir);
+					foreach (string noteFile in Directory.GetFiles (old_backup, "*.note"))
+						File.Copy (noteFile, Path.Combine (backup_dir, Path.GetFileName (noteFile)));
+				}
+
+				// Copy configuration data
+				// NOTE: Add-in configuration data copied by AddinManager
+				string sync_manifest_name = "manifest.xml";
+				string old_sync_manifest_path =
+					Path.Combine (old_notes_dir, sync_manifest_name);
+				if (File.Exists (old_sync_manifest_path))
+					File.Copy (old_sync_manifest_path,
+					           Path.Combine (conf_dir, sync_manifest_name));
+
+
+				// NOTE: Not copying cached data
+
+				first_run = false;
+			}
 
 			trie_controller = CreateTrieController ();
-			addin_mgr = CreateAddinManager ();
+			addin_mgr = new AddinManager (conf_dir,
+			                              migration_needed ? old_notes_dir : null);
 
 			if (first_run) {
 				// First run. Create "Start Here" notes.
@@ -65,6 +105,60 @@ public NoteManager (string directory) :
 				LoadNotes ();
 			}
 
+			if (migration_needed) {
+				// Create migration notification note
+				// Translators: The title of the data migration note
+				string base_migration_note_title = Catalog.GetString ("Your Notes Have Moved!");
+				string migration_note_title = base_migration_note_title;
+
+				// NOTE: Uncomment to generate a title suitable for
+				//       putting in the note collection
+//				int count = 1;
+//				while (Find (migration_note_title) != null) {
+//					migration_note_title = base_migration_note_title +
+//						string.Format (" ({0})", ++count);
+//				}
+
+				string migration_note_content_template = Catalog.GetString (
+// Translators: The contents (not including the title) of the data migration note. {0}, {1}, {2}, {3}, and {4} are replaced by directory paths and should not be changed
+@"In the latest version of Tomboy, your note files have moved.  You have probably never cared where your notes are stored, and if you still don't care, please go ahead and <bold>delete this note</bold>.  :-)
+
+Your old note directory is still safe and sound at <link:url>{0}</link:url> . If you go back to an older version of Tomboy, it will look for notes there.
+
+But we've copied your notes and configuration info into new directories, which will be used from now on:
+
+<list><list-item dir=""ltr"">Notes can now be found at <link:url>{1}</link:url>
+</list-item><list-item dir=""ltr"">Configuration is at <link:url>{2}</link:url>
+</list-item><list-item dir=""ltr"">You can install add-ins at <link:url>{3}</link:url>
+</list-item><list-item dir=""ltr"">Log files can be found at <link:url>{4}</link:url></list-item></list>
+
+Ciao!");
+				string migration_note_content =
+					"<note-content version=\"1.0\">" +
+					migration_note_title + "\n\n" +
+					string.Format (migration_note_content_template,
+					               old_notes_dir + Path.DirectorySeparatorChar,
+					               notes_dir + Path.DirectorySeparatorChar,
+					               conf_dir + Path.DirectorySeparatorChar,
+					               Path.Combine (conf_dir, "addins") + Path.DirectorySeparatorChar,
+					               Services.NativeApplication.LogDirectory + Path.DirectorySeparatorChar) +
+					"</note-content>";
+
+				// NOTE: Uncomment to create a Tomboy note and
+				//       show it to the user
+//				Note migration_note = Create (migration_note_title,
+//				                              migration_note_content);
+//				migration_note.QueueSave (ChangeType.ContentChanged);
+//				migration_note.Window.Show ();
+
+				// Place file announcing migration in old note directory
+				try {
+					using (var writer = File.CreateText (Path.Combine (old_notes_dir,
+					                                                   migration_note_title.ToUpper ().Replace (" ", "_"))))
+						writer.Write (migration_note_content);
+				} catch {}
+			}
+
 			Tomboy.ExitingEvent += OnExitingEvent;
 		}
 		
@@ -75,13 +169,6 @@ public NoteManager (string directory) :
 			return new TrieController (this);
 		}
 
-		protected virtual AddinManager CreateAddinManager ()
-		{
-			string tomboy_conf_dir = Services.NativeApplication.ConfDir;
-
-			return new AddinManager (tomboy_conf_dir);
-		}
-
 		// For overriding in test methods.
 		protected virtual bool DirectoryExists (string directory)
 		{
diff --git a/Tomboy/Synchronization/FileSystemSyncServer.cs b/Tomboy/Synchronization/FileSystemSyncServer.cs
index ed143e6..5cd5315 100644
--- a/Tomboy/Synchronization/FileSystemSyncServer.cs
+++ b/Tomboy/Synchronization/FileSystemSyncServer.cs
@@ -13,7 +13,7 @@ namespace Tomboy.Sync
 		private string serverId;
 
 		private string serverPath;
-		private string notePath;
+		private string cachePath;
 		private string lockPath;
 		private string manifestPath;
 
@@ -32,7 +32,7 @@ namespace Tomboy.Sync
 			if (!Directory.Exists (serverPath))
 				throw new DirectoryNotFoundException (serverPath);
 
-			notePath = Tomboy.DefaultNoteManager.NoteDirectoryPath;
+			cachePath = Services.NativeApplication.CacheDirectory;
 			lockPath = Path.Combine (serverPath, "lock");
 			manifestPath = Path.Combine (serverPath, "manifest.xml");
 
@@ -100,7 +100,7 @@ namespace Tomboy.Sync
 		{
 			Dictionary<string, NoteUpdate> noteUpdates = new Dictionary<string, NoteUpdate> ();
 
-			string tempPath = Path.Combine (notePath, "sync_temp");
+			string tempPath = Path.Combine (cachePath, "sync_temp");
 			if (!Directory.Exists (tempPath)) {
 				Directory.CreateDirectory (tempPath);
 			} else {
@@ -112,7 +112,7 @@ namespace Tomboy.Sync
 				} catch {}
 			}
 
-		if (IsValidXmlFile (manifestPath)) {
+			if (IsValidXmlFile (manifestPath)) {
 				// TODO: Permissions errors
 				using (FileStream fs = new FileStream (manifestPath, FileMode.Open)) {
 					XmlDocument doc = new XmlDocument ();
diff --git a/Tomboy/Synchronization/FuseSyncServiceAddin.cs b/Tomboy/Synchronization/FuseSyncServiceAddin.cs
index da09b0f..1fdcaad 100644
--- a/Tomboy/Synchronization/FuseSyncServiceAddin.cs
+++ b/Tomboy/Synchronization/FuseSyncServiceAddin.cs
@@ -121,9 +121,9 @@ namespace Tomboy.Sync
 					// Test ability to read
 					bool testFileFound = false;
 					foreach (string filePath in Directory.GetFiles (mountPath))
-					if (filePath == testPath) {
-						testFileFound = true;
-						break;
+						if (filePath == testPath) {
+							testFileFound = true;
+							break;
 					}
 					if (!testFileFound)
 						throw new TomboySyncException (Catalog.GetString ("Could not read testfile."));
@@ -265,7 +265,7 @@ namespace Tomboy.Sync
 
 		private void SetUpMountPath ()
 		{
-			string notesPath = Tomboy.DefaultNoteManager.NoteDirectoryPath;
+			string notesPath = Services.NativeApplication.CacheDirectory;
 			mountPath = Path.Combine (notesPath, "sync-" + Id); // TODO: Best mount path name?
 		}
 
diff --git a/Tomboy/Synchronization/TomboySyncClient.cs b/Tomboy/Synchronization/TomboySyncClient.cs
index d85b46b..bf9cb21 100644
--- a/Tomboy/Synchronization/TomboySyncClient.cs
+++ b/Tomboy/Synchronization/TomboySyncClient.cs
@@ -20,12 +20,12 @@ namespace Tomboy.Sync
 		{
 			// TODO: Why doesn't OnChanged ever get fired?!
 			FileSystemWatcher w = new FileSystemWatcher ();
-			w.Path = Tomboy.DefaultNoteManager.NoteDirectoryPath;
+			w.Path = Services.NativeApplication.ConfigurationDirectory;
 			w.Filter = localManifestFileName;
 			w.Changed += OnChanged;
 
 			localManifestFilePath =
-			        Path.Combine (Tomboy.DefaultNoteManager.NoteDirectoryPath,
+			        Path.Combine (Services.NativeApplication.ConfigurationDirectory,
 			                      localManifestFileName);
 			Parse (localManifestFilePath);
 
diff --git a/Tomboy/Tomboy.cs b/Tomboy/Tomboy.cs
index 63e55b0..326c471 100644
--- a/Tomboy/Tomboy.cs
+++ b/Tomboy/Tomboy.cs
@@ -124,7 +124,7 @@ namespace Tomboy
 				RegisterSessionManagerRestart (
 				        Environment.GetEnvironmentVariable ("TOMBOY_WRAPPER_PATH"),
 				        args,
-				        new string [] { "TOMBOY_PATH=" + note_path  });
+				        new string [] { "TOMBOY_PATH=" + note_path  }); // TODO: Pass along XDG_*?
 				StartTrayIcon ();
 			}
 
@@ -143,10 +143,10 @@ namespace Tomboy
 			        override_path :
 			        Environment.GetEnvironmentVariable ("TOMBOY_PATH");
 			if (note_path == null)
-				note_path = Services.NativeApplication.ConfDir;
+				note_path = Services.NativeApplication.DataDirectory;
 
 			// Tilde expand
-			return note_path.Replace ("~", Environment.GetEnvironmentVariable ("HOME"));
+			return note_path.Replace ("~", Environment.GetEnvironmentVariable ("HOME")); // TODO: Wasted work
 		}
 
 		static void RegisterPanelAppletFactory ()
diff --git a/Tomboy/Utils.cs b/Tomboy/Utils.cs
index 1ed72d8..b074d74 100644
--- a/Tomboy/Utils.cs
+++ b/Tomboy/Utils.cs
@@ -953,4 +953,21 @@ namespace Tomboy
 			}
 		}
 	}
+
+	public static class IOUtils
+	{
+		/// <summary>
+		/// Recursively copy the directory specified by old_path to
+		/// new_path. Assumes that old_path is an existing directory
+		/// and new_path does not exist.
+		/// </summary>
+		public static void CopyDirectory (string old_path, string new_path)
+		{
+			Directory.CreateDirectory (new_path);
+			foreach (string file_path in Directory.GetFiles (old_path))
+				File.Copy (file_path, Path.Combine (new_path, Path.GetFileName (file_path)));
+			foreach (string dir_path in Directory.GetDirectories (old_path))
+				CopyDirectory (dir_path, Path.Combine (new_path, Path.GetFileName (dir_path)));
+		}
+	}
 }
diff --git a/Tomboy/WindowsApplication.cs b/Tomboy/WindowsApplication.cs
index 7b6c9cb..4bbb27b 100644
--- a/Tomboy/WindowsApplication.cs
+++ b/Tomboy/WindowsApplication.cs
@@ -29,19 +29,31 @@ using System.IO;
 
 namespace Tomboy
 {
-	// TODO: Rename to GtkApplication
 	public class WindowsApplication : INativeApplication
 	{
-		private string confDir;
-		
-		public WindowsApplication ()
+		private static string confDir;
+		private static string dataDir;
+		private static string cacheDir;
+		private static string logDir;
+		private const string tomboyDirName = "Tomboy";
+
+		static WindowsApplication ()
 		{
-			confDir = Path.Combine (
-				Environment.GetFolderPath (
-			        	Environment.SpecialFolder.ApplicationData),
-					"tomboy");
+			string appDataPath = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
+			                                   tomboyDirName);
+			string localAppDataPath = Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.LocalApplicationData),
+			                                        tomboyDirName);
+			dataDir = Path.Combine (appDataPath, "notes");
+			confDir = Path.Combine (appDataPath, "config");
+			cacheDir = Path.Combine (localAppDataPath, "cache");
+			logDir = localAppDataPath;
+
+			// NOTE: Other directories created on demand
+			//       (non-existence is an indicator that migration is needed)
+			if (!Directory.Exists (cacheDir))
+				Directory.CreateDirectory (cacheDir);
 		}
-		
+
 		#region INativeApplication implementation 
 		
 		public event EventHandler ExitingEvent;
@@ -73,11 +85,29 @@ namespace Tomboy
 			Gtk.Application.Run ();
 		}
 
-		public virtual string ConfDir
-		{
+		public string DataDirectory {
+			get { return dataDir; }
+		}
+
+		public string ConfigurationDirectory {
 			get { return confDir; }
 		}
 
+		public string CacheDirectory {
+			get { return cacheDir; }
+		}
+
+		public string LogDirectory {
+			get { return logDir; }
+		}
+
+		public string PreOneDotZeroNoteDirectory {
+			get {
+				return Path.Combine (Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
+				                     "tomboy");
+			}
+		}
+
 		public virtual void OpenUrl (string url, Gdk.Screen screen)
 		{
 			try {
diff --git a/Tomboy/XmlPreferencesClient.cs b/Tomboy/XmlPreferencesClient.cs
index 5f8d67c..d0a09a6 100644
--- a/Tomboy/XmlPreferencesClient.cs
+++ b/Tomboy/XmlPreferencesClient.cs
@@ -19,10 +19,22 @@ namespace Tomboy
 
 		public XmlPreferencesClient ()
 		{
-			fileName = Path.Combine (
-				Services.NativeApplication.ConfDir,
-				"prefs.xml");
+			string confDir = Services.NativeApplication.ConfigurationDirectory;
+			fileName = Path.Combine (confDir, "prefs.xml");
 			prefsDoc = new XmlDocument ();
+
+			// Migration from old location
+			// NOTE: Assumes this class is instantiated before
+			//       NoteManager performs its migration
+			if (!Directory.Exists (Services.NativeApplication.DataDirectory) &&
+			    !File.Exists (fileName) &&
+			    File.Exists (Path.Combine (Services.NativeApplication.PreOneDotZeroNoteDirectory, "prefs.xml"))) {
+				if (!Directory.Exists (confDir))
+					Directory.CreateDirectory (confDir);
+				File.Copy (Path.Combine (Services.NativeApplication.PreOneDotZeroNoteDirectory, "prefs.xml"),
+					   fileName);
+			}
+
 			if (File.Exists (fileName))
 				prefsDoc.Load (fileName);
 			events = new Dictionary<string, NotifyEventHandler> ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]