[tasque] Improve TimerColumn API



commit b3c6265c0a9f8165a7a250a9ce10113998315321
Author: Antonius Riha <antoniusriha gmail com>
Date:   Mon Jan 7 14:01:06 2013 +0100

    Improve TimerColumn API

 src/Gtk.Tasque/Gtk.Tasque.csproj                   |    4 +
 src/Gtk.Tasque/TaskCompleteTimer.cs                |  155 ++++++++++++
 src/Gtk.Tasque/TaskCompleteTimerState.cs           |   35 +++
 .../TaskCompleteTimerStoppedEventArgs.cs           |   45 ++++
 src/Gtk.Tasque/TaskCompleteTimerTickEventArgs.cs   |   45 ++++
 src/Gtk.Tasque/TaskTreeView.cs                     |   54 ++--
 src/Gtk.Tasque/TimerColumn.cs                      |  258 ++-----------------
 7 files changed, 340 insertions(+), 256 deletions(-)
---
diff --git a/src/Gtk.Tasque/Gtk.Tasque.csproj b/src/Gtk.Tasque/Gtk.Tasque.csproj
index d2376f7..14d6d29 100644
--- a/src/Gtk.Tasque/Gtk.Tasque.csproj
+++ b/src/Gtk.Tasque/Gtk.Tasque.csproj
@@ -106,6 +106,10 @@
     <Compile Include="GtkWinApplication.cs" />
     <Compile Include="TreeModelListAdapter.cs" />
     <Compile Include="TimerColumn.cs" />
+    <Compile Include="TaskCompleteTimer.cs" />
+    <Compile Include="TaskCompleteTimerTickEventArgs.cs" />
+    <Compile Include="TaskCompleteTimerState.cs" />
+    <Compile Include="TaskCompleteTimerStoppedEventArgs.cs" />
   </ItemGroup>
   <ItemGroup Condition=" '$(Configuration)' == 'LinuxDebug' Or '$(Configuration)' == 'LinuxRelease' ">
     <Compile Include="RemoteControl.cs" />
diff --git a/src/Gtk.Tasque/TaskCompleteTimer.cs b/src/Gtk.Tasque/TaskCompleteTimer.cs
new file mode 100644
index 0000000..70495e2
--- /dev/null
+++ b/src/Gtk.Tasque/TaskCompleteTimer.cs
@@ -0,0 +1,155 @@
+//
+// TaskCompletingTimer.cs
+//
+// Author:
+//       Antonius Riha <antoniusriha gmail com>
+//
+// Copyright (c) 2013 Antonius Riha
+//
+// 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.Timers;
+using Tasque;
+using Gdk;
+
+namespace Gtk.Tasque
+{
+	public class TaskCompleteTimer
+	{
+		static TaskCompleteTimer ()
+		{
+			inactiveAnimPixbufs = new Pixbuf [12];
+			for (int i = 0; i < 12; i++) {
+				var iconName = string.Format ("tasque-completing-{0}", i);
+				inactiveAnimPixbufs [i] = Utilities.GetIcon (iconName, 16);
+			}
+		}
+		
+		static Pixbuf [] inactiveAnimPixbufs;
+		
+		public TaskCompleteTimer (int timeout, TreeIter iter, TreeModel model)
+		{
+			if (model == null)
+				throw new ArgumentNullException ("model");
+			if (timeout < 0)
+				timeout = 5;
+			
+			CurrentAnimPixbuf = inactiveAnimPixbufs [0];
+			
+			long lngTimeout = timeout * 1000;
+			var interval = lngTimeout / (double)inactiveAnimPixbufs.Length;
+			
+			this.model = model;
+			this.iter = iter;
+			
+			timer = new Timer (interval);
+			timer.Elapsed += delegate {
+				try {
+					CurrentAnimPixbuf = inactiveAnimPixbufs [++i];
+					NotifyChange ();
+				} catch (IndexOutOfRangeException) {
+					StopTimer (false);
+				}
+			};
+			
+			countdown = timeout;
+			sTimer = new Timer (1000);
+			sTimer.Elapsed += delegate {
+				if (countdown == 0) {
+					sTimer.Dispose ();
+					return;
+				}
+				
+				var task = model.GetValue (iter, 0) as ITask;
+				if (task == null)
+					return;
+				
+				if (Tick != null)
+					Tick (this, new TaskCompleteTimerTickEventArgs (--countdown, task));
+			};
+		}
+		
+		public Pixbuf CurrentAnimPixbuf { get; private set; }
+		
+		public TaskCompleteTimerState State { get; private set; }
+		
+		public void Start ()
+		{
+			timer.Start ();
+			sTimer.Start ();
+			State = TaskCompleteTimerState.Running;
+			NotifyChange ();
+		}
+		
+		public void Pause ()
+		{
+			timer.Stop ();
+			sTimer.Stop ();
+			State = TaskCompleteTimerState.Paused;
+			NotifyChange ();
+		}
+		
+		public void Resume ()
+		{
+			timer.Start ();
+			sTimer.Start ();
+			State = TaskCompleteTimerState.Running;
+			NotifyChange ();
+		}
+		
+		public void Cancel ()
+		{
+			StopTimer (true);
+		}
+		
+		public event EventHandler<TaskCompleteTimerTickEventArgs> Tick;
+		
+		public event EventHandler<TaskCompleteTimerStoppedEventArgs> TimerStopped;
+		
+		void NotifyChange ()
+		{
+			var path = model.GetPath (iter);
+			model.EmitRowChanged (path, iter);
+		}
+		
+		void StopTimer (bool canceled)
+		{
+			timer.Dispose ();
+			sTimer.Dispose ();
+			State = TaskCompleteTimerState.Stopped;
+			CurrentAnimPixbuf = null;
+			
+			var task = model.GetValue (iter, 0) as ITask;
+			if (task == null)
+				return;
+			
+			NotifyChange ();
+			
+			if (TimerStopped != null)
+				TimerStopped (this, new TaskCompleteTimerStoppedEventArgs (task, canceled));
+		}
+		
+		int i;
+		int countdown;
+		TreeModel model;
+		TreeIter iter;
+		Timer timer;
+		Timer sTimer;
+	}
+}
diff --git a/src/Gtk.Tasque/TaskCompleteTimerState.cs b/src/Gtk.Tasque/TaskCompleteTimerState.cs
new file mode 100644
index 0000000..438e500
--- /dev/null
+++ b/src/Gtk.Tasque/TaskCompleteTimerState.cs
@@ -0,0 +1,35 @@
+//
+// TaskCompleteTimerState.cs
+//
+// Author:
+//       Antonius Riha <antoniusriha gmail com>
+//
+// Copyright (c) 2013 Antonius Riha
+//
+// 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.
+namespace Gtk.Tasque
+{
+	public enum TaskCompleteTimerState
+	{
+		NotStarted,
+		Running,
+		Paused,
+		Stopped
+	}
+}
diff --git a/src/Gtk.Tasque/TaskCompleteTimerStoppedEventArgs.cs b/src/Gtk.Tasque/TaskCompleteTimerStoppedEventArgs.cs
new file mode 100644
index 0000000..7d52791
--- /dev/null
+++ b/src/Gtk.Tasque/TaskCompleteTimerStoppedEventArgs.cs
@@ -0,0 +1,45 @@
+//
+// TaskCompleteTimerExpired.cs
+//
+// Author:
+//       Antonius Riha <antoniusriha gmail com>
+//
+// Copyright (c) 2013 Antonius Riha
+//
+// 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 Tasque;
+
+namespace Gtk.Tasque
+{
+	public class TaskCompleteTimerStoppedEventArgs : EventArgs
+	{
+		public TaskCompleteTimerStoppedEventArgs (ITask task, bool canceled)
+		{
+			if (task == null)
+				throw new ArgumentNullException ("task");
+			Task = task;
+			Canceled = canceled;
+		}
+		
+		public bool Canceled { get; private set; }
+		
+		public ITask Task { get; private set; }
+	}
+}
diff --git a/src/Gtk.Tasque/TaskCompleteTimerTickEventArgs.cs b/src/Gtk.Tasque/TaskCompleteTimerTickEventArgs.cs
new file mode 100644
index 0000000..13be62c
--- /dev/null
+++ b/src/Gtk.Tasque/TaskCompleteTimerTickEventArgs.cs
@@ -0,0 +1,45 @@
+//
+// TaskCompleteTimerTickEventArgs.cs
+//
+// Author:
+//       Antonius Riha <antoniusriha gmail com>
+//
+// Copyright (c) 2013 Antonius Riha
+//
+// 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 Tasque;
+
+namespace Gtk.Tasque
+{
+	public class TaskCompleteTimerTickEventArgs : EventArgs
+	{
+		public TaskCompleteTimerTickEventArgs (int tick, ITask task)
+		{
+			if (task == null)
+				throw new ArgumentNullException ("task");
+			Task = task;
+			CountdownTick = tick;
+		}
+		
+		public int CountdownTick { get; private set; }
+		
+		public ITask Task { get; private set; }
+	}
+}
diff --git a/src/Gtk.Tasque/TaskTreeView.cs b/src/Gtk.Tasque/TaskTreeView.cs
index b6b87cc..591ad67 100644
--- a/src/Gtk.Tasque/TaskTreeView.cs
+++ b/src/Gtk.Tasque/TaskTreeView.cs
@@ -2,7 +2,6 @@
 // User: boyd on 2/9/2008
 
 using System;
-using System.Collections.Generic;
 using Mono.Unix;
 using Tasque;
 using Gtk;
@@ -238,16 +237,7 @@ namespace Gtk.Tasque
 			// Timer Column
 			//
 			timerCol = new TimerColumn (preferences, model);
-			timerCol.TimerExpired += (sender, e) => {
-				if (!e.Canceled)
-					e.Task.Complete ();
-			};
-
-			timerCol.Tick += (sender, e) => {
-				var status = string.Format (Catalog.GetString ("Completing Task In: {0}"), e.CountdownTick);
-				TaskWindow.ShowStatus (status, 2000);
-			};
-			AppendColumn (timerCol);
+			AppendColumn (timerCol.TreeViewColumn);
 		}
 
 		void CellRenderer_EditingStarted (object o, EditingStartedArgs args)
@@ -263,7 +253,9 @@ namespace Gtk.Tasque
 				return;
 
 			taskBeingEdited = task;
-			timerCol.PauseTimer (taskBeingEdited);
+			var timer = timerCol.GetTimer (taskBeingEdited);
+			if (timer != null)
+				timer.Pause ();
 		}
 		
 		void SetCellRendererCallbacks (CellRendererText renderer, EditedHandler handler)
@@ -273,9 +265,9 @@ namespace Gtk.Tasque
 			// Canceled: timer can continue.
 			renderer.EditingCanceled += (o, args) => {
 				if (taskBeingEdited != null) {
-					var timerState = timerCol.GetTimerState (taskBeingEdited);
-					if (timerState != null && (TimerColumn.TaskTimerState)timerState == TimerColumn.TaskTimerState.Paused)
-						timerCol.ResumeTimer (taskBeingEdited);
+					var timer = timerCol.GetTimer (taskBeingEdited);
+					if (timer != null && timer.State == TaskCompleteTimerState.Paused)
+						timer.Resume ();
 					taskBeingEdited = null;
 				}
 			};
@@ -285,9 +277,9 @@ namespace Gtk.Tasque
 					handler (o, args);
 
 				if (taskBeingEdited != null) {
-					var timerState = timerCol.GetTimerState (taskBeingEdited);
-					if (timerState != null && (TimerColumn.TaskTimerState)timerState == TimerColumn.TaskTimerState.Paused)
-						timerCol.ResumeTimer (taskBeingEdited);
+					var timer = timerCol.GetTimer (taskBeingEdited);
+					if (timer != null && timer.State == TaskCompleteTimerState.Paused)
+						timer.Resume ();
 					taskBeingEdited = null;
 				}
 			};
@@ -338,8 +330,7 @@ namespace Gtk.Tasque
 			if (task == null)
 				crt.Active = false;
 			else {
-				var timerState = timerCol.GetTimerState (task);
-				crt.Active = !(task.State == TaskState.Active && timerState == null);
+				crt.Active = !(task.State == TaskState.Active && timerCol.GetTimer (task) == null);
 			}
 		}
 
@@ -448,9 +439,8 @@ namespace Gtk.Tasque
 			switch (task.State) {
 			case TaskState.Active:
 				// Strikeout the text
-				var timerState = timerCol.GetTimerState (task);
-				if (timerState != null && (TimerColumn.TaskTimerState)timerState
-				    == TimerColumn.TaskTimerState.Running)
+				var timer = timerCol.GetTimer (task);
+				if (timer != null && timer.State == TaskCompleteTimerState.Running)
 					formatString = "<span strikethrough=\"true\">{0}</span>";
 				break;
 			case TaskState.Deleted:
@@ -542,7 +532,9 @@ namespace Gtk.Tasque
 				return;
 
 			// remove any timer set up on this task
-			timerCol.CancelTimer (task);
+			var tmr = timerCol.GetTimer (task);
+			if (tmr != null)
+				tmr.Cancel ();
 			
 			if (task.State == TaskState.Active) {
 				bool showCompletedTasks =
@@ -554,8 +546,18 @@ namespace Gtk.Tasque
 				if (showCompletedTasks) {
 					task.Complete ();
 					ShowCompletedTaskStatus ();
-				} else
-					timerCol.StartTimer (task);
+				} else {
+					var timer = timerCol.CreateTimer (task);
+					timer.TimerStopped += (s, e) => {
+						if (!e.Canceled)
+							e.Task.Complete ();
+					};
+					timer.Tick += (s, e) => {
+						var status = string.Format (Catalog.GetString ("Completing Task In: {0}"), e.CountdownTick);
+						TaskWindow.ShowStatus (status, 2000);
+					};
+					timer.Start ();
+				}
 			} else {
 				status = Catalog.GetString ("Action Canceled");
 				TaskWindow.ShowStatus (status);
diff --git a/src/Gtk.Tasque/TimerColumn.cs b/src/Gtk.Tasque/TimerColumn.cs
index d8359e0..cea7ffa 100644
--- a/src/Gtk.Tasque/TimerColumn.cs
+++ b/src/Gtk.Tasque/TimerColumn.cs
@@ -25,14 +25,12 @@
 // THE SOFTWARE.
 using System;
 using System.Collections.Concurrent;
-using System.Timers;
 using Mono.Unix;
 using Tasque;
-using Gdk;
 
 namespace Gtk.Tasque
 {
-	public class TimerColumn : TreeViewColumn
+	public class TimerColumn
 	{
 		public TimerColumn (IPreferences preferences, TreeModel model)
 		{
@@ -43,23 +41,27 @@ namespace Gtk.Tasque
 				throw new ArgumentNullException ("preferences");
 			this.preferences = preferences;
 
-			timeoutTargets = new ConcurrentDictionary<ITask, TaskTimer> ();
+			timeoutTargets = new ConcurrentDictionary<ITask, TaskCompleteTimer> ();
 
-			Title = Catalog.GetString ("Timer");
-			Sizing = TreeViewColumnSizing.Fixed;
-			FixedWidth = 20;
-			Resizable = false;
+			TreeViewColumn = new TreeViewColumn {
+				Title = Catalog.GetString ("Timer"),
+				Sizing = TreeViewColumnSizing.Fixed,
+				FixedWidth = 20,
+				Resizable = false
+			};
 			
 			var renderer = new CellRendererPixbuf {	Xalign = 0.5f };
-			PackStart (renderer, false);
-			SetCellDataFunc (renderer, TaskTimerCellDataFunc);
+			TreeViewColumn.PackStart (renderer, false);
+			TreeViewColumn.SetCellDataFunc (renderer, TaskTimerCellDataFunc);
 		}
-
-		public void StartTimer (ITask task)
+		
+		public TreeViewColumn TreeViewColumn { get; private set; }
+		
+		public TaskCompleteTimer CreateTimer (ITask task)
 		{
 			if (task == null)
 				throw new ArgumentNullException ("task");
-
+			
 			var timeout = preferences.GetInt (PreferencesKeys.InactivateTimeoutKey);
 			TreeIter treeIter;
 			var iterFound = false;
@@ -71,75 +73,32 @@ namespace Gtk.Tasque
 				}
 				return false;
 			});
-
-			var timer = new TaskTimer (timeout, treeIter, model);
-			// if no iter found for task or this task exists in the timer dictinary, return
-			// silently (this is a concurrency sensitive area, hence we shouldn't be to
-			// strict if it is called multiple times)
+			
+			var timer = new TaskCompleteTimer (timeout, treeIter, model);
 			if (!iterFound || !timeoutTargets.TryAdd (task, timer))
-				return;
-
+				throw new Exception ("Unable to create a timer for the provided task.");
+			
 			timer.TimerStopped += (sender, e) => {
-				TaskTimer tmr;
+				TaskCompleteTimer tmr;
 				timeoutTargets.TryRemove (e.Task, out tmr);
-				if (TimerExpired != null)
-					TimerExpired (this, e);
-			};
-
-			timer.Tick += (sender, e) => {
-				if (Tick != null)
-					Tick (this, e);
 			};
-
-			timer.Start ();
-		}
-
-		public void PauseTimer (ITask task)
-		{
-			if (task == null)
-				return;
-			TaskTimer timer;
-			if (timeoutTargets.TryGetValue (task, out timer))
-				timer.Pause ();
+			
+			return timer;
 		}
 
-		public void ResumeTimer (ITask task)
+		public TaskCompleteTimer GetTimer (ITask task)
 		{
-			if (task == null)
-				return;
-			TaskTimer timer;
+			TaskCompleteTimer timer;
 			if (timeoutTargets.TryGetValue (task, out timer))
-				timer.Resume ();
+				return timer;
+			return null;
 		}
 
-		public TaskTimerState? GetTimerState (ITask task)
-		{
-			if (task == null)
-				throw new ArgumentNullException ("task");
-			TaskTimer timer;
-			if (!timeoutTargets.TryGetValue (task, out timer))
-				return null;
-			return timer.State;
-		}
-
-		public void CancelTimer (ITask task)
-		{
-			if (task == null)
-				return;
-			TaskTimer timer;
-			if (timeoutTargets.TryRemove (task, out timer))
-				timer.Cancel ();
-		}
-
-		public event EventHandler<TickEventArgs> Tick;
-
-		public event EventHandler<TimerExpiredEventArgs> TimerExpired;
-
 		void TaskTimerCellDataFunc (TreeViewColumn treeColumn, CellRenderer cell,
 		                            TreeModel treeModel, TreeIter iter)
 		{
 			var task = treeModel.GetValue (iter, 0) as ITask;
-			TaskTimer timer;
+			TaskCompleteTimer timer;
 			var crp = cell as CellRendererPixbuf;
 			if (task == null || !timeoutTargets.TryGetValue (task, out timer)) {
 				crp.Pixbuf = null;
@@ -149,169 +108,8 @@ namespace Gtk.Tasque
 			crp.Pixbuf = timer.CurrentAnimPixbuf;
 		}
 
-		ConcurrentDictionary<ITask, TaskTimer> timeoutTargets;
+		ConcurrentDictionary<ITask, TaskCompleteTimer> timeoutTargets;
 		IPreferences preferences;
 		TreeModel model;
-
-		public class TimerExpiredEventArgs : EventArgs
-		{
-			public TimerExpiredEventArgs (ITask task, bool canceled)
-			{
-				if (task == null)
-					throw new ArgumentNullException ("task");
-				Task = task;
-				Canceled = canceled;
-			}
-
-			public bool Canceled { get; private set; }
-
-			public ITask Task { get; private set; }
-		}
-
-		public class TickEventArgs : EventArgs
-		{
-			public TickEventArgs (int tick, ITask task)
-			{
-				if (task == null)
-					throw new ArgumentNullException ("task");
-				Task = task;
-				CountdownTick = tick;
-			}
-
-			public int CountdownTick { get; private set; }
-
-			public ITask Task { get; private set; }
-		}
-
-		public enum TaskTimerState
-		{
-			NotStarted,
-			Running,
-			Paused,
-			Stopped
-		}
-
-		class TaskTimer
-		{
-			static TaskTimer ()
-			{
-				inactiveAnimPixbufs = new Pixbuf [12];
-				for (int i = 0; i < 12; i++) {
-					var iconName = string.Format ("tasque-completing-{0}", i);
-					inactiveAnimPixbufs [i] = Utilities.GetIcon (iconName, 16);
-				}
-			}
-			
-			static Pixbuf [] inactiveAnimPixbufs;
-
-			public TaskTimer (int timeout, TreeIter iter, TreeModel model)
-			{
-				if (model == null)
-					throw new ArgumentNullException ("model");
-				if (timeout < 0)
-					timeout = 5;
-
-				CurrentAnimPixbuf = inactiveAnimPixbufs [0];
-
-				long lngTimeout = timeout * 1000;
-				var interval = lngTimeout / (double)inactiveAnimPixbufs.Length;
-
-				this.model = model;
-				this.iter = iter;
-
-				timer = new Timer (interval);
-				timer.Elapsed += delegate {
-					try {
-						CurrentAnimPixbuf = inactiveAnimPixbufs [++i];
-						NotifyChange ();
-					} catch (IndexOutOfRangeException) {
-						StopTimer (false);
-					}
-				};
-
-				countdown = timeout;
-				sTimer = new Timer (1000);
-				sTimer.Elapsed += delegate {
-					if (countdown == 0) {
-						sTimer.Dispose ();
-						return;
-					}
-
-					var task = model.GetValue (iter, 0) as ITask;
-					if (task == null)
-						return;
-
-					if (Tick != null)
-						Tick (this, new TickEventArgs (--countdown, task));
-				};
-			}
-
-			public Pixbuf CurrentAnimPixbuf { get; private set; }
-
-			public TaskTimerState State { get; private set; }
-
-			public void Start ()
-			{
-				timer.Start ();
-				sTimer.Start ();
-				State = TaskTimerState.Running;
-				NotifyChange ();
-			}
-
-			public void Pause ()
-			{
-				timer.Stop ();
-				sTimer.Stop ();
-				State = TaskTimerState.Paused;
-				NotifyChange ();
-			}
-
-			public void Resume ()
-			{
-				timer.Start ();
-				sTimer.Start ();
-				State = TaskTimerState.Running;
-				NotifyChange ();
-			}
-
-			public void Cancel ()
-			{
-				StopTimer (true);
-			}
-
-			public event EventHandler<TickEventArgs> Tick;
-
-			public event EventHandler<TimerExpiredEventArgs> TimerStopped;
-
-			void NotifyChange ()
-			{
-				var path = model.GetPath (iter);
-				model.EmitRowChanged (path, iter);
-			}
-
-			void StopTimer (bool canceled)
-			{
-				timer.Dispose ();
-				sTimer.Dispose ();
-				State = TaskTimerState.Stopped;
-				CurrentAnimPixbuf = null;
-
-				var task = model.GetValue (iter, 0) as ITask;
-				if (task == null)
-					return;
-
-				NotifyChange ();
-
-				if (TimerStopped != null)
-					TimerStopped (this, new TimerExpiredEventArgs (task, canceled));
-			}
-
-			int i;
-			int countdown;
-			TreeModel model;
-			TreeIter iter;
-			Timer timer;
-			Timer sTimer;
-		}
 	}
 }



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