Index: Tomboy.mdp
===================================================================
--- Tomboy.mdp	(revision 1587)
+++ Tomboy.mdp	(working copy)
@@ -21,11 +21,13 @@
     <File name="./Tomboy/NoteBuffer.cs" subtype="Code" buildaction="Compile" />
     <File name="./Tomboy/NoteManager.cs" subtype="Code" buildaction="Compile" />
     <File name="./Tomboy/NoteTag.cs" subtype="Code" buildaction="Compile" />
+    <File name="./Tomboy/NoteTagBar.cs" subtype="Code" buildaction="Compile" />
     <File name="./Tomboy/NoteWindow.cs" subtype="Code" buildaction="Compile" />
     <File name="./Tomboy/Preferences.cs" subtype="Code" buildaction="Compile" />
     <File name="./Tomboy/RecentChanges.cs" subtype="Code" buildaction="Compile" />
     <File name="./Tomboy/RemoteControl.cs" subtype="Code" buildaction="Compile" />
     <File name="./Tomboy/RemoteControlProxy.cs" subtype="Code" buildaction="Compile" />
+    <File name="./Tomboy/TagTreeWidget.cs" subtype="Code" buildaction="Compile" />
     <File name="./Tomboy/Tomboy.cs" subtype="Code" buildaction="Compile" />
     <File name="./Tomboy/Tray.cs" subtype="Code" buildaction="Compile" />
     <File name="./Tomboy/Trie.cs" subtype="Code" buildaction="Compile" />
@@ -200,4 +202,4 @@
     <AsmRefVar />
     <ProjectRefVar />
   </MonoDevelop.Autotools.MakefileInfo>
-</Project>
\ No newline at end of file
+</Project>
Index: Tomboy/NoteTagBar.cs
===================================================================
--- Tomboy/NoteTagBar.cs	(revision 0)
+++ Tomboy/NoteTagBar.cs	(revision 0)
@@ -0,0 +1,356 @@
+using System;
+using System.Collections.Generic;
+using Mono.Unix;
+
+namespace Tomboy
+{
+	public class NoteTagBar : Gtk.VBox
+	{
+		private Note note;
+		
+//		WrapBox tag_cloud;
+		Gtk.Entry tag_entry;
+//		Gtk.Button add_tag_button;
+//		Gtk.TreeView tree;
+//		Gtk.TreeStore store;
+		TagTreeWidget tag_tree;
+		
+		#region Constructors
+		public NoteTagBar (Note note) : base (false, 4)
+		{
+			this.note = note;
+			
+			BorderWidth = 2;
+			
+//			Gtk.Button button = new Gtk.Button ();
+//			button.Image = new Gtk.Image (Gtk.Stock.Close, Gtk.IconSize.Menu);
+//			button.Relief = Gtk.ReliefStyle.None;
+//			button.Clicked += HideTagBar;
+//			button.Show ();
+//			PackStart (button, false, false, 4);
+
+			Gtk.Label label = new Gtk.Label (
+					string.Format ("<span weight=\"bold\">{0}</span>",
+						Catalog.GetString ("Tags:")));
+			label.Xalign = 0.5f;
+			label.UseMarkup = true;
+			label.Show ();
+			
+			PackStart (label, false, false, 0);
+
+			tag_entry = new Gtk.Entry ();
+			
+			Gtk.EntryCompletion entry_completion = new Gtk.EntryCompletion ();
+			entry_completion.InlineCompletion = true;
+			entry_completion.PopupSingleMatch = true;
+			entry_completion.Model = new NoteTagBarCompletionModel (tag_entry, typeof (Tag));
+			entry_completion.MatchFunc = TagEntryCompletionMatchFunc;
+			entry_completion.MatchSelected += TagEntryCompletionMatchSelected;
+			Gtk.CellRendererText crt = new Gtk.CellRendererText ();
+			entry_completion.PackStart (crt, true);
+			entry_completion.SetCellDataFunc (crt,
+					new Gtk.CellLayoutDataFunc (TagEntryCompletionDataFunc));
+			
+			tag_entry.Completion = entry_completion;
+			tag_entry.Activated += TagEntryActivated;
+			tag_entry.Changed += TagEntryChanged;
+			// Bind ESC to close the TagBar if it's open and has focus.
+			tag_entry.KeyPressEvent += KeyPressed;
+			tag_entry.Show ();
+			PackStart (tag_entry, false, false, 0);
+			
+			
+			tag_tree = new TagTreeWidget ();
+			tag_tree.TagSelected += OnTagSelected;
+			tag_tree.TagUnselected += OnTagUnselected;
+			foreach (Tag tag in note.Tags) {
+				tag_tree.SelectTag (tag);
+			}
+			tag_tree.Show ();
+			
+			PackStart (tag_tree, true, true, 0);
+//			foreach (Tag tag in note.Tags) {
+//				button = MakeTagButton (tag);
+//				button.Show ();
+//				tag_cloud.Insert (button);
+//			}
+			
+//			add_tag_button = new Gtk.Button (String.Empty);
+//			add_tag_button.Image = new Gtk.Image (Gtk.Stock.Add, Gtk.IconSize.Menu);
+//			add_tag_button.Sensitive = false;
+//			add_tag_button.Clicked += AddTagButtonClicked;
+//			add_tag_button.Show ();
+//			PackStart (add_tag_button, false, false, 0);
+
+			note.TagAdded += TagAddedHandler;
+			note.TagRemoved += TagRemovedHandler;
+		}
+		#endregion
+		
+		#region Private Methods
+		Gtk.Button MakeTagButton (Tag tag)
+		{
+			TagButton button = new TagButton (tag);
+			button.Clicked += TagButtonClicked;
+
+			return button;
+		}
+
+		protected override void OnShown ()
+		{
+			tag_entry.GrabFocus ();
+
+			base.OnShown ();
+		}
+		
+		protected override void OnHidden ()
+		{
+			base.OnHidden ();
+		}
+		
+		#endregion
+
+		#region Event Handlers
+		// <summary>
+		// When the user presses return, call the same method that is called
+		// when the user presses the Add button.
+		// </summary>
+		void TagEntryActivated (object sender, EventArgs args)
+		{
+			AddTagButtonClicked (sender, args);
+		}
+		
+		void TagEntryChanged (object sender, EventArgs args)
+		{
+//			string text = tag_entry.Text.Trim ();
+//			if (text.Length == 0) {
+//				add_tag_button.Sensitive = false;
+//			} else {
+//				add_tag_button.Sensitive = true;
+//			}
+		}
+		
+		void AddTagButtonClicked (object sender, EventArgs args)
+		{
+			string text = tag_entry.Text.Trim ();
+			if (text.Length > 0) {
+				// Split up into different tags if there are commas
+				char [] delims = {','};
+				foreach (string tag_str in text.Split (delims, StringSplitOptions.RemoveEmptyEntries)) {
+					string trimmed_str = tag_str.Trim ();
+					if (trimmed_str == String.Empty)
+						continue;
+					
+					Tag tag = TagManager.GetOrCreateTag (trimmed_str);
+					if (!note.Data.Tags.ContainsKey (tag.NormalizedName)) {
+						note.AddTag (tag);
+					}
+				}
+			}
+			
+			// Clear out the entry and grab the cursor focus so it's ready to
+			// have another tag typed and added.
+			tag_entry.Text = String.Empty;
+		}
+		
+		void TagButtonClicked (object sender, EventArgs args)
+		{
+			TagButton button = sender as TagButton;
+			
+			note.RemoveTag (button.Tag);
+		}
+		
+		void TagAddedHandler (Note note, Tag tag)
+		{
+//			Gtk.Button button = MakeTagButton (tag);
+//			button.Show ();
+//			tag_cloud.Insert (button);
+			tag_tree.SelectTag (tag);
+		}
+		
+		void TagRemovedHandler (Note note, string tag_name)
+		{
+//			// Remove the button from the list
+//			TagButton button_to_remove = null;
+			
+//			foreach (Gtk.Widget w in tag_cloud.Children) {
+//				if (w is TagButton) {
+//					TagButton button = w as TagButton;
+//					
+//					if (string.Compare (button.Tag.NormalizedName, tag_name) == 0) {
+//						button_to_remove = button;
+//						button.Hide ();
+//						break;
+//					}
+//				}
+//			}
+			
+//			if (button_to_remove != null)
+//				tag_cloud.Remove (button_to_remove);
+//			else
+//				Logger.Debug ("\tDid not remove a tag button");
+			Tag tag = TagManager.GetTag (tag_name);
+			if (tag != null)
+				tag_tree.UnselectTag (tag);
+		}
+		
+		void TagEntryCompletionDataFunc (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell,
+				Gtk.TreeModel tree_model, Gtk.TreeIter iter)
+		{
+			Gtk.CellRendererText crt = cell as Gtk.CellRendererText;
+			Tag tag = tree_model.GetValue (iter, 0) as Tag;
+			crt.Text = tag.Name;
+		}
+		
+		bool TagEntryCompletionMatchFunc (Gtk.EntryCompletion completion, string key, Gtk.TreeIter iter)
+		{
+			if (key.Length == 0)
+				return true;
+			
+			Tag tag = completion.Model.GetValue (iter, 0) as Tag;
+			if (tag == null)
+				return false;
+			
+			string lower_cased_key = key.ToLower ();
+			
+			if (tag.NormalizedName.StartsWith (lower_cased_key)) {
+				// Only return tags that aren't already tagged in this note
+				if (note.Data.Tags.ContainsKey (tag.NormalizedName) == false)
+					return true;
+			}
+			
+			return false;
+		}
+		
+		[GLib.ConnectBefore]
+		void TagEntryCompletionMatchSelected (object sender, Gtk.MatchSelectedArgs args)
+		{
+			Tag tag = args.Model.GetValue (args.Iter, 0) as Tag;
+			if (tag != null) {
+				tag_entry.Text = tag.Name;
+				args.RetVal = true;
+				
+				// Press the add button for the user
+				AddTagButtonClicked (sender, EventArgs.Empty);
+			}
+		}
+		
+		void HideTagBar (object sender, EventArgs args)
+		{
+			Hide ();
+		}
+		
+		void KeyPressed (object sender, Gtk.KeyPressEventArgs args)
+		{
+			args.RetVal = true;
+			
+			switch (args.Event.Key)
+			{
+			case Gdk.Key.Escape:
+				Hide ();
+				break;
+			default:
+				args.RetVal = false;
+				break;
+			}
+		}
+		
+		void OnTagSelected (Tag tag)
+		{
+			note.AddTag (tag);
+		}
+		
+		void OnTagUnselected (Tag tag)
+		{
+			note.RemoveTag (tag);
+		}
+		
+		#endregion // Event Handlers
+
+		#region Public Methods
+		#endregion
+		
+		#region Properties
+		#endregion
+	}
+	
+	public class NoteTagBarCompletionModel : Gtk.ListStore
+	{
+		Dictionary<string, Gtk.TreeIter> iters;
+		Gtk.Entry entry;
+		CreateNewTag create_tag;
+		
+		public NoteTagBarCompletionModel (Gtk.Entry tag_entry, params Type[] types)
+			: base (types)
+		{
+			entry = tag_entry;
+			
+			iters = new Dictionary<string,Gtk.TreeIter> ();
+			
+			TagManager.TagAdded += OnTagAdded;
+			TagManager.TagRemoved += OnTagRemoved;
+			
+			// Add all the tags into the completion tag model
+			Gtk.TreeIter iter;
+			Gtk.TreeIter new_iter;
+			if (TagManager.Tags.GetIterFirst (out iter)) {
+				do {
+					new_iter = this.Append ();
+					this.SetValue (new_iter, 0, TagManager.Tags.GetValue (iter, 0));
+				} while (TagManager.Tags.IterNext (ref iter));
+			}
+			
+			// Add in the special tag
+			create_tag = new CreateNewTag (entry);
+		}
+		
+		#region Event Handlers
+		void OnTagAdded (Tag tag, Gtk.TreeIter iter)
+		{
+			Gtk.TreeIter new_iter = Append ();
+			SetValue (new_iter, 0, tag);
+			iters [tag.NormalizedName] = new_iter;
+		}
+		
+		void OnTagRemoved (string tag_name)
+		{
+			if (iters.ContainsKey (tag_name)) {
+				Gtk.TreeIter iter = iters [tag_name];
+				Remove (ref iter);
+				iters.Remove (tag_name);
+			}
+		}
+		#endregion // Event Handlers
+	}
+	
+	public class CreateNewTag : Tag
+	{
+		Gtk.Entry entry;
+		public const string NORMALIZED_NAME = "e20c68f1-0ced-4cd6-84f1-19460828e0d5"; 
+		
+		public CreateNewTag (Gtk.Entry tag_entry) : base (string.Empty)
+		{
+			entry = tag_entry;
+		}
+		
+		public new string Name
+		{
+			get {
+				return string.Format ("{0} \"{1}\"",
+					Catalog.GetString ("Create"),
+					entry.Text.Trim ());
+			}
+			
+			set {
+				// Do nothing
+			}
+		}
+		
+		public new string NormalizedName
+		{
+			get {
+				return NORMALIZED_NAME;
+			}
+		}
+	}
+}
Index: Tomboy/TagManager.cs
===================================================================
--- Tomboy/TagManager.cs	(revision 1587)
+++ Tomboy/TagManager.cs	(working copy)
@@ -145,6 +145,21 @@ namespace Tomboy
 			}
 		}
 		
+		/// <summary>
+		/// Get the Gtk.TreeIter of the specified tag if it exists.  Returns
+		/// true if found, false otherwise.
+		/// </summary>
+		public static bool GetTagIter (string normalized_name, out Gtk.TreeIter iter)
+		{
+			if (tag_map.ContainsKey (normalized_name) == false) {
+				iter = Gtk.TreeIter.Zero;
+				return false;
+			}
+			
+			iter = tag_map [normalized_name];
+			return true;
+		}
+		
 		// <summary>
 		// </summary>
 		#endregion
Index: Tomboy/NoteWindow.cs
===================================================================
--- Tomboy/NoteWindow.cs	(revision 1588)
+++ Tomboy/NoteWindow.cs	(working copy)
@@ -18,7 +18,7 @@ namespace Tomboy
 		Gtk.Menu plugin_menu;
 		Gtk.TextView editor;
 		Gtk.ScrolledWindow editor_window;
-//		NoteTagBar tag_bar;
+		NoteTagBar tag_bar;
 		NoteFindBar find_bar;
 
 		GlobalKeybinder global_keys;
@@ -68,10 +68,10 @@ namespace Tomboy
 			toolbar = MakeToolbar ();
 			toolbar.Show ();
 			
-//			tag_bar = new NoteTagBar (note);
-//			tag_bar.Visible = false;
-//			tag_bar.NoShowAll = true;
-//			tag_bar.Hidden += TagBarHidden;
+			tag_bar = new NoteTagBar (note);
+			tag_bar.Visible = false;
+			tag_bar.NoShowAll = true;
+			tag_bar.Hidden += TagBarHidden;
 			
 			// The main editor widget
 			editor = new NoteEditor (note.Buffer);
@@ -99,11 +99,19 @@ namespace Tomboy
 			find_bar.NoShowAll = true;
 			find_bar.Hidden += FindBarHidden;
 
+			Gtk.VBox vbox = new Gtk.VBox (false, 2);
+			vbox.PackStart (editor_window, true, true, 0);
+			vbox.PackStart (find_bar, false, false, 0);
+			vbox.Show ();
+
+			Gtk.HBox hbox = new Gtk.HBox (false, 2);
+			hbox.PackStart (vbox, true, true, 0);
+			hbox.PackStart (tag_bar, false, false, 0);
+			hbox.Show ();
+
 			Gtk.VBox box = new Gtk.VBox (false, 2);
 			box.PackStart (toolbar, false, false, 0);
-//			box.PackStart (tag_bar, false, false, 0);
-			box.PackStart (editor_window, true, true, 0);
-			box.PackStart (find_bar, false, false, 0);
+			box.PackStart (hbox, true, true, 0);
 			box.Show ();
 			
 			// Don't set up Ctrl-W or Ctrl-N if Emacs is in use
@@ -439,18 +447,18 @@ namespace Tomboy
 			
 			// FIXME: Isn't there a better way to load an icon besides having
 			// to specify a size implicitly?  (tomboy-tag, 22)
-//			Gtk.Widget tags_button =
-//				toolbar.AppendItem (
-//					Catalog.GetString ("Tags"),
-//					Catalog.GetString ("Add/Remove note tags"),
-//					null,
-//					new Gtk.Image (GuiUtils.GetIcon ("tomboy-tag", 22)),
-//					new Gtk.SignalFunc (TagBarClicked));
-//			tags_button.AddAccelerator ("activate",
-//						    accel_group,
-//						    (uint) Gdk.Key.t, 
-//						    Gdk.ModifierType.ControlMask,
-//						    Gtk.AccelFlags.Visible);
+			Gtk.Widget tags_button =
+				toolbar.AppendItem (
+					Catalog.GetString ("Tags"),
+					Catalog.GetString ("Add/Remove note tags"),
+					null,
+					new Gtk.Image (GuiUtils.GetIcon ("tomboy-tag", 22)),
+					new Gtk.SignalFunc (TagBarClicked));
+			tags_button.AddAccelerator ("activate",
+						    accel_group,
+						    (uint) Gdk.Key.t, 
+						    Gdk.ModifierType.ControlMask,
+						    Gtk.AccelFlags.Visible);
 
 			ToolMenuButton plugin_button = 
 				new ToolMenuButton (toolbar, 
@@ -596,12 +604,12 @@ namespace Tomboy
 			Find.FindPreviousButton.Click ();
 		}
 		
-//		void TagBarHidden (object sender, EventArgs args)
-//		{
-//			// Reposition the current focus back to the editor so the
-//			// cursor will be ready for typing.
-//			editor.GrabFocus ();
-//		}
+		void TagBarHidden (object sender, EventArgs args)
+		{
+			// Reposition the current focus back to the editor so the
+			// cursor will be ready for typing.
+			editor.GrabFocus ();
+		}
 		
 		void FindBarHidden (object sender, EventArgs args)
 		{
@@ -689,13 +697,13 @@ namespace Tomboy
 			((NoteBuffer)editor.Buffer).ChangeCursorDepthDirectional (false);
 		}
 		
-//		void TagBarClicked ()
-//		{
-//			if (tag_bar.Visible)
-//				tag_bar.Hide ();
-//			else
-//				tag_bar.Show ();
-//		}
+		void TagBarClicked ()
+		{
+			if (tag_bar.Visible)
+				tag_bar.Hide ();
+			else
+				tag_bar.Show ();
+		}
 	}
 
 /*	
Index: Tomboy/TagTreeWidget.cs
===================================================================
--- Tomboy/TagTreeWidget.cs	(revision 0)
+++ Tomboy/TagTreeWidget.cs	(revision 0)
@@ -0,0 +1,223 @@
+using System;
+using System.Collections.Generic;
+using Mono.Unix;
+
+namespace Tomboy
+{
+	public class TagTreeWidget : Gtk.ScrolledWindow
+	{
+		Gtk.ScrolledWindow sw;
+		Gtk.TreeView tree;
+		
+		Dictionary<string, Gtk.TreeIter> tag_iters;
+		Dictionary<string, Tag> selected_tags;
+		
+		public TagTreeWidget()
+		{
+			tag_iters = new Dictionary<string,Gtk.TreeIter> ();
+			selected_tags = new Dictionary<string,Tag> ();
+			
+			VscrollbarPolicy = Gtk.PolicyType.Automatic;
+			HscrollbarPolicy = Gtk.PolicyType.Automatic;
+			
+			//
+			// Set up the tag TreeView
+			//
+			tree = new Gtk.TreeView ();
+			Gtk.TreeView t;
+			tree.HeadersVisible = false;
+			tree.Show ();
+			
+//			tag_cloud = new WrapBox ();
+//			tag_cloud.Show ();
+//			PackStart (tag_cloud, true, true, 0);
+			
+			// Set up the TreeStore for the tag tree
+//			store = new Gtk.TreeStore (typeof (Tag));
+			Gtk.TreeViewColumn col = new Gtk.TreeViewColumn ();
+			col.Title = Catalog.GetString ("Tags");
+			col.Resizable = false;
+			
+			Gtk.CellRenderer renderer;
+			renderer = new Gtk.CellRendererToggle ();
+			(renderer as Gtk.CellRendererToggle).Toggled += OnTagToggled;
+			col.PackStart (renderer, false);
+			col.SetCellDataFunc (renderer,
+					new Gtk.TreeCellDataFunc (TagsToggleCellDataFunc));
+
+			renderer = new Gtk.CellRendererText ();
+			col.PackStart (renderer, true);
+			col.SetCellDataFunc (renderer,
+					new Gtk.TreeCellDataFunc (TagsNameCellDataFunc));
+
+			tree.AppendColumn (col);
+//			tree.Model = store;
+			tree.Model = TagManager.Tags;
+			
+			Add (tree);
+		}
+		
+		#region Events
+		public event TagSelectionEventHandler TagSelected;
+		public event TagSelectionEventHandler TagUnselected;
+		#endregion // Events
+		
+		#region Public Methods
+/*
+		public void AddTag (Tag tag)
+		{
+			if (tag_iters.ContainsKey (tag.NormalizedName) == false) {
+				Gtk.TreeIter iter;
+				store.Append (out iter);
+				
+				store.SetValue (iter, 0, tag);
+				tag_iters [tag.NormalizedName] = iter;
+			}
+		}
+		
+		public void RemoveTag (Tag tag)
+		{
+			if (tag_iters.ContainsKey (tag.NormalizedName)) {
+				Gtk.TreeIter iter = tag_iters [tag.NormalizedName];
+				store.Remove (ref iter);
+				tag_iters.Remove (tag.NormalizedName);
+				if (selected_tags.ContainsKey (tag.NormalizedName))
+					selected_tags.Remove (tag.NormalizedName);
+			}
+		}
+*/		
+		public void SelectTag (Tag tag)
+		{
+			if (selected_tags.ContainsKey (tag.NormalizedName) == false) {
+				selected_tags [tag.NormalizedName] = tag;
+				
+				// Notify the listeners
+				if (TagSelected != null) {
+					try {
+						TagSelected (tag);
+					} catch (Exception e) {
+						Logger.Warn ("Error occurred in TagSelectedEventHandler: {0}\n{1}",
+							e.Message, e.StackTrace);
+					}
+				}
+				
+				// Update the TreeView by emitting a change
+				Gtk.TreeIter iter;
+				if (TagManager.GetTagIter (tag.NormalizedName, out iter)) {
+					Gtk.TreePath path = tree.Model.GetPath (iter);
+					tree.Model.EmitRowChanged (path, iter);
+				}
+			}
+		}
+		
+		public void UnselectTag (Tag tag)
+		{
+			if (selected_tags.ContainsKey (tag.NormalizedName) == true) {
+				selected_tags.Remove (tag.NormalizedName);
+				if (TagUnselected != null) {
+					try {
+						TagUnselected (tag);
+					} catch (Exception e) {
+						Logger.Warn ("Error occurred in TagUnselectedEventHandler: {0}\n{1}",
+							e.Message, e.StackTrace);
+					}
+				}
+
+				
+				// Update the TreeView by emitting a change
+				Gtk.TreeIter iter;
+				if (TagManager.GetTagIter (tag.NormalizedName, out iter)) {
+					Gtk.TreePath path = tree.Model.GetPath (iter);
+					tree.Model.EmitRowChanged (path, iter);
+				}
+			}
+		}
+		
+		public void UnselectAll ()
+		{
+			selected_tags.Clear ();
+		}
+		
+		/// <summary>
+		/// Clear out the entire tree
+		/// </summary>
+		public void Clear ()
+		{
+			tag_iters.Clear ();
+			selected_tags.Clear ();
+//			store.Clear ();
+		}
+		#endregion // Public Methods
+		
+		#region Public Properties
+		public List<Tag> SelectedTags
+		{
+			get {
+				// TODO: Should we be returning a copy (new) list object here
+				// to prevent corrupting the initial list?
+				return new List<Tag> (selected_tags.Values);
+			}
+		}
+		#endregion // Public Properties
+		
+		#region Private Methods
+		void TagsToggleCellDataFunc (Gtk.TreeViewColumn tree_column,
+				Gtk.CellRenderer cell, Gtk.TreeModel tree_model,
+				Gtk.TreeIter iter)
+		{
+			Gtk.CellRendererToggle crt = cell as Gtk.CellRendererToggle;
+			Tag tag = tree_model.GetValue (iter, 0) as Tag;
+			if (tag == null)
+				crt.Active = false;
+			else {
+				crt.Active = selected_tags.ContainsKey (tag.NormalizedName);
+			}
+		}
+		
+		void TagsNameCellDataFunc (Gtk.TreeViewColumn tree_column,
+				Gtk.CellRenderer cell, Gtk.TreeModel tree_model,
+				Gtk.TreeIter iter)
+		{
+			Gtk.CellRendererText crt = cell as Gtk.CellRendererText;
+			Tag tag = tree_model.GetValue (iter, 0) as Tag;
+			if (tag == null)
+				crt.Text = String.Empty;
+			else
+				crt.Text = tag.Name;
+		}
+		#endregion // Private Methods
+		
+		#region Event Handlers
+		void OnTagToggled (object sender, Gtk.ToggledArgs args)
+		{
+			Gtk.CellRendererToggle crt = sender as Gtk.CellRendererToggle;
+
+			Gtk.TreePath path = new Gtk.TreePath (args.Path);
+			Gtk.TreeIter iter;
+//			if (store.GetIter (out iter, path) == false)
+//				return;
+			if (tree.Model.GetIter (out iter, path) == false)
+				return;
+			
+//			Tag tag = store.GetValue (iter, 0) as Tag;
+			Tag tag = tree.Model.GetValue (iter, 0) as Tag;
+			if (tag == null)
+				return;
+			
+			if (crt.Active) {
+				// Uncheck the tag (remove the tag from selected_tags)
+				if (selected_tags.ContainsKey (tag.NormalizedName))
+					selected_tags.Remove (tag.NormalizedName);
+			} else {
+				// Check the tag (add it to selected_tags)
+				// Add the tag to the selected_tags
+				selected_tags [tag.NormalizedName] = tag;
+			}
+			
+//			UpdateResults ();
+		}
+		#endregion
+	}
+	
+	public delegate void TagSelectionEventHandler (Tag tag);
+}
Index: Tomboy/Makefile.am
===================================================================
--- Tomboy/Makefile.am	(revision 1587)
+++ Tomboy/Makefile.am	(working copy)
@@ -48,6 +48,7 @@ CSFILES = 					\
 	$(srcdir)/Note.cs 			\
 	$(srcdir)/NoteAddin.cs			\
 	$(srcdir)/NoteEditor.cs			\
+	$(srcdir)/NoteTagBar.cs			\
 	$(srcdir)/NoteManager.cs 		\
 	$(srcdir)/NoteWindow.cs 		\
 	$(srcdir)/NoteBuffer.cs 		\
@@ -58,6 +59,7 @@ CSFILES = 					\
 	$(srcdir)/Tag.cs			\
 	$(srcdir)/TagButton.cs			\
 	$(srcdir)/TagManager.cs			\
+	$(srcdir)/TagTreeWidget.cs		\
 	$(srcdir)/Tray.cs 			\
 	$(srcdir)/Trie.cs			\
 	$(srcdir)/Undo.cs 			\
