[tasque] Remove Application.cs



commit 421da0145a8d69a40e0def56cd5b8922f1931782
Author: Antonius Riha <antoniusriha gmail com>
Date:   Sat Dec 1 23:14:37 2012 +0100

    Remove Application.cs
    
    * All logic of Application.cs has been moved to
    NativeApplication.cs

 src/Addins/Backends/Dummy/DummyBackend.cs          |    7 +-
 .../Backends/Rtm/Gtk/RtmPreferencesWidget.cs       |  101 ++++----
 src/Addins/Backends/Rtm/RtmBackend.cs              |   53 +++--
 src/Addins/Backends/Sqlite/SqliteBackend.cs        |    7 +-
 src/Gtk.Tasque/AllCategory.cs                      |   10 +-
 src/Gtk.Tasque/AppIndicatorTray.cs                 |    2 +-
 src/Gtk.Tasque/Application.cs                      |  255 --------------------
 src/Gtk.Tasque/CompletedTaskGroup.cs               |    6 +-
 src/Gtk.Tasque/Gtk.Tasque.csproj                   |    4 -
 src/Gtk.Tasque/GtkApplicationBase.cs               |  107 ++++++++-
 src/Gtk.Tasque/GtkLinuxApplication.cs              |    2 +-
 src/Gtk.Tasque/GtkTray.cs                          |   45 ++--
 src/Gtk.Tasque/PreferencesDialog.cs                |   35 ++--
 src/Gtk.Tasque/RemoteControl.cs                    |   31 ++-
 src/Gtk.Tasque/StatusIconTray.cs                   |    2 +-
 src/Gtk.Tasque/TaskGroup.cs                        |   10 +-
 src/Gtk.Tasque/TaskTreeView.cs                     |   26 +-
 src/Gtk.Tasque/TaskWindow.cs                       |  100 ++++----
 .../CompletedTaskGroupModel.cs                     |    0
 src/libtasque/IBackend.cs                          |    2 +-
 src/libtasque/INativeApplication.cs                |    6 +
 src/libtasque/NativeApplication.cs                 |   62 ++++-
 src/{Gtk.Tasque => libtasque}/TaskGroupModel.cs    |    0
 .../TaskGroupModelFactory.cs                       |    0
 src/libtasque/libtasque.csproj                     |    3 +
 src/tasque/Program.cs                              |   23 +-
 26 files changed, 413 insertions(+), 486 deletions(-)
---
diff --git a/src/Addins/Backends/Dummy/DummyBackend.cs b/src/Addins/Backends/Dummy/DummyBackend.cs
index 7eb5c3f..8c83477 100644
--- a/src/Addins/Backends/Dummy/DummyBackend.cs
+++ b/src/Addins/Backends/Dummy/DummyBackend.cs
@@ -119,14 +119,17 @@ namespace Tasque.Backends.Dummy
 		public void Refresh()
 		{}
 		
-		public void Initialize()
+		public void Initialize (Preferences preferences)
 		{
+			if (preferences == null)
+				throw new ArgumentNullException ("preferences");
+
 			Gtk.TreeIter iter;
 			
 			//
 			// Add in the "All" Category
 			//
-			AllCategory allCategory = new Tasque.AllCategory ();
+			AllCategory allCategory = new Tasque.AllCategory (preferences);
 			iter = categoryListStore.Append ();
 			categoryListStore.SetValue (iter, 0, allCategory);
 			
diff --git a/src/Addins/Backends/Rtm/Gtk/RtmPreferencesWidget.cs b/src/Addins/Backends/Rtm/Gtk/RtmPreferencesWidget.cs
index 45387b7..da9912c 100644
--- a/src/Addins/Backends/Rtm/Gtk/RtmPreferencesWidget.cs
+++ b/src/Addins/Backends/Rtm/Gtk/RtmPreferencesWidget.cs
@@ -2,6 +2,7 @@
 // User: boyd at 11:29 PMÂ2/18/2008
 
 using System;
+using System.Diagnostics;
 using Gtk;
 using Mono.Unix;
 
@@ -9,6 +10,9 @@ namespace Tasque.Backends.RtmBackend
 {
 	public class RtmPreferencesWidget : Gtk.EventBox, IBackendPreferences
 	{
+		Preferences preferences;
+		RtmBackend backend;
+
  		private LinkButton		authButton;
 		
 		private Label			statusLabel;
@@ -23,8 +27,15 @@ namespace Tasque.Backends.RtmBackend
 			normalPixbuf = Utilities.GetIcon ("tasque-rtm-logo", 128);
 		}
 		
-		public RtmPreferencesWidget () : base ()
+		public RtmPreferencesWidget (RtmBackend backend, Preferences preferences) : base ()
 		{
+			if (backend == null)
+				throw new ArgumentNullException ("backend");
+			if (preferences == null)
+				throw new ArgumentNullException ("preferences");
+			this.backend = backend;
+			this.preferences = preferences;
+
 			LoadPreferences ();
 			
 			BorderWidth = 0;
@@ -69,7 +80,7 @@ namespace Tasque.Backends.RtmBackend
 			if ( isAuthorized ) {
 				statusLabel.Text = "\n\n" +
 					Catalog.GetString ("You are currently connected");
-				string userName = Application.Preferences.Get (Preferences.UserNameKey);
+				string userName = preferences.Get (Preferences.UserNameKey);
 				if (userName != null && userName.Trim () != string.Empty)
 					statusLabel.Text = "\n\n" +
 						Catalog.GetString ("You are currently connected as") +
@@ -89,7 +100,7 @@ namespace Tasque.Backends.RtmBackend
 		
 		private void LoadPreferences ()
 		{
-			string authToken = Tasque.Application.Preferences.Get(Preferences.AuthTokenKey);
+			string authToken = preferences.Get(Preferences.AuthTokenKey);
 			if (authToken == null || authToken.Trim() == "") {
 				Logger.Debug("Rtm: Not authorized");
 				isAuthorized = false;
@@ -101,52 +112,48 @@ namespace Tasque.Backends.RtmBackend
 		
 		private void OnAuthButtonClicked (object sender, EventArgs args)
 		{
-			RtmBackend rtmBackend = Application.Backend as RtmBackend;
-			if (rtmBackend != null) {
-				if (!isAuthorized && !authRequested) {
-					string url = string.Empty;
-					try {
-						url = rtmBackend.GetAuthUrl();
-					} catch (Exception) {
-						Logger.Debug ("Failed to get auth URL from Remember the Milk. Try again later.");
-						authButton.Label = Catalog.GetString ("Remember the Milk not responding. Try again later.");
-						return;
-					}
-					Logger.Debug("Launching browser to authorize with Remember the Milk");
-					try {
-						Application.Instance.NativeApplication.OpenUrl (url);
-						authRequested = true;
-						authButton.Label = Catalog.GetString ("Click Here After Authorizing");
-					} catch (Exception ex) {
-						Logger.Error ("Exception opening URL: {0}",ex.Message);
-						authButton.Label = Catalog.GetString ("Set the default browser and try again");						
-					}			
-				} else if (!isAuthorized && authRequested) {
-					authButton.Label = Catalog.GetString ("Processing...");
-					try {
-						rtmBackend.FinishedAuth();
-						Logger.Debug("Successfully authorized with Remember the Milk");
-						isAuthorized = true;
-						authRequested = false;
-					} catch (RtmNet.RtmApiException) {
-						Logger.Debug("Failed to authorize with Remember the Milk");
-						isAuthorized = false;
-						authRequested = true;
-						authButton.Label = Catalog.GetString ("Failed, Try Again");
-					}
+			if (!isAuthorized && !authRequested) {
+				string url = string.Empty;
+				try {
+					url = backend.GetAuthUrl ();
+				} catch (Exception) {
+					Logger.Debug ("Failed to get auth URL from Remember the Milk. Try again later.");
+					authButton.Label = Catalog.GetString ("Remember the Milk not responding. Try again later.");
+					return;
 				}
-				if (isAuthorized) {
-					authButton.Label = Catalog.GetString ("Thank You");
-					authButton.Sensitive = false;
-					statusLabel.Text = "\n\n" +
-						Catalog.GetString ("You are currently connected");
-					string userName =
-						Application.Preferences.Get(Preferences.UserNameKey);
-					if (userName != null && userName.Trim() != string.Empty)
-						statusLabel.Text = "\n\n" +
-							Catalog.GetString ("You are currently connected as") +
-							"\n" + userName.Trim();
+				Logger.Debug ("Launching browser to authorize with Remember the Milk");
+				try {
+					Process.Start (url);
+					authRequested = true;
+					authButton.Label = Catalog.GetString ("Click Here After Authorizing");
+				} catch (Exception ex) {
+					Logger.Error ("Exception opening URL: {0}", ex.Message);
+					authButton.Label = Catalog.GetString ("Set the default browser and try again");
 				}
+			} else if (!isAuthorized && authRequested) {
+				authButton.Label = Catalog.GetString ("Processing...");
+				try {
+					backend.FinishedAuth ();
+					Logger.Debug ("Successfully authorized with Remember the Milk");
+					isAuthorized = true;
+					authRequested = false;
+				} catch (RtmNet.RtmApiException) {
+					Logger.Debug ("Failed to authorize with Remember the Milk");
+					isAuthorized = false;
+					authRequested = true;
+					authButton.Label = Catalog.GetString ("Failed, Try Again");
+				}
+			}
+			if (isAuthorized) {
+				authButton.Label = Catalog.GetString ("Thank You");
+				authButton.Sensitive = false;
+				statusLabel.Text = "\n\n" +
+					Catalog.GetString ("You are currently connected");
+				string userName = preferences.Get (Preferences.UserNameKey);
+				if (userName != null && userName.Trim () != string.Empty)
+					statusLabel.Text = "\n\n" +
+						Catalog.GetString ("You are currently connected as") +
+						"\n" + userName.Trim ();
 			}
 		}
 	}
diff --git a/src/Addins/Backends/Rtm/RtmBackend.cs b/src/Addins/Backends/Rtm/RtmBackend.cs
index dd448d2..380a7c8 100644
--- a/src/Addins/Backends/Rtm/RtmBackend.cs
+++ b/src/Addins/Backends/Rtm/RtmBackend.cs
@@ -15,6 +15,8 @@ namespace Tasque.Backends.RtmBackend
 {
 	public class RtmBackend : IBackend
 	{
+		Preferences preferences;
+
 		private const string apiKey = "b29f7517b6584035d07df3170b80c430";
 		private const string sharedSecret = "93eb5f83628b2066";
 		private Gtk.TreeStore taskStore;
@@ -69,18 +71,6 @@ namespace Tasque.Backends.RtmBackend
 			sortedCategoriesModel = new Gtk.TreeModelSort (categoryListStore);
 			sortedCategoriesModel.SetSortFunc (0, new Gtk.TreeIterCompareFunc (CompareCategorySortFunc));
 			sortedCategoriesModel.SetSortColumnId (0, Gtk.SortType.Ascending);
-
-			// make sure we have the all Category in our list
-			Gtk.Application.Invoke ( delegate {
-				AllCategory allCategory = new Tasque.AllCategory ();
-				Gtk.TreeIter iter = categoryListStore.Append ();
-				categoryListStore.SetValue (iter, 0, allCategory);				
-			});
-
-			runRefreshEvent = new AutoResetEvent(false);
-			
-			runningRefreshThread = false;
-			refreshThread  = new Thread(RefreshThreadLoop);
 		}
 
 		#region Public Properties
@@ -131,7 +121,7 @@ namespace Tasque.Backends.RtmBackend
 			get { return initialized; }
 		}
 		
-		public IBackendPreferences Preferences { get { return new RtmPreferencesWidget (); } }
+		public IBackendPreferences Preferences { get { return new RtmPreferencesWidget (this, preferences); } }
 		
 #endregion // Public Properties
 
@@ -205,13 +195,28 @@ namespace Tasque.Backends.RtmBackend
 			Logger.Debug("Done refreshing data!");
 		}
 
-		public void Initialize()
+		public void Initialize (Preferences preferences)
 		{
+			if (preferences == null)
+				throw new ArgumentNullException ("preferences");
+			this.preferences = preferences;
+
+			// make sure we have the all Category in our list
+			Gtk.Application.Invoke ( delegate {
+				AllCategory allCategory = new Tasque.AllCategory (preferences);
+				Gtk.TreeIter iter = categoryListStore.Append ();
+				categoryListStore.SetValue (iter, 0, allCategory);
+			});
+			
+			runRefreshEvent = new AutoResetEvent(false);
+			
+			runningRefreshThread = false;
+			refreshThread  = new Thread(RefreshThreadLoop);
+
 			// *************************************
 			// AUTHENTICATION to Remember The Milk
 			// *************************************
-			string authToken =
-				Application.Preferences.Get (Tasque.Preferences.AuthTokenKey);
+			string authToken = preferences.Get (Tasque.Preferences.AuthTokenKey);
 			if (authToken != null ) {
 				Logger.Debug("Found AuthToken, checking credentials...");
 				try {
@@ -223,9 +228,9 @@ namespace Tasque.Backends.RtmBackend
 					configured = true;
 				} catch (RtmNet.RtmApiException e) {
 					
-					Application.Preferences.Set (Tasque.Preferences.AuthTokenKey, null);
-					Application.Preferences.Set (Tasque.Preferences.UserIdKey, null);
-					Application.Preferences.Set (Tasque.Preferences.UserNameKey, null);
+					preferences.Set (Tasque.Preferences.AuthTokenKey, null);
+					preferences.Set (Tasque.Preferences.UserIdKey, null);
+					preferences.Set (Tasque.Preferences.UserNameKey, null);
 					rtm = null;
 					rtmAuth = null;
 					Logger.Error("Exception authenticating, reverting" + e.Message);
@@ -289,16 +294,14 @@ namespace Tasque.Backends.RtmBackend
 		{
 			rtmAuth = rtm.AuthGetToken(frob);
 			if (rtmAuth != null) {
-				Preferences prefs = Application.Preferences;
-				prefs.Set (Tasque.Preferences.AuthTokenKey, rtmAuth.Token);
+				preferences.Set (Tasque.Preferences.AuthTokenKey, rtmAuth.Token);
 				if (rtmAuth.User != null) {
-					prefs.Set (Tasque.Preferences.UserNameKey, rtmAuth.User.Username);
-					prefs.Set (Tasque.Preferences.UserIdKey, rtmAuth.User.UserId);
+					preferences.Set (Tasque.Preferences.UserNameKey, rtmAuth.User.Username);
+					preferences.Set (Tasque.Preferences.UserIdKey, rtmAuth.User.UserId);
 				}
 			}
 			
-			string authToken =
-				Application.Preferences.Get (Tasque.Preferences.AuthTokenKey);
+			string authToken = preferences.Get (Tasque.Preferences.AuthTokenKey);
 			if (authToken != null ) {
 				Logger.Debug("Found AuthToken, checking credentials...");
 				try {
diff --git a/src/Addins/Backends/Sqlite/SqliteBackend.cs b/src/Addins/Backends/Sqlite/SqliteBackend.cs
index cd41d1a..6c6d50d 100644
--- a/src/Addins/Backends/Sqlite/SqliteBackend.cs
+++ b/src/Addins/Backends/Sqlite/SqliteBackend.cs
@@ -131,8 +131,11 @@ namespace Tasque.Backends.Sqlite
 		public void Refresh()
 		{}
 		
-		public void Initialize()
+		public void Initialize (Preferences preferences)
 		{
+			if (preferences == null)
+				throw new ArgumentNullException ("preferences");
+
 			if(db == null)
 				db = new Database();
 				
@@ -141,7 +144,7 @@ namespace Tasque.Backends.Sqlite
 			//
 			// Add in the "All" Category
 			//
-			AllCategory allCategory = new Tasque.AllCategory ();
+			AllCategory allCategory = new Tasque.AllCategory (preferences);
 			Gtk.TreeIter iter = categoryListStore.Append ();
 			categoryListStore.SetValue (iter, 0, allCategory);
 			
diff --git a/src/Gtk.Tasque/AllCategory.cs b/src/Gtk.Tasque/AllCategory.cs
index 0e5505b..1197f77 100644
--- a/src/Gtk.Tasque/AllCategory.cs
+++ b/src/Gtk.Tasque/AllCategory.cs
@@ -14,13 +14,17 @@ namespace Tasque
 		// from all categories will be shown.  Otherwise, only tasks from the
 		// specified lists will be shown.
 		List<string> categoriesToHide;
+
+		Preferences preferences;
 		
-		public AllCategory ()
+		public AllCategory (Preferences preferences)
 		{
-			Preferences preferences = Application.Preferences;
+			if (preferences == null)
+				throw new ArgumentNullException ("preferences");
+			this.preferences = preferences;
 			categoriesToHide =
 				preferences.GetStringList (Preferences.HideInAllCategory);
-			Application.Preferences.SettingChanged += OnSettingChanged;
+			preferences.SettingChanged += OnSettingChanged;
 		}
 		
 		public string Name
diff --git a/src/Gtk.Tasque/AppIndicatorTray.cs b/src/Gtk.Tasque/AppIndicatorTray.cs
index cdb47ab..d724345 100644
--- a/src/Gtk.Tasque/AppIndicatorTray.cs
+++ b/src/Gtk.Tasque/AppIndicatorTray.cs
@@ -30,7 +30,7 @@ namespace Tasque
 {
 	public class AppIndicatorTray : GtkTray
 	{
-		public AppIndicatorTray ()
+		public AppIndicatorTray (INativeApplication application) : base  (application)
 		{
 			appIndicator = new ApplicationIndicator ("TasqueTray", IconName, Category.ApplicationStatus);
 			appIndicator.Status = Status.Active;
diff --git a/src/Gtk.Tasque/CompletedTaskGroup.cs b/src/Gtk.Tasque/CompletedTaskGroup.cs
index 9b0b0df..4bcd71d 100644
--- a/src/Gtk.Tasque/CompletedTaskGroup.cs
+++ b/src/Gtk.Tasque/CompletedTaskGroup.cs
@@ -26,9 +26,9 @@ namespace Tasque
 		ShowCompletedRange currentRange;
 		
 		public CompletedTaskGroup (string groupName, DateTime rangeStart,
-								   DateTime rangeEnd, Gtk.TreeModel tasks)
+								   DateTime rangeEnd, Gtk.TreeModel tasks, INativeApplication application)
 			: base (groupName, rangeStart, rangeEnd,
-					new CompletedTasksSortModel(tasks))
+					new CompletedTasksSortModel(tasks), application)
 		{
 			// Don't hide this group when it's empty because then the range
 			// slider won't appear and the user won't be able to customize the
@@ -36,7 +36,7 @@ namespace Tasque
 			this.HideWhenEmpty = false;
 			
 			selectedCategory = GetSelectedCategory ();
-			Application.Preferences.SettingChanged += OnSelectedCategorySettingChanged;
+			application.Preferences.SettingChanged += OnSelectedCategorySettingChanged;
 			
 			CreateRangeSlider ();
 			UpdateDateRanges ();
diff --git a/src/Gtk.Tasque/Gtk.Tasque.csproj b/src/Gtk.Tasque/Gtk.Tasque.csproj
index 39ed652..2430b6f 100644
--- a/src/Gtk.Tasque/Gtk.Tasque.csproj
+++ b/src/Gtk.Tasque/Gtk.Tasque.csproj
@@ -86,10 +86,8 @@
     <Compile Condition=" '$(AppIndicator)' != '' " Include="AppIndicatorTray.cs" />
     <Compile Include="AbstractTask.cs" />
     <Compile Include="AllCategory.cs" />
-    <Compile Include="Application.cs" />
     <Compile Include="CellRendererDate.cs" />
     <Compile Include="CompletedTaskGroup.cs" />
-    <Compile Include="CompletedTaskGroupModel.cs" />
     <Compile Include="DateButton.cs" />
     <Compile Include="NoteDialog.cs" />
     <Compile Include="NoteWidget.cs" />
@@ -97,8 +95,6 @@
     <Compile Include="PreferencesDialog.cs" />
     <Compile Include="TaskCalendar.cs" />
     <Compile Include="TaskGroup.cs" />
-    <Compile Include="TaskGroupModel.cs" />
-    <Compile Include="TaskGroupModelFactory.cs" />
     <Compile Include="TaskTreeView.cs" />
     <Compile Include="TaskWindow.cs" />
     <Compile Include="Utilities.cs" />
diff --git a/src/Gtk.Tasque/GtkApplicationBase.cs b/src/Gtk.Tasque/GtkApplicationBase.cs
index 6702c65..10d829e 100644
--- a/src/Gtk.Tasque/GtkApplicationBase.cs
+++ b/src/Gtk.Tasque/GtkApplicationBase.cs
@@ -33,8 +33,8 @@ using Gtk;
 namespace Tasque
 {
 	public abstract class GtkApplicationBase : NativeApplication
-	{		
-		public GtkApplicationBase ()
+	{
+		protected GtkApplicationBase ()
 		{
 			confDir = Path.Combine (Environment.GetFolderPath (
 				Environment.SpecialFolder.ApplicationData), "tasque");
@@ -57,20 +57,25 @@ namespace Tasque
 				InitializeIdle ();
 				return false;
 			});
+
+			GLib.Timeout.Add (60000, delegate {
+				CheckForDaySwitch ();
+				return true;
+			});
 			
 			base.OnInitialize ();
 		}
 		
 		protected override void OnInitializeIdle ()
 		{
-			trayIcon = GtkTray.CreateTray ();
+			trayIcon = GtkTray.CreateTray (this);
 			
 			if (Backend == null) {
 				// Pop open the preferences dialog so the user can choose a
 				// backend service to use.
 				ShowPreferences ();
 			} else if (!QuietStart)
-				TaskWindow.ShowWindow ();
+				TaskWindow.ShowWindow (this);
 			
 			if (Backend == null || !Backend.Configured) {
 				GLib.Timeout.Add (1000, new GLib.TimeoutHandler (delegate {
@@ -91,12 +96,22 @@ namespace Tasque
 		{
 			Gtk.Application.Quit ();
 		}
+
+#if ENABLE_NOTIFY_SHARP
+		public static void ShowAppNotification(Notification notification)
+		{
+			// TODO: Use this API for newer versions of notify-sharp
+			//notification.AttachToStatusIcon(
+			//		Tasque.Application.Instance.trayIcon);
+			notification.Show();
+		}
+#endif
 		
-		public void ShowPreferences ()
+		public override void ShowPreferences ()
 		{
 			Logger.Info ("OnPreferences called");
 			if (preferencesDialog == null) {
-				preferencesDialog = new PreferencesDialog ();
+				preferencesDialog = new PreferencesDialog (this);
 				preferencesDialog.Hidden += OnPreferencesDialogHidden;
 			}
 			
@@ -113,13 +128,13 @@ namespace Tasque
 		protected override void OnBackendChanged ()
 		{
 			if (backendWasNullBeforeChange)
-				TaskWindow.Reinitialize (!QuietStart);
+				TaskWindow.Reinitialize (!QuietStart, this);
 			else
-				TaskWindow.Reinitialize (true);
+				TaskWindow.Reinitialize (true, this);
 			
 			Debug.WriteLine ("Configuration status: {0}", Backend.Configured.ToString ());
 			
-			Application.Instance.RebuildTooltipTaskGroupModels ();
+			RebuildTooltipTaskGroupModels ();
 			if (trayIcon != null)
 				trayIcon.RefreshTrayIconTooltip ();
 			
@@ -129,13 +144,35 @@ namespace Tasque
 		protected override void OnBackendChanging ()
 		{
 			if (Backend != null)
-				Application.Instance.UnhookFromTooltipTaskGroupModels ();
+				UnhookFromTooltipTaskGroupModels ();
 			
 			backendWasNullBeforeChange = Backend == null;
 			
 			base.OnBackendChanging ();
 		}
-		
+
+		protected override void OnDaySwitched ()
+		{
+			// Reinitialize window according to new date
+			if (TaskWindow.IsOpen)
+				TaskWindow.Reinitialize (true, this);
+			
+			UnhookFromTooltipTaskGroupModels ();
+			RebuildTooltipTaskGroupModels ();
+			if (trayIcon != null)
+				trayIcon.RefreshTrayIconTooltip ();
+		}
+
+		protected override void OnQuitting ()
+		{
+			if (Backend != null)
+				UnhookFromTooltipTaskGroupModels ();
+			
+			TaskWindow.SavePosition (Preferences);
+			
+			base.OnQuitting ();
+		}
+
 		public override void OpenUrl (string url)
 		{
 			try {
@@ -147,7 +184,7 @@ namespace Tasque
 		
 		protected override void ShowMainWindow ()
 		{
-			TaskWindow.ShowWindow ();
+			TaskWindow.ShowWindow (this);
 		}
 		
 		protected override event EventHandler RemoteInstanceKnocked;
@@ -157,6 +194,52 @@ namespace Tasque
 			if (RemoteInstanceKnocked != null)
 				RemoteInstanceKnocked (this, EventArgs.Empty);
 		}
+
+		void OnTooltipModelChanged (object o, EventArgs args)
+		{
+			if (trayIcon != null)
+				trayIcon.RefreshTrayIconTooltip ();
+		}
+
+		void RebuildTooltipTaskGroupModels ()
+		{
+			if (Backend == null || Backend.Tasks == null) {
+				OverdueTasks = null;
+				TodayTasks = null;
+				TomorrowTasks = null;
+				
+				return;
+			}
+			
+			OverdueTasks = TaskGroupModelFactory.CreateOverdueModel (Backend.Tasks);
+			TodayTasks = TaskGroupModelFactory.CreateTodayModel (Backend.Tasks);
+			TomorrowTasks = TaskGroupModelFactory.CreateTomorrowModel (Backend.Tasks);
+			
+			foreach (TaskGroupModel model in new TaskGroupModel[] { OverdueTasks, TodayTasks, TomorrowTasks })
+			{
+				if (model == null) {
+					continue;
+				}
+				
+				model.RowInserted += OnTooltipModelChanged;
+				model.RowChanged += OnTooltipModelChanged;
+				model.RowDeleted += OnTooltipModelChanged;
+			}
+		}
+
+		void UnhookFromTooltipTaskGroupModels ()
+		{
+			foreach (TaskGroupModel model in new TaskGroupModel[] { OverdueTasks, TodayTasks, TomorrowTasks })
+			{
+				if (model == null) {
+					continue;
+				}
+				
+				model.RowInserted -= OnTooltipModelChanged;
+				model.RowChanged -= OnTooltipModelChanged;
+				model.RowDeleted -= OnTooltipModelChanged;
+			}
+		}
 		
 		internal GtkTray TrayIcon { get { return trayIcon; } }
 		
diff --git a/src/Gtk.Tasque/GtkLinuxApplication.cs b/src/Gtk.Tasque/GtkLinuxApplication.cs
index 5a92c06..3157f0c 100644
--- a/src/Gtk.Tasque/GtkLinuxApplication.cs
+++ b/src/Gtk.Tasque/GtkLinuxApplication.cs
@@ -42,7 +42,7 @@ namespace Tasque
 		{
 			// Register Tasque RemoteControl
 			try {
-				remoteInstance = RemoteControl.Register ();
+				remoteInstance = RemoteControl.Register (this);
 				if (remoteInstance != null) {
 					remoteInstance.RemoteInstanceKnocked = OnRemoteInstanceKnocked;
 					Logger.Debug ("Tasque remote control created.");
diff --git a/src/Gtk.Tasque/GtkTray.cs b/src/Gtk.Tasque/GtkTray.cs
index 27c4deb..3801bea 100644
--- a/src/Gtk.Tasque/GtkTray.cs
+++ b/src/Gtk.Tasque/GtkTray.cs
@@ -33,7 +33,7 @@ namespace Tasque
 {
 	public abstract class GtkTray : IDisposable
 	{
-		public static GtkTray CreateTray ()
+		public static GtkTray CreateTray (INativeApplication application)
 		{
 			var desktopSession = Environment.GetEnvironmentVariable ("DESKTOP_SESSION");
 			GtkTray tray;
@@ -43,29 +43,34 @@ namespace Tasque
 			case "gnome-classic":
 			case "gnome-fallback":
 #if APPINDICATOR
-				tray = new AppIndicatorTray ();
+				tray = new AppIndicatorTray (application);
 				break;
 #endif
 			default:
-				tray = new StatusIconTray ();
+				tray = new StatusIconTray (application);
 				break;
 			}
 			return tray;
 		}
 
-		protected GtkTray ()
+		protected GtkTray (INativeApplication application)
 		{
+			if (application == null)
+				throw new ArgumentNullException ("application");
+			this.application = application;
+
 			UpdateBackend ();
-			Application.Instance.BackendChanged += HandleBackendChanged;
+			application.BackendChanged += HandleBackendChanged;
 			RefreshTrayIconTooltip ();
 		}
 
 		#region IDisposable implementation
 		public void Dispose ()
 		{
-			var app = Application.Instance;
-			if (app != null)
-				app.BackendChanged -= HandleBackendChanged;
+			if (disposed)
+				return;
+			application.BackendChanged -= HandleBackendChanged;
+			disposed = true;
 		}
 		#endregion
 		
@@ -74,7 +79,7 @@ namespace Tasque
 			var oldTooltip = Tooltip;
 			var sb = new StringBuilder ();
 			
-			var overdueTasks = Application.Instance.OverdueTasks;
+			var overdueTasks = application.OverdueTasks;
 			if (overdueTasks != null) {
 				int count = overdueTasks.IterNChildren ();
 
@@ -83,7 +88,7 @@ namespace Tasque
 				}
 			}
 			
-			var todayTasks = Application.Instance.TodayTasks;
+			var todayTasks = application.TodayTasks;
 			if (todayTasks != null) {
 				int count = todayTasks.IterNChildren ();
 
@@ -92,7 +97,7 @@ namespace Tasque
 				}
 			}
 			
-			var tomorrowTasks = Application.Instance.TomorrowTasks;
+			var tomorrowTasks = application.TomorrowTasks;
 			if (tomorrowTasks != null) {
 				int count = tomorrowTasks.IterNChildren ();
 
@@ -166,23 +171,23 @@ namespace Tasque
 			trayActionGroup.Add (new ActionEntry [] {
 				new ActionEntry ("NewTaskAction", Stock.New, Catalog.GetString ("New Task ..."), null, null, delegate {
 					// Show the TaskWindow and then cause a new task to be created
-					TaskWindow.ShowWindow ();
-					TaskWindow.GrabNewTaskEntryFocus ();
+					TaskWindow.ShowWindow (application);
+					TaskWindow.GrabNewTaskEntryFocus (application);
 				}),
 
 				new ActionEntry ("AboutAction", Stock.About, OnAbout),
 
-				new ActionEntry ("PreferencesAction", Stock.Preferences, delegate { Application.ShowPreferences (); }),
+				new ActionEntry ("PreferencesAction", Stock.Preferences, delegate { application.ShowPreferences (); }),
 
 				new ActionEntry ("RefreshAction", Stock.Execute, Catalog.GetString ("Refresh Tasks ..."),
-				                 null, null, delegate { Application.Backend.Refresh(); }),
+				                 null, null, delegate { application.Backend.Refresh(); }),
 
-				new ActionEntry ("QuitAction", Stock.Quit, delegate { Application.Instance.Quit (); })
+				new ActionEntry ("QuitAction", Stock.Quit, delegate { application.Quit (); })
 			});
 			
 			ToggleTaskWindowAction = new Gtk.Action ("ToggleTaskWindowAction", Catalog.GetString ("Toggle Task Window"));
 			ToggleTaskWindowAction.ActionGroup = trayActionGroup;
-			ToggleTaskWindowAction.Activated += delegate { TaskWindow.ToggleWindowVisible (); };
+			ToggleTaskWindowAction.Activated += delegate { TaskWindow.ToggleWindowVisible (application); };
 			
 			uiManager = new UIManager ();
 			uiManager.AddUiFromString (MenuXml);
@@ -191,7 +196,7 @@ namespace Tasque
 
 		void UpdateActionSensitivity ()
 		{
-			var backend = Application.Backend;
+			var backend = application.Backend;
 			var backendItemsSensitive = (backend != null && backend.Initialized);
 			
 			if (uiManager == null)
@@ -205,7 +210,7 @@ namespace Tasque
 		{
 			if (backend != null)
 				backend.BackendInitialized -= HandleBackendInitialized;
-			backend = Application.Backend;
+			backend = application.Backend;
 
 			if (backend != null)
 				backend.BackendInitialized += HandleBackendInitialized;
@@ -213,7 +218,9 @@ namespace Tasque
 			UpdateActionSensitivity ();
 		}
 
+		INativeApplication application;
 		IBackend backend;
+		bool disposed;
 		UIManager uiManager;
 		const string MenuXml = @"
 <ui>
diff --git a/src/Gtk.Tasque/PreferencesDialog.cs b/src/Gtk.Tasque/PreferencesDialog.cs
index 252d9dd..36ac198 100644
--- a/src/Gtk.Tasque/PreferencesDialog.cs
+++ b/src/Gtk.Tasque/PreferencesDialog.cs
@@ -38,6 +38,7 @@ namespace Tasque
 	public class PreferencesDialog : Gtk.Dialog
 	{
 //		private CheckButton		showCompletedTasksCheck;
+		INativeApplication application;
 		
 		Gtk.Notebook			notebook;
 		
@@ -69,8 +70,12 @@ namespace Tasque
 		Gtk.Widget				backendPage;
 		int						backendPageId;
 
-		public PreferencesDialog() : base ()
+		public PreferencesDialog (INativeApplication application) : base ()
 		{
+			if (application == null)
+				throw new ArgumentNullException ("application");
+			this.application = application;
+
 			LoadPreferences();
 			Init();
 			ConnectEvents();
@@ -129,12 +134,12 @@ namespace Tasque
 			backendPage = null;
 			backendPageId = -1;
 			
-			if (Application.Backend != null) {
-				backendPage = (Widget)Application.Backend.Preferences;
+			if (application.Backend != null) {
+				backendPage = (Widget)application.Backend.Preferences;
 				if (backendPage != null) {
 					backendPage.Show ();
 					Label l =
-						new Label (GLib.Markup.EscapeText (Application.Backend.Name));
+						new Label (GLib.Markup.EscapeText (application.Backend.Name));
 					l.UseMarkup = false;
 					l.UseUnderline = false;
 					l.Show ();
@@ -173,7 +178,7 @@ namespace Tasque
 			lblTodaysTaskColor.WidthRequest = 75;
 			lblTodaysTaskColor.Show ();
 
-			Preferences prefs = Application.Preferences;
+			Preferences prefs = application.Preferences;
 			txtTodaysTaskColor = new Entry();
 			txtTodaysTaskColor.Text = prefs.Get (Preferences.TodayTaskTextColor);
 			txtTodaysTaskColor.Changed += OnTxtTodaysTaskColorChanged;
@@ -254,10 +259,10 @@ namespace Tasque
 			// Fill out the ComboBox
 			int i = 0;
 			selectedBackend = -1;
-			foreach (IBackend backend in Application.AvailableBackends) {
+			foreach (IBackend backend in application.AvailableBackends) {
 				backendComboBox.AppendText (backend.Name);
 				backendComboMap [i] = backend;
-				if (backend == Application.Backend)
+				if (backend == application.Backend)
 					selectedBackend = i;
 				i++;
 			}
@@ -298,7 +303,7 @@ namespace Tasque
 			VBox innerSectionVBox = new VBox (false, 6);
 			hbox = new HBox (false, 6);
 			
-			bool showCompletedTasks = Application.Preferences.GetBool (
+			bool showCompletedTasks = application.Preferences.GetBool (
 											Preferences.ShowCompletedTasksKey);
 			showCompletedTasksCheckButton =
 				new CheckButton (Catalog.GetString ("Sh_ow completed tasks"));
@@ -375,7 +380,7 @@ namespace Tasque
 		{
 			Logger.Debug("Loading preferences");
 			categoriesToHide =
-				Application.Preferences.GetStringList (Preferences.HideInAllCategory);
+				application.Preferences.GetStringList (Preferences.HideInAllCategory);
 			//if (categoriesToHide == null || categoriesToHide.Count == 0)
 			//	categoriesToHide = BuildNewCategoryList ();
 		}
@@ -384,7 +389,7 @@ namespace Tasque
 		{
 			// showCompletedTasksCheckbox delegate
 			showCompletedTasksCheckButton.Toggled += delegate {
-				Application.Preferences.SetBool (
+				application.Preferences.SetBool (
 					Preferences.ShowCompletedTasksKey,
 					showCompletedTasksCheckButton.Active);
 			};
@@ -399,7 +404,7 @@ namespace Tasque
 		private void OnTxtTodaysTaskColorChanged (object sender, EventArgs args)
 		{
 			// Save the user preference
-			Application.Preferences.Set (Preferences.TodayTaskTextColor,
+			application.Preferences.Set (Preferences.TodayTaskTextColor,
 			                             ((Entry) sender).Text);
 		}
 
@@ -412,7 +417,7 @@ namespace Tasque
 		private void OnTxtOverdueTaskColorChanged (object sender, EventArgs args)
 		{
 			// Save the user preference
-			Application.Preferences.Set (Preferences.OverdueTaskTextColor,
+			application.Preferences.Set (Preferences.OverdueTaskTextColor,
 			                             ((Entry) sender).Text);
 		}
 
@@ -453,7 +458,7 @@ namespace Tasque
 			}
 			
 			// TODO: Set the new backend
-			Application.Backend = newBackend;
+			application.Backend = newBackend;
 			
 			if (newBackend == null)
 				return;
@@ -478,7 +483,7 @@ namespace Tasque
 			}
 			
 			// Save the user preference
-			Application.Preferences.Set (Preferences.CurrentBackend,
+			application.Preferences.Set (Preferences.CurrentBackend,
 										 newBackend.GetType ().ToString ());
 			
 			//categoriesToHide = BuildNewCategoryList ();
@@ -549,7 +554,7 @@ namespace Tasque
 			else
 				categoriesToHide.Add (category.Name);
 			
-			Application.Preferences.SetStringList (Preferences.HideInAllCategory,
+			application.Preferences.SetStringList (Preferences.HideInAllCategory,
 												   categoriesToHide);
 		}
 		
diff --git a/src/Gtk.Tasque/RemoteControl.cs b/src/Gtk.Tasque/RemoteControl.cs
index d4ffef9..5e92b2c 100644
--- a/src/Gtk.Tasque/RemoteControl.cs
+++ b/src/Gtk.Tasque/RemoteControl.cs
@@ -34,11 +34,11 @@ namespace Tasque
 			return Bus.Session.GetObject<RemoteControl> (Namespace, new ObjectPath (Path));
 		}
 		
-		public static RemoteControl Register ()
+		public static RemoteControl Register (INativeApplication application)
 		{
 			BusG.Init ();
 			
-			var remoteControl = new RemoteControl ();
+			var remoteControl = new RemoteControl (application);
 			Bus.Session.Register (new ObjectPath (Path), remoteControl);
 			
 			if (Bus.Session.RequestName (Namespace) != RequestNameReply.PrimaryOwner)
@@ -47,7 +47,12 @@ namespace Tasque
 			return remoteControl;
 		}
 		
-		RemoteControl () {}
+		RemoteControl (INativeApplication application)
+		{
+			if (application == null)
+				throw new ArgumentNullException ("application");
+			this.application = application;
+		}
 		
 		public void KnockKnock ()
 		{
@@ -111,7 +116,7 @@ namespace Tasque
 						bool enterEditMode, bool parseDate)
 		{
 			Gtk.TreeIter iter;
-			Gtk.TreeModel model = Application.Backend.Categories;
+			Gtk.TreeModel model = application.Backend.Categories;
 			
 			//
 			// Validate the input parameters.  Don't allow null or empty strings
@@ -145,14 +150,14 @@ namespace Tasque
 			// If enabled, attempt to parse due date information
 			// out of the taskName.
 			DateTime taskDueDate = DateTime.MinValue;
-			if (parseDate && Application.Preferences.GetBool (Preferences.ParseDateEnabledKey))
+			if (parseDate && application.Preferences.GetBool (Preferences.ParseDateEnabledKey))
 				TaskParser.Instance.TryParse (
 				                         taskName,
 				                         out taskName,
 				                         out taskDueDate);
 			ITask task = null;
 			try {
-				task = Application.Backend.CreateTask (taskName, category);
+				task = application.Backend.CreateTask (taskName, category);
 				if (taskDueDate != DateTime.MinValue)
 					task.DueDate = taskDueDate;
 			} catch (Exception e) {
@@ -165,7 +170,7 @@ namespace Tasque
 			}
 			
 			if (enterEditMode) {
-				TaskWindow.SelectAndEdit (task);
+				TaskWindow.SelectAndEdit (task, application);
 			}
 			
 			#if ENABLE_NOTIFY_SHARP
@@ -195,7 +200,7 @@ namespace Tasque
 			string[] emptyArray = categories.ToArray ();
 			
 			Gtk.TreeIter iter;
-			Gtk.TreeModel model = Application.Backend.Categories;
+			Gtk.TreeModel model = application.Backend.Categories;
 			
 			if (!model.GetIterFirst (out iter))
 				return emptyArray;
@@ -212,7 +217,7 @@ namespace Tasque
 		
 		public void ShowTasks ()
 		{
-			TaskWindow.ShowWindow ();
+			TaskWindow.ShowWindow (application);
 		}
 		
 		/// <summary>
@@ -231,7 +236,7 @@ namespace Tasque
 			List<string> ids;
 			
 			ids = new List<string> ();
-			model = Application.Backend.Tasks;
+			model = application.Backend.Tasks;
 			
 			if (!model.GetIterFirst (out iter))
 				return new string[0];
@@ -320,7 +325,7 @@ namespace Tasque
 				return false;
 			}
 			Gtk.TreeIter iter;
-			Gtk.TreeModel model = Application.Backend.Categories;
+			Gtk.TreeModel model = application.Backend.Categories;
 			
 			if (!model.GetIterFirst (out iter))
 				return false;
@@ -512,7 +517,7 @@ namespace Tasque
 			Gtk.TreeModel model;
 			
 			ITask task = null;
-			model = Application.Backend.Tasks;
+			model = application.Backend.Tasks;
 			
 			if (model.GetIterFirst (out iter)) {
 				do {
@@ -525,5 +530,7 @@ namespace Tasque
 			
 			return task;
 		}
+
+		INativeApplication application;
 	}
 }
diff --git a/src/Gtk.Tasque/StatusIconTray.cs b/src/Gtk.Tasque/StatusIconTray.cs
index 706ddb5..d379889 100644
--- a/src/Gtk.Tasque/StatusIconTray.cs
+++ b/src/Gtk.Tasque/StatusIconTray.cs
@@ -29,7 +29,7 @@ namespace Tasque
 {
 	public class StatusIconTray : GtkTray
 	{
-		public StatusIconTray ()
+		public StatusIconTray (INativeApplication application) : base  (application)
 		{
 			tray = new StatusIcon (Utilities.GetIcon (IconName, 24));
 			tray.Visible = true;
diff --git a/src/Gtk.Tasque/TaskGroup.cs b/src/Gtk.Tasque/TaskGroup.cs
index 7b0ac6e..122ea72 100644
--- a/src/Gtk.Tasque/TaskGroup.cs
+++ b/src/Gtk.Tasque/TaskGroup.cs
@@ -24,8 +24,12 @@ namespace Tasque
 		
 		#region Constructor
 		public TaskGroup (string groupName, DateTime rangeStart,
-						  DateTime rangeEnd, Gtk.TreeModel tasks)
+						  DateTime rangeEnd, Gtk.TreeModel tasks, INativeApplication application)
 		{
+			if (application == null)
+				throw new ArgumentNullException ("application");
+			Application = application;
+
 			hideWhenEmpty = true;
 						
 			// TODO: Add a date time event watcher so that when we rollover to
@@ -84,7 +88,7 @@ namespace Tasque
 			//
 			// Group TreeView
 			//
-			treeView = new TaskTreeView (filteredTasks);
+			treeView = new TaskTreeView (filteredTasks, application.Preferences);
 			treeView.Show ();
 			PackStart (treeView, true, true, 0);
 			
@@ -319,6 +323,8 @@ namespace Tasque
 		#endregion // Methods
 		
 		#region Private Methods
+		protected INativeApplication Application { get; private set; }
+
 		protected override void OnRealized ()
 		{
 			base.OnRealized ();
diff --git a/src/Gtk.Tasque/TaskTreeView.cs b/src/Gtk.Tasque/TaskTreeView.cs
index 4a87875..845fbda 100644
--- a/src/Gtk.Tasque/TaskTreeView.cs
+++ b/src/Gtk.Tasque/TaskTreeView.cs
@@ -14,6 +14,8 @@ namespace Tasque
 	/// </summary>
 	public class TaskTreeView : Gtk.TreeView
 	{
+		Preferences preferences;
+
 		private static Gdk.Pixbuf notePixbuf;
 		
 		private static Gdk.Pixbuf[] inactiveAnimPixbufs;
@@ -42,9 +44,12 @@ namespace Tasque
 			get { return taskBeingEdited; }
 		}
 
-		public TaskTreeView (Gtk.TreeModel model)
+		public TaskTreeView (Gtk.TreeModel model, Preferences preferences)
 			: base ()
-		{		
+		{
+			if (preferences == null)
+				throw new ArgumentNullException ("preferences");
+			this.preferences = preferences;
 
 			#if GTK_2_12
 			// set up the timing for the tooltips
@@ -443,9 +448,8 @@ namespace Tasque
 			
 			string formatString = "{0}";
 
-			Preferences prefs = Application.Preferences;
-			string todayTasksColor = prefs.Get (Preferences.TodayTaskTextColor);
-			string overdueTaskColor = prefs.Get (Preferences.OverdueTaskTextColor);
+			string todayTasksColor = preferences.Get (Preferences.TodayTaskTextColor);
+			string overdueTaskColor = preferences.Get (Preferences.OverdueTaskTextColor);
 
 			if (task.IsComplete)
 				; // Completed tasks colored below
@@ -526,9 +530,8 @@ namespace Tasque
 				crp.Pixbuf = null;
 				return;
 			}
-			
-			Preferences prefs = Application.Preferences;
-			int timerSeconds = prefs.GetInt (Preferences.InactivateTimeoutKey);
+
+			int timerSeconds = preferences.GetInt (Preferences.InactivateTimeoutKey);
 			// convert to milliseconds for more granularity
 			long timeout = timerSeconds * 1000;
 			
@@ -631,8 +634,7 @@ namespace Tasque
 			
 			if (task.State == TaskState.Active) {
 				bool showCompletedTasks =
-					Application.Preferences.GetBool (
-						Preferences.ShowCompletedTasksKey);
+					preferences.GetBool (Preferences.ShowCompletedTasksKey);
 				
 				// When showCompletedTasks is true, complete the tasks right
 				// away.  Otherwise, set a timer and show the timer animation
@@ -645,7 +647,7 @@ namespace Tasque
 					
 					// Read the inactivate timeout from a preference
 					int timeout =
-						Application.Preferences.GetInt (Preferences.InactivateTimeoutKey);
+						preferences.GetInt (Preferences.InactivateTimeoutKey);
 					Logger.Debug ("Read timeout from prefs: {0}", timeout);
 					InactivateTimer timer =
 						new InactivateTimer (this, iter, task, (uint) timeout);
@@ -695,7 +697,7 @@ namespace Tasque
 			string newText = args.NewText;
 			
 			// Attempt to derive due date information from text.
-			if (Application.Preferences.GetBool (Preferences.ParseDateEnabledKey) &&
+			if (preferences.GetBool (Preferences.ParseDateEnabledKey) &&
 			    task.State == TaskState.Active &&
 			    task.DueDate == DateTime.MinValue) {
 				
diff --git a/src/Gtk.Tasque/TaskWindow.cs b/src/Gtk.Tasque/TaskWindow.cs
index 49d6d11..8411656 100644
--- a/src/Gtk.Tasque/TaskWindow.cs
+++ b/src/Gtk.Tasque/TaskWindow.cs
@@ -40,6 +40,8 @@ namespace Tasque
 {
 	public class TaskWindow : Gtk.Window 
 	{
+		INativeApplication application;
+
 		private static TaskWindow taskWindow = null;
 		private static int lastXPos;
 		private static int lastYPos;
@@ -83,8 +85,12 @@ namespace Tasque
 			noteIcon = Utilities.GetIcon ("tasque-note", 16);
 		}
 		
-		public TaskWindow (IBackend aBackend) : base (Gtk.WindowType.Toplevel)
+		public TaskWindow (IBackend aBackend, INativeApplication application) : base (Gtk.WindowType.Toplevel)
 		{
+			if (application == null)
+				throw new ArgumentNullException ("application");
+			this.application = application;
+
 			this.backend = aBackend;
 			taskGroups = new List<TaskGroup> ();
 			noteDialogs = new Dictionary<ITask, NoteDialog> ();
@@ -102,8 +108,8 @@ namespace Tasque
 			// Update the window title
 			Title = string.Format ("Tasque");	
 
-			width = Application.Preferences.GetInt("MainWindowWidth");
-			height = Application.Preferences.GetInt("MainWindowHeight");
+			width = application.Preferences.GetInt("MainWindowWidth");
+			height = application.Preferences.GetInt("MainWindowHeight");
 			
 			if(width == -1)
 				width = 600;
@@ -183,7 +189,7 @@ namespace Tasque
 						Gtk.AccelFlags.Visible);
 			
 			globalKeys.AddAccelerator (delegate (object sender, EventArgs e) {
-				Application.Instance.Quit (); },
+				application.Quit (); },
 						(uint) Gdk.Key.q,
 						Gdk.ModifierType.ControlMask,
 						Gtk.AccelFlags.Visible);
@@ -237,7 +243,7 @@ namespace Tasque
 				OnBackendInitialized();
 			}
 			
-			Application.Preferences.SettingChanged += OnSettingChanged;
+			application.Preferences.SettingChanged += OnSettingChanged;
 		}
 
 		void PopulateWindow()
@@ -257,7 +263,7 @@ namespace Tasque
 			
 			overdueGroup = new TaskGroup (Catalog.GetString ("Overdue"),
 										  rangeStart, rangeEnd,
-										  backend.Tasks);
+										  backend.Tasks, application);
 			overdueGroup.RowActivated += OnRowActivated;
 			overdueGroup.ButtonPressed += OnButtonPressed;
 			overdueGroup.Show ();
@@ -275,7 +281,7 @@ namespace Tasque
 									 rangeEnd.Day, 23, 59, 59);
 			todayGroup = new TaskGroup (Catalog.GetString ("Today"),
 										rangeStart, rangeEnd,
-										backend.Tasks);
+										backend.Tasks, application);
 			todayGroup.RowActivated += OnRowActivated;
 			todayGroup.ButtonPressed += OnButtonPressed;
 			todayGroup.Show ();
@@ -293,7 +299,7 @@ namespace Tasque
 									 rangeEnd.Day, 23, 59, 59);
 			tomorrowGroup = new TaskGroup (Catalog.GetString ("Tomorrow"),
 										   rangeStart, rangeEnd,
-										   backend.Tasks);
+										   backend.Tasks, application);
 			tomorrowGroup.RowActivated += OnRowActivated;
 			tomorrowGroup.ButtonPressed += OnButtonPressed;			
 			tomorrowGroup.Show ();
@@ -311,7 +317,7 @@ namespace Tasque
 									 rangeEnd.Day, 23, 59, 59);
 			nextSevenDaysGroup = new TaskGroup (Catalog.GetString ("Next 7 Days"),
 										   rangeStart, rangeEnd,
-										   backend.Tasks);
+										   backend.Tasks, application);
 			nextSevenDaysGroup.RowActivated += OnRowActivated;
 			nextSevenDaysGroup.ButtonPressed += OnButtonPressed;				
 			nextSevenDaysGroup.Show ();
@@ -327,7 +333,7 @@ namespace Tasque
 			rangeEnd = DateTime.MaxValue;
 			futureGroup = new TaskGroup (Catalog.GetString ("Future"),
 										 rangeStart, rangeEnd,
-										 backend.Tasks);
+										 backend.Tasks, application);
 			futureGroup.RowActivated += OnRowActivated;
 			futureGroup.ButtonPressed += OnButtonPressed;			
 			futureGroup.Show ();
@@ -342,7 +348,7 @@ namespace Tasque
 			completedTaskGroup = new CompletedTaskGroup (
 					Catalog.GetString ("Completed"),
 					rangeStart, rangeEnd,
-					backend.Tasks);
+					backend.Tasks, application);
 			completedTaskGroup.RowActivated += OnRowActivated;
 			completedTaskGroup.ButtonPressed += OnButtonPressed;
 			completedTaskGroup.Show ();
@@ -357,11 +363,11 @@ namespace Tasque
 			
 			// Set up the combo box (after the above to set the current filter)
 
-			categoryComboBox.Model = Application.Backend.Categories;		
+			categoryComboBox.Model = application.Backend.Categories;		
 
 			// Read preferences for the last-selected category and select it
 			string selectedCategoryName =
-				Application.Preferences.Get (Preferences.SelectedCategoryKey);
+				application.Preferences.Get (Preferences.SelectedCategoryKey);
 			
 			categoryComboBox.Changed += OnCategoryChanged;
 			
@@ -373,15 +379,15 @@ namespace Tasque
 		/// <summary>
 		/// Method to allow other classes to "click" on the "Add Task" button.
 		/// </summary>
-		public static void AddTask ()
+		public static void AddTask (INativeApplication application)
 		{
 			if (taskWindow == null)
-				TaskWindow.ShowWindow ();
+				TaskWindow.ShowWindow (application);
 			
 			taskWindow.OnAddTask (null, EventArgs.Empty);
 		}
 
-		public static void SavePosition()
+		public static void SavePosition (Preferences preferences)
 		{
 			if(taskWindow != null) {
 				int x;
@@ -395,25 +401,25 @@ namespace Tasque
 				lastXPos = x;
 				lastYPos = y;
 				
-				Application.Preferences.SetInt("MainWindowLastXPos", lastXPos);
-				Application.Preferences.SetInt("MainWindowLastYPos", lastYPos);
-				Application.Preferences.SetInt("MainWindowWidth", width);
-				Application.Preferences.SetInt("MainWindowHeight", height);	
+				preferences.SetInt("MainWindowLastXPos", lastXPos);
+				preferences.SetInt("MainWindowLastYPos", lastYPos);
+				preferences.SetInt("MainWindowWidth", width);
+				preferences.SetInt("MainWindowHeight", height);	
 			}
 
 		}
 		
-		public static void ShowWindow ()
+		public static void ShowWindow (INativeApplication application)
 		{
-			ShowWindow (false);
+			ShowWindow (false, application);
 		}
 		
-		public static void ToggleWindowVisible ()
+		public static void ToggleWindowVisible (INativeApplication application)
 		{
-			ShowWindow (true);
+			ShowWindow (true, application);
 		}
 		
-		private static void ShowWindow(bool supportToggle)
+		private static void ShowWindow (bool supportToggle, INativeApplication application)
 		{
 			if(taskWindow != null) {
 				if(taskWindow.IsActive && supportToggle) {
@@ -436,12 +442,12 @@ namespace Tasque
 					}
 					taskWindow.Present();
 				}
-			} else if (Application.Backend != null) {
-				TaskWindow.taskWindow = new TaskWindow(Application.Backend);
+			} else if (application.Backend != null) {
+				TaskWindow.taskWindow = new TaskWindow (application.Backend, application);
 				if(lastXPos == 0 || lastYPos == 0)
 				{
-					lastXPos = Application.Preferences.GetInt("MainWindowLastXPos");
-					lastYPos = Application.Preferences.GetInt("MainWindowLastYPos");				
+					lastXPos = application.Preferences.GetInt("MainWindowLastXPos");
+					lastYPos = application.Preferences.GetInt("MainWindowLastYPos");				
 				}
 
 				int x = lastXPos;
@@ -454,17 +460,17 @@ namespace Tasque
 			}
 		}
 		
-		public static void GrabNewTaskEntryFocus ()
+		public static void GrabNewTaskEntryFocus (INativeApplication application)
 		{
 			if (taskWindow == null)
-				TaskWindow.ShowWindow ();
+				TaskWindow.ShowWindow (application);
 			
 			taskWindow.addTaskEntry.GrabFocus ();
 		}
 		
-		public static void SelectAndEdit (ITask task)
+		public static void SelectAndEdit (ITask task, INativeApplication application)
 		{
-			ShowWindow ();
+			ShowWindow (application);
 			taskWindow.EnterEditMode (task, true);
 			taskWindow.Present ();
 		}
@@ -520,7 +526,7 @@ namespace Tasque
 		/// <summary>
 		/// This should be called after a new IBackend has been set
 		/// </summary>
-		public static void Reinitialize (bool show)
+		public static void Reinitialize (bool show, INativeApplication application)
 		{
 			if (TaskWindow.taskWindow != null) {
 				TaskWindow.taskWindow.Hide ();
@@ -529,7 +535,7 @@ namespace Tasque
 			}
 
 			if (show)
-				TaskWindow.ShowWindow ();
+				TaskWindow.ShowWindow (application);
 		}
 		
 		public void HighlightTask (ITask task)
@@ -658,7 +664,7 @@ namespace Tasque
 			int count = 0;
 			
 			Gtk.TreeIter iter;
-			Gtk.TreeModel model = Application.Backend.Tasks;
+			Gtk.TreeModel model = application.Backend.Tasks;
 			
 			if (!model.GetIterFirst (out iter))
 				return 0;
@@ -861,10 +867,10 @@ namespace Tasque
 			lastXPos = x;
 			lastYPos = y;
 			
-			Application.Preferences.SetInt("MainWindowLastXPos", lastXPos);
-			Application.Preferences.SetInt("MainWindowLastYPos", lastYPos);
-			Application.Preferences.SetInt("MainWindowWidth", width);
-			Application.Preferences.SetInt("MainWindowHeight", height);
+			application.Preferences.SetInt("MainWindowLastXPos", lastXPos);
+			application.Preferences.SetInt("MainWindowLastYPos", lastYPos);
+			application.Preferences.SetInt("MainWindowWidth", width);
+			application.Preferences.SetInt("MainWindowHeight", height);
 
 			Logger.Debug("WindowDeleted was called");
 			taskWindow = null;
@@ -952,7 +958,7 @@ namespace Tasque
 			// out of the entered task text.
 			DateTime taskDueDate = DateTime.MinValue;
 			string taskName;
-			if (Application.Preferences.GetBool (Preferences.ParseDateEnabledKey))
+			if (application.Preferences.GetBool (Preferences.ParseDateEnabledKey))
 				TaskParser.Instance.TryParse (
 				                         enteredTaskText,
 				                         out taskName,
@@ -996,7 +1002,7 @@ namespace Tasque
 					// the "All" category and if not, select the category
 					// specifically.
 					List<string> categoriesToHide =
-						Application.Preferences.GetStringList (
+						application.Preferences.GetStringList (
 							Preferences.HideInAllCategory);
 					if (categoriesToHide != null && categoriesToHide.Contains (item.Category.Name)) {
 						SelectCategory (item.Category.Name);
@@ -1029,7 +1035,7 @@ namespace Tasque
 			completedTaskGroup.Refilter (category);
 			
 			// Save the selected category in preferences
-			Application.Preferences.Set (Preferences.SelectedCategoryKey,
+			application.Preferences.Set (Preferences.SelectedCategoryKey,
 										 category.Name);
 		}
 		
@@ -1109,7 +1115,7 @@ namespace Tasque
 					 * here in order to enable changing categories. The list of available categories
 					 * is pre-filtered as to not contain the current category and the AllCategory.
 					 */
-					TreeModelFilter filteredCategories = new TreeModelFilter(Application.Backend.Categories, null);
+					TreeModelFilter filteredCategories = new TreeModelFilter(application.Backend.Categories, null);
 					filteredCategories.VisibleFunc = delegate(TreeModel t, TreeIter i) {
 						ICategory category = t.GetValue (i, 0) as ICategory;
 						if (category == null || category is AllCategory || category.Equals(clickedTask.Category))
@@ -1185,7 +1191,7 @@ namespace Tasque
 			if (clickedTask == null)
 				return;
 		
-			Application.Backend.DeleteTask(clickedTask);
+			application.Backend.DeleteTask(clickedTask);
 			
 			status = Catalog.GetString ("Task deleted");
 			TaskWindow.ShowStatus (status);
@@ -1235,13 +1241,13 @@ namespace Tasque
 		private void OnBackendSyncFinished ()
 		{
 			Logger.Debug("Backend sync finished");
-			if (Application.Backend.Configured) {
+			if (application.Backend.Configured) {
 				string now = DateTime.Now.ToString ();
 				// Translators: This status shows the date and time when the task list was last refreshed
 				status = string.Format (Catalog.GetString ("Tasks loaded: {0}"), now);
 				TaskWindow.lastLoadedTime = now;
 				TaskWindow.ShowStatus (status);
-				RebuildAddTaskMenu (Application.Backend.Categories);
+				RebuildAddTaskMenu (application.Backend.Categories);
 				addTaskEntry.Sensitive = true;
 				categoryComboBox.Sensitive = true;
 				// Keep insensitive text color
diff --git a/src/Gtk.Tasque/CompletedTaskGroupModel.cs b/src/libtasque/CompletedTaskGroupModel.cs
similarity index 100%
rename from src/Gtk.Tasque/CompletedTaskGroupModel.cs
rename to src/libtasque/CompletedTaskGroupModel.cs
diff --git a/src/libtasque/IBackend.cs b/src/libtasque/IBackend.cs
index 06073e5..81fc8ee 100644
--- a/src/libtasque/IBackend.cs
+++ b/src/libtasque/IBackend.cs
@@ -95,7 +95,7 @@ namespace Tasque.Backends
 		/// <summary>
 		/// Initializes the backend
 		/// </summary>
-		void Initialize();
+		void Initialize (Preferences preferences);
 
 		/// <summary>
 		/// Cleanup the backend before quitting
diff --git a/src/libtasque/INativeApplication.cs b/src/libtasque/INativeApplication.cs
index 5166e0f..5ef68c2 100644
--- a/src/libtasque/INativeApplication.cs
+++ b/src/libtasque/INativeApplication.cs
@@ -8,13 +8,19 @@ namespace Tasque
 	{
 		IList<IBackend> AvailableBackends { get; }
 		IBackend Backend { get; set; }
+		TaskGroupModel OverdueTasks { get; }
+		TaskGroupModel TodayTasks { get; }
+		TaskGroupModel TomorrowTasks { get; }
 		string ConfDir { get; }
 		Preferences Preferences { get; }
 		void Exit (int exitcode);
+		void Quit ();
 		void Initialize (string [] args);
 		void OpenUrl (string url);
 		void QuitMainLoop ();
+		void ShowPreferences ();
 		void StartMainLoop ();
 		event EventHandler Exiting;
+		event EventHandler BackendChanged;
 	}
 }
diff --git a/src/libtasque/NativeApplication.cs b/src/libtasque/NativeApplication.cs
index 9062861..1ce611c 100644
--- a/src/libtasque/NativeApplication.cs
+++ b/src/libtasque/NativeApplication.cs
@@ -39,15 +39,13 @@ namespace Tasque
 		
 		public Preferences Preferences { get { return preferences; } }
 
-		public void Exit (int exitcode)
-		{
-			OnExit (exitcode);
-
-			if (Exiting != null)
-				Exiting (this, EventArgs.Empty);
+		public abstract void ShowPreferences ();
 
-			Environment.Exit (exitcode);
-		}
+		public TaskGroupModel OverdueTasks { get; protected set; }
+		
+		public TaskGroupModel TodayTasks { get; protected set; }
+		
+		public TaskGroupModel TomorrowTasks { get; protected set; }
 
 		public virtual void Initialize (string[] args)
 		{
@@ -91,7 +89,49 @@ namespace Tasque
 		
 		protected virtual void OnInitializeIdle () {}
 
+		#region Day switch
+		protected DateTime CurrentDay { get; private set; }
+		
+		protected void CheckForDaySwitch ()
+		{
+			if (DateTime.Today != CurrentDay) {
+				Logger.Debug ("Day has changed, reloading tasks");
+				CurrentDay = DateTime.Today;
+				OnDaySwitched ();
+			}
+		}
+		
+		protected virtual void OnDaySwitched () {}
+		#endregion
+
+		#region Exit and Quit
+		public void Exit (int exitcode)
+		{
+			OnExit (exitcode);
+			
+			if (Exiting != null)
+				Exiting (this, EventArgs.Empty);
+			
+			Environment.Exit (exitcode);
+		}
+		
+		public event EventHandler Exiting;
+		
 		protected virtual void OnExit (int exitCode) {}
+		
+		public void Quit ()
+		{
+			Logger.Info ("Quit called - terminating application");
+			OnQuitting ();
+			
+			if (backend != null)
+				backend.Cleanup ();
+			
+			QuitMainLoop ();
+		}
+		
+		protected virtual void OnQuitting () {}
+		#endregion
 
 		public virtual void OpenUrl (string url)
 		{
@@ -138,7 +178,7 @@ namespace Tasque
 				return;
 			
 			Logger.Info ("Using backend: {0} ({1})", backend.Name, backend.GetType ().ToString ());
-			backend.Initialize ();
+			backend.Initialize (preferences);
 			
 			OnBackendChanged ();
 		}
@@ -148,8 +188,6 @@ namespace Tasque
 
 		public abstract void StartMainLoop ();
 
-		public event EventHandler Exiting;
-
 		/// <summary>
 		/// Determines whether this a remote instance is running.
 		/// </summary>
@@ -183,7 +221,7 @@ namespace Tasque
 			try {
 				if (backend != null && !backend.Configured) {
 					backend.Cleanup ();
-					backend.Initialize();
+					backend.Initialize (preferences);
 				}
 			} catch (Exception e) {
 				Logger.Error ("{0}", e.Message);
diff --git a/src/Gtk.Tasque/TaskGroupModel.cs b/src/libtasque/TaskGroupModel.cs
similarity index 100%
rename from src/Gtk.Tasque/TaskGroupModel.cs
rename to src/libtasque/TaskGroupModel.cs
diff --git a/src/Gtk.Tasque/TaskGroupModelFactory.cs b/src/libtasque/TaskGroupModelFactory.cs
similarity index 100%
rename from src/Gtk.Tasque/TaskGroupModelFactory.cs
rename to src/libtasque/TaskGroupModelFactory.cs
diff --git a/src/libtasque/libtasque.csproj b/src/libtasque/libtasque.csproj
index 1f4649d..3957724 100644
--- a/src/libtasque/libtasque.csproj
+++ b/src/libtasque/libtasque.csproj
@@ -78,6 +78,9 @@
       <Link>Options.cs</Link>
     </Compile>
     <Compile Include="Preferences.cs" />
+    <Compile Include="TaskGroupModel.cs" />
+    <Compile Include="TaskGroupModelFactory.cs" />
+    <Compile Include="CompletedTaskGroupModel.cs" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="DateFormatters\" />
diff --git a/src/tasque/Program.cs b/src/tasque/Program.cs
index 8cd9e96..9491917 100644
--- a/src/tasque/Program.cs
+++ b/src/tasque/Program.cs
@@ -76,23 +76,26 @@ namespace Tasque
 				lock (lockObject) {
 					if (application != null)
 						return;
-
-					var nativeApp = CreateApplication ();
-					
-					// Fix process name not set on Unix
-					SetProcessName ("Tasque");
-					
-					application = new Application (nativeApp);
-					application.Init (args);
-					application.StartMainLoop ();
+					application = CreateApplication ();
 				}
+					
+				// Fix process name not set on Unix
+				SetProcessName ("Tasque");
+
+				application.Initialize (args);
+				application.StartMainLoop ();
 			} catch (Exception e) {
 				Logger.Debug ("Exception is: {0}", e);
 				application.Exit (-1);
+			} finally {
+				lock (lockObject) {
+					if (application != null)
+						application.Dispose ();
+				}
 			}
 		}
 		
-		static Application application;
+		static INativeApplication application;
 		static object lockObject = new object ();
 	}
 }



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