context: 
  using System;
  using System.Collections.Generic;
  using System.Text;
  using Mono.Unix;
  
  using Tomboy.Sync;
  
  namespace Tomboy
  {
  	public class PreferencesDialog : Gtk.Dialog
  	{
  		Gtk.ListStore syncAddinStore;
  		Dictionary<string, Gtk.TreeIter> syncAddinIters;
  		Gtk.ComboBox syncAddinCombo;
  		SyncServiceAddin selectedSyncAddin;
  		Gtk.VBox syncAddinPrefsContainer;
  		Gtk.Widget syncAddinPrefsWidget;
  		Gtk.Button resetSyncAddinButton;
  		Gtk.Button saveSyncAddinButton;
  		Gtk.CheckButton autosyncCheck;
  		Gtk.SpinButton autosyncSpinner;
  		Gtk.ComboBox rename_behavior_combo;
  		readonly AddinManager addin_manager;
  		
  		Gtk.Button font_button;
  		Gtk.Label font_face;
  		Gtk.Label font_size;
  
  		Mono.Addins.Gui.AddinTreeWidget addin_tree;
  
  		Gtk.Button enable_addin_button;
  		Gtk.Button disable_addin_button;
  		Gtk.Button addin_prefs_button;
  		Gtk.Button addin_info_button;
  
  		private Gtk.RadioButton promptOnConflictRadio;
  		private Gtk.RadioButton renameOnConflictRadio;
  		private Gtk.RadioButton overwriteOnConflictRadio;
  
  		/// <summary>
  		/// Keep track of the opened addin prefs dialogs so other windows
  		/// can be interacted with (as opposed to opening these as modal
  		/// dialogs).
  		///
  		/// Key = Mono.Addins.Addin.Id
  		/// </summary>
  		Dictionary<string, Gtk.Dialog> addin_prefs_dialogs;
  
  		/// <summary>
  		/// Used to keep track of open AddinInfoDialogs.
  		/// Key = Mono.Addins.Addin.Id
  		/// </summary>
  		Dictionary<string, Gtk.Dialog> addin_info_dialogs;
  
  		public PreferencesDialog (AddinManager addin_manager)
  : base ()
  		{
  			this.addin_manager = addin_manager;
  
  			IconName = "tomboy";
  			HasSeparator = false;
  			BorderWidth = 5;
  			Resizable = true;
  			Title = Catalog.GetString ("Tomboy Preferences");
  
  			ActionArea.Layout = Gtk.ButtonBoxStyle.End;
  
  			addin_prefs_dialogs =
  			        new Dictionary<string, Gtk.Dialog> ();
  			addin_info_dialogs =
  			        new Dictionary<string, Gtk.Dialog> ();
  
  			// Notebook Tabs (Editing, Hotkeys)...
  
  			Gtk.Notebook notebook = new Gtk.Notebook ();
  			notebook.TabPos = Gtk.PositionType.Top;
  			notebook.Show ();
  
  			notebook.AppendPage (MakeEditingPane (),
  			                     new Gtk.Label (Catalog.GetString ("Editing")));
  			if (! (Services.Keybinder is NullKeybinder))
  				notebook.AppendPage (MakeHotkeysPane (),
  				                     new Gtk.Label (Catalog.GetString ("Hotkeys")));
  			notebook.AppendPage (MakeSyncPane (),
  			                     new Gtk.Label (Catalog.GetString ("Synchronization")));
  			notebook.AppendPage (MakeAddinsPane (),
  			                     new Gtk.Label (Catalog.GetString ("Add-ins")));
  			
  			// TODO: Figure out a way to have these be placed in a specific order
  			foreach (PreferenceTabAddin tabAddin in addin_manager.GetPreferenceTabAddins ()) {
  				Logger.Debug ("Adding preference tab addin: {0}", tabAddin.GetType ().Name);
  				try {
  					string tabName;
  					Gtk.Widget tabWidget;
  					if (tabAddin.GetPreferenceTabWidget (this, out tabName, out tabWidget) == true) {
  						notebook.AppendPage (tabWidget, new Gtk.Label (tabName));
  					}
  				} catch {
  					Logger.Warn ("Problems adding preferences tab addin: {0}", tabAddin.GetType ().Name);
  				}
  			}
  
  			VBox.PackStart (notebook, true, true, 0);
  
  			addin_manager.ApplicationAddinListChanged += OnAppAddinListChanged;
  
  
  			// Ok button...
  
  			Gtk.Button button = new Gtk.Button (Gtk.Stock.Close);
  			button.CanDefault = true;
  			button.Show ();
  
  			Gtk.AccelGroup accel_group = new Gtk.AccelGroup ();
  			AddAccelGroup (accel_group);
  
  			button.AddAccelerator ("activate",
  			                       accel_group,
  			                       (uint) Gdk.Key.Escape,
  			                       0,
  			                       0);
  
  			AddActionWidget (button, Gtk.ResponseType.Close);
  			DefaultResponse = Gtk.ResponseType.Close;
  
  			Preferences.SettingChanged += HandlePreferencesSettingChanged;
  		}
  
  		void HandlePreferencesSettingChanged (object sender, NotifyEventArgs args)
  		{
  			if (args.Key == Preferences.NOTE_RENAME_BEHAVIOR) {
  				int rename_behavior = (int) args.Value;
  				if (rename_behavior < 0 || rename_behavior > 2) {
  					rename_behavior = 0;
  					Preferences.Set (Preferences.NOTE_RENAME_BEHAVIOR, rename_behavior);
  				}
  				if (rename_behavior_combo.Active != rename_behavior)
  					rename_behavior_combo.Active = rename_behavior;
  			} else if (args.Key == Preferences.SYNC_AUTOSYNC_TIMEOUT) {
  				int timeout = (int) args.Value;
  				if (timeout <= 0 && autosyncCheck.Active)
  					autosyncCheck.Active = false;
  				else if (timeout > 0) {
  					timeout = (timeout >= 5 && timeout < 1000) ? timeout : 5;
  					if (!autosyncCheck.Active)
  						autosyncCheck.Active = true;
  					if ((int) autosyncSpinner.Value != timeout)
  						autosyncSpinner.Value = timeout;
  				}
  			}
  		}
  		
  		// Page 1
  		// List of editing options
  		public Gtk.Widget MakeEditingPane ()
  		{
  			Gtk.Label label;
  			Gtk.CheckButton check;
  			Gtk.Alignment align;
  			IPropertyEditorBool peditor, font_peditor, bullet_peditor;
  
  			Gtk.VBox options_list = new Gtk.VBox (false, 12);
  			options_list.BorderWidth = 12;
  			options_list.Show ();
  
  
  			// Spell checking...
  
  			#if FIXED_GTKSPELL
  			if (NoteSpellChecker.GtkSpellAvailable) {
  				check = MakeCheckButton (
  				                Catalog.GetString ("_Spell check while typing"));
  				options_list.PackStart (check, false, false, 0);
  
  				peditor = Services.Factory.CreatePropertyEditorToggleButton (
  				        Preferences.ENABLE_SPELLCHECKING,
  				        check);
  				SetupPropertyEditor (peditor);
  
  				label = MakeTipLabel (
  				                Catalog.GetString ("Misspellings will be underlined " +
  				                                   "in red, with correct spelling " +
  				                                   "suggestions shown in the context " +
  				                                   "menu."));
  				options_list.PackStart (label, false, false, 0);
  			}
  			#endif
  
  
  			// WikiWords...
  
  			check = MakeCheckButton (Catalog.GetString ("Highlight _WikiWords"));
  			options_list.PackStart (check, false, false, 0);
  
  			peditor = Services.Factory.CreatePropertyEditorToggleButton (Preferences.ENABLE_WIKIWORDS,
  			                check);
  			SetupPropertyEditor (peditor);
  
  			label = MakeTipLabel (
  			                Catalog.GetString ("Enable this option to highlight " +
  			                                   "words <b>ThatLookLikeThis</b>. " +
  			                                   "Clicking the word will create a " +
  			                                   "note with that name."));
  			options_list.PackStart (label, false, false, 0);
  
  			// Auto bulleted list
  			check = MakeCheckButton (Catalog.GetString ("Enable auto-_bulleted lists"));
  			options_list.PackStart (check, false, false, 0);
  			bullet_peditor =
  			        Services.Factory.CreatePropertyEditorToggleButton (Preferences.ENABLE_AUTO_BULLETED_LISTS,
  			                                        check);
  			SetupPropertyEditor (bullet_peditor);
  
  			// Custom font...
  			Gtk.HBox font_box = new Gtk.HBox (false, 0);
  			check = MakeCheckButton (Catalog.GetString ("Use custom _font"));
  			font_box.PackStart (check);
  
  			font_peditor =
  			        Services.Factory.CreatePropertyEditorToggleButton (Preferences.ENABLE_CUSTOM_FONT,
  			                                        check);
  			SetupPropertyEditor (font_peditor);
  
  			font_button = MakeFontButton ();
  			font_button.Sensitive = check.Active;
  			font_box.PackStart (font_button);
  			font_box.ShowAll ();
  			options_list.PackStart (font_box, false, false, 0);
  
  			font_peditor.AddGuard (font_button);
  
  			// Note renaming bahvior
  			Gtk.HBox rename_behavior_box = new Gtk.HBox (false, 0);
  			label = MakeLabel (Catalog.GetString ("When renaming a linked note: "));
  			rename_behavior_box.PackStart (label);
  			rename_behavior_combo = new Gtk.ComboBox (new string [] {
  				Catalog.GetString ("Ask me what to do"),
  				Catalog.GetString ("Never rename links"),
  				Catalog.GetString ("Always rename links")});
  			int rename_behavior = (int) Preferences.Get (Preferences.NOTE_RENAME_BEHAVIOR);
  			if (rename_behavior < 0 || rename_behavior > 2) {
  				rename_behavior = 0;
  				Preferences.Set (Preferences.NOTE_RENAME_BEHAVIOR, rename_behavior);
  			}
  			rename_behavior_combo.Active = rename_behavior;
  			rename_behavior_combo.Changed += (o, e) =>
  				Preferences.Set (Preferences.NOTE_RENAME_BEHAVIOR,
  				                 rename_behavior_combo.Active);
  			rename_behavior_box.PackStart (rename_behavior_combo);
  			rename_behavior_box.ShowAll ();
  			options_list.PackStart (rename_behavior_box, false, false, 0);
  			
  			// New Note Template
  			// Translators: This is 'New Note' Template, not New 'Note Template'
  			label = MakeLabel (Catalog.GetString ("New Note Template"));
  			options_list.PackStart (label, false, false, 0);
  
  			label = MakeTipLabel (
  				Catalog.GetString ("Use the new note template to specify the text " +
  								   "that should be used when creating a new note."));
  			options_list.PackStart (label, false, false, 0);
  			
  			align = new Gtk.Alignment (0.5f, 0.5f, 0.4f, 1.0f);
  			align.Show ();
  			options_list.PackStart (align, false, false, 0);
  			
  			Gtk.Button open_template_button = new Gtk.Button ();
  			open_template_button.Label = Catalog.GetString ("Open New Note Template");
  
  			open_template_button.Clicked += OpenTemplateButtonClicked;
  			open_template_button.Show ();
  			align.Add (open_template_button);
  
  			return options_list;
  		}
  
  		Gtk.Button MakeFontButton ()
  		{
  			Gtk.HBox font_box = new Gtk.HBox (false, 0);
  			font_box.Show ();
  
  			font_face = new Gtk.Label (null);
  			font_face.UseMarkup = true;
  			font_face.Show ();
  			font_box.PackStart (font_face, true, true, 0);
  
  			Gtk.VSeparator sep = new Gtk.VSeparator ();
  			sep.Show ();
  			font_box.PackStart (sep, false, false, 0);
  
  			font_size = new Gtk.Label (null);
  			font_size.Xpad = 4;
  			font_size.Show ();
  			font_box.PackStart (font_size, false, false, 0);
  
  			Gtk.Button button = new Gtk.Button ();
  			button.Clicked += OnFontButtonClicked;
  			button.Add (font_box);
  			button.Show ();
  
  			string font_desc = (string) Preferences.Get (Preferences.CUSTOM_FONT_FACE);
  			UpdateFontButton (font_desc);
  
  			return button;
  		}
  
  		// Page 2
  		// List of Hotkey options
  		public Gtk.Widget MakeHotkeysPane ()
  		{
  			Gtk.Label label;
  			Gtk.CheckButton check;
  			Gtk.Alignment align;
  			Gtk.Entry entry;
  			IPropertyEditorBool keybind_peditor;
  			IPropertyEditor peditor;
  
  			Gtk.VBox hotkeys_list = new Gtk.VBox (false, 12);
  			hotkeys_list.BorderWidth = 12;
  			hotkeys_list.Show ();
  
  
  			// Hotkeys...
  
  			check = MakeCheckButton (Catalog.GetString ("Listen for _Hotkeys"));
  			hotkeys_list.PackStart (check, false, false, 0);
  
  			keybind_peditor =
  			        Services.Factory.CreatePropertyEditorToggleButton (Preferences.ENABLE_KEYBINDINGS,
  			                                        check);
  			SetupPropertyEditor (keybind_peditor);
  
  			label = MakeTipLabel (
  			                Catalog.GetString ("Hotkeys allow you to quickly access " +
  			                                   "your notes from anywhere with a keypress. " +
  			                                   "Example Hotkeys: " +
  			                                   "<b>&lt;Control&gt;&lt;Shift&gt;F11</b>, " +
  			                                   "<b>&lt;Alt&gt;N</b>"));
  			hotkeys_list.PackStart (label, false, false, 0);
  
  			align = new Gtk.Alignment (0.5f, 0.5f, 0.0f, 1.0f);
  			align.Show ();
  			hotkeys_list.PackStart (align, false, false, 0);
  
  			Gtk.Table table = new Gtk.Table (4, 2, false);
  			table.ColumnSpacing = 6;
  			table.RowSpacing = 6;
  			table.Show ();
  			align.Add (table);
  
  
  			// Show notes menu keybinding...
  
  			label = MakeLabel (Catalog.GetString ("Show notes _menu"));
  			table.Attach (label, 0, 1, 0, 1);
  
  			entry = new Gtk.Entry ();
  			label.MnemonicWidget = entry;
  			entry.Show ();
  			table.Attach (entry, 1, 2, 0, 1);
  
  			peditor = Services.Factory.CreatePropertyEditorEntry (Preferences.KEYBINDING_SHOW_NOTE_MENU,
  			                                   entry);
  			SetupPropertyEditor (peditor);
  
  			keybind_peditor.AddGuard (entry);
  
  
  			// Open Start Here keybinding...
  
  			label = MakeLabel (Catalog.GetString ("Open \"_Start Here\""));
  			table.Attach (label, 0, 1, 1, 2);
  
  			entry = new Gtk.Entry ();
  			label.MnemonicWidget = entry;
  			entry.Show ();
  			table.Attach (entry, 1, 2, 1, 2);
  
  			peditor = Services.Factory.CreatePropertyEditorEntry (Preferences.KEYBINDING_OPEN_START_HERE,
  			                                   entry);
  			SetupPropertyEditor (peditor);
  
  			keybind_peditor.AddGuard (entry);
  
  
  			// Create new note keybinding...
  
  			label = MakeLabel (Catalog.GetString ("Create _new note"));
  			table.Attach (label, 0, 1, 2, 3);
  
  			entry = new Gtk.Entry ();
  			label.MnemonicWidget = entry;
  			entry.Show ();
  			table.Attach (entry, 1, 2, 2, 3);
  
  			peditor = Services.Factory.CreatePropertyEditorEntry (Preferences.KEYBINDING_CREATE_NEW_NOTE,
  			                                   entry);
  			SetupPropertyEditor (peditor);
  
  			keybind_peditor.AddGuard (entry);
  
  
  			// Open Search All Notes window keybinding...
  
  			label = MakeLabel (Catalog.GetString ("Open \"Search _All Notes\""));
  			table.Attach (label, 0, 1, 3, 4);
  
  			entry = new Gtk.Entry ();
  			label.MnemonicWidget = entry;
  			entry.Show ();
  			table.Attach (entry, 1, 2, 3, 4);
  
  			peditor = Services.Factory.CreatePropertyEditorEntry (
  			        Preferences.KEYBINDING_OPEN_RECENT_CHANGES,
  			        entry);
  			SetupPropertyEditor (peditor);
  
  			keybind_peditor.AddGuard (entry);
  
  
  			return hotkeys_list;
  		}
  
  		public Gtk.Widget MakeSyncPane ()
  		{
  			Gtk.VBox vbox = new Gtk.VBox (false, 0);
  			vbox.Spacing = 4;
  			vbox.BorderWidth = 8;
  
  			Gtk.HBox hbox = new Gtk.HBox (false, 4);
  
  			Gtk.Label label = new Gtk.Label (Catalog.GetString ("Ser_vice:"));
  			label.Xalign = 0;
  			label.Show ();
  			hbox.PackStart (label, false, false, 0);
  
  			// Populate the store with all the available SyncServiceAddins
  			syncAddinStore = new Gtk.ListStore (typeof (SyncServiceAddin));
  			syncAddinIters = new Dictionary<string,Gtk.TreeIter> ();
  			SyncServiceAddin [] addins = Tomboy.DefaultNoteManager.AddinManager.GetSyncServiceAddins ();
  			Array.Sort (addins, CompareSyncAddinsByName);
  			foreach (SyncServiceAddin addin in addins) {
  				Gtk.TreeIter iter = syncAddinStore.Append ();
  				syncAddinStore.SetValue (iter, 0, addin);
  				syncAddinIters [addin.Id] = iter;
  			}
  
  			syncAddinCombo = new Gtk.ComboBox (syncAddinStore);
  			label.MnemonicWidget = syncAddinCombo;
  			Gtk.CellRendererText crt = new Gtk.CellRendererText ();
  			syncAddinCombo.PackStart (crt, true);
  			syncAddinCombo.SetCellDataFunc (crt,
  			                                new Gtk.CellLayoutDataFunc (ComboBoxTextDataFunc));
  
  			// Read from Preferences which service is configured and select it
  			// by default.  Otherwise, just select the first one in the list.
  			string addin_id = Preferences.Get (
  			                          Preferences.SYNC_SELECTED_SERVICE_ADDIN) as String;
  
  			Gtk.TreeIter active_iter;
  			if (addin_id != null && syncAddinIters.ContainsKey (addin_id)) {
  				active_iter = syncAddinIters [addin_id];
  				syncAddinCombo.SetActiveIter (active_iter);
  			} else {
  				if (syncAddinStore.GetIterFirst (out active_iter) == true) {
  					syncAddinCombo.SetActiveIter (active_iter);
  				}
  			}
  
  			syncAddinCombo.Changed += OnSyncAddinComboChanged;
  
  			syncAddinCombo.Show ();
  			hbox.PackStart (syncAddinCombo, true, true, 0);
  
  			hbox.Show ();
  			vbox.PackStart (hbox, false, false, 0);
  
  			// Get the preferences GUI for the Sync Addin
  			if (active_iter.Stamp != Gtk.TreeIter.Zero.Stamp)
  				selectedSyncAddin = syncAddinStore.GetValue (active_iter, 0) as SyncServiceAddin;
  
  			if (selectedSyncAddin != null)
  				syncAddinPrefsWidget = selectedSyncAddin.CreatePreferencesControl ();
  			if (syncAddinPrefsWidget == null) {
  				Gtk.Label l = new Gtk.Label (Catalog.GetString ("Not configurable"));
  				l.Yalign = 0.5f;
  				l.Yalign = 0.5f;
  				syncAddinPrefsWidget = l;
  			}
  			if (syncAddinPrefsWidget != null && addin_id != null &&
  			                syncAddinIters.ContainsKey (addin_id) && selectedSyncAddin.IsConfigured)
  				syncAddinPrefsWidget.Sensitive = false;
  
  			syncAddinPrefsWidget.Show ();
  			syncAddinPrefsContainer = new Gtk.VBox (false, 0);
  			syncAddinPrefsContainer.PackStart (syncAddinPrefsWidget, false, false, 0);
  			syncAddinPrefsContainer.Show ();
  			vbox.PackStart (syncAddinPrefsContainer, true, true, 10);
  
  			// Autosync preference
  			int timeout = (int) Preferences.Get (Preferences.SYNC_AUTOSYNC_TIMEOUT);
  			if (timeout > 0 && timeout < 5) {
  				timeout = 5;
  				Preferences.Set (Preferences.SYNC_AUTOSYNC_TIMEOUT, 5);
  			}
  			Gtk.HBox autosyncBox = new Gtk.HBox (false, 5);
  			// Translators: This is and the next string go together.
  			// Together they look like "Automatically Sync in Background Every [_] Minutes",
  			// where "[_]" is a GtkSpinButton.
  			autosyncCheck =
  				new Gtk.CheckButton (Catalog.GetString ("Automaticall_y Sync in Background Every"));
  			autosyncSpinner = new Gtk.SpinButton (5, 1000, 1);
  			autosyncSpinner.Value = timeout >= 5 ? timeout : 10;
  			Gtk.Label autosyncExtraText =
  				// Translators: See above comment for details on
  				// this string.
  				new Gtk.Label (Catalog.GetString ("Minutes"));
  			autosyncCheck.Active = autosyncSpinner.Sensitive = timeout >= 5;
  			EventHandler updateTimeoutPref = (o, e) => {
  				Preferences.Set (Preferences.SYNC_AUTOSYNC_TIMEOUT,
  				                 autosyncCheck.Active ? (int) autosyncSpinner.Value : -1);
  			};
  			autosyncCheck.Toggled += (o, e) => {
  				autosyncSpinner.Sensitive = autosyncCheck.Active;
  				updateTimeoutPref (o, e);
  			};
  			autosyncSpinner.ValueChanged += updateTimeoutPref;
  
  			autosyncBox.PackStart (autosyncCheck);
  			autosyncBox.PackStart (autosyncSpinner);
  			autosyncBox.PackStart (autosyncExtraText);
  			vbox.PackStart (autosyncBox, false, true, 0);
  
  			Gtk.HButtonBox bbox = new Gtk.HButtonBox ();
  			bbox.Spacing = 4;
  			bbox.LayoutStyle = Gtk.ButtonBoxStyle.End;
  
  			// "Advanced..." button to bring up extra sync config dialog
  			Gtk.Button advancedConfigButton = new Gtk.Button (Catalog.GetString ("_Advanced..."));
  			advancedConfigButton.Clicked += OnAdvancedSyncConfigButton;
  			advancedConfigButton.Show ();
  			bbox.PackStart (advancedConfigButton, false, false, 0);
  			bbox.SetChildSecondary (advancedConfigButton, true);
  
  			resetSyncAddinButton = new Gtk.Button (Gtk.Stock.Clear);
  			resetSyncAddinButton.Clicked += OnResetSyncAddinButton;
  			resetSyncAddinButton.Sensitive =
  			        (selectedSyncAddin != null &&
  			         addin_id == selectedSyncAddin.Id &&
  			         selectedSyncAddin.IsConfigured);
  			resetSyncAddinButton.Show ();
  			bbox.PackStart (resetSyncAddinButton, false, false, 0);
  
  			// TODO: Tabbing should go directly from sync prefs widget to here
  			// TODO: Consider connecting to "Enter" pressed in sync prefs widget
  			saveSyncAddinButton = new Gtk.Button (Gtk.Stock.Save);
  			saveSyncAddinButton.Clicked += OnSaveSyncAddinButton;
  			saveSyncAddinButton.Sensitive =
  			        (selectedSyncAddin != null &&
  			         (addin_id != selectedSyncAddin.Id || !selectedSyncAddin.IsConfigured));
  			saveSyncAddinButton.Show ();
  			bbox.PackStart (saveSyncAddinButton, false, false, 0);
  
  			syncAddinCombo.Sensitive =
  			        (selectedSyncAddin == null ||
  			         addin_id != selectedSyncAddin.Id ||
  			         !selectedSyncAddin.IsConfigured);
  
  			bbox.Show ();
  			vbox.PackStart (bbox, false, false, 0);
  
  			vbox.ShowAll ();
  			return vbox;
  		}
  
  		private int CompareSyncAddinsByName (SyncServiceAddin addin1, SyncServiceAddin addin2)
  		{
  			return addin1.Name.CompareTo (addin2.Name);
  		}
  
  		private void ComboBoxTextDataFunc (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell,
  		                                   Gtk.TreeModel tree_model, Gtk.TreeIter iter)
  		{
  			Gtk.CellRendererText crt = cell as Gtk.CellRendererText;
  			SyncServiceAddin addin = tree_model.GetValue (iter, 0) as SyncServiceAddin;
  			if (addin == null) {
  				crt.Text = string.Empty;
  			} else {
  				crt.Text = addin.Name;
  			}
  		}
  
  		// Page 3
  		// Extension Preferences
  		public Gtk.Widget MakeAddinsPane ()
  		{
  			Gtk.VBox vbox = new Gtk.VBox (false, 6);
  			vbox.BorderWidth = 6;
  			Gtk.Label l = new Gtk.Label (Catalog.GetString (
  			                                     "The following add-ins are installed"));
  			l.Xalign = 0;
  			l.Show ();
  			vbox.PackStart (l, false, false, 0);
  
  			Gtk.HBox hbox = new Gtk.HBox (false, 6);
  
  			// TreeView of Add-ins
  			Gtk.TreeView tree = new Gtk.TreeView ();
  			addin_tree = new Mono.Addins.Gui.AddinTreeWidget (tree);
  
  			tree.Show ();
  
  			Gtk.ScrolledWindow sw = new Gtk.ScrolledWindow ();
  			sw.HscrollbarPolicy = Gtk.PolicyType.Automatic;
  			sw.VscrollbarPolicy = Gtk.PolicyType.Automatic;
  			sw.ShadowType = Gtk.ShadowType.In;
  			sw.Add (tree);
  			sw.Show ();
  			Gtk.LinkButton get_more_link =
  				new Gtk.LinkButton ("http://live.gnome.org/Tomboy/PluginList",
  				                    Catalog.GetString ("Get More Add-Ins..."));
  			get_more_link.Clicked += delegate(object sender, EventArgs args) {
  				string uri = ((Gtk.LinkButton) sender).Uri;
  				try {
  					Services.NativeApplication.OpenUrl (uri, Screen);
  				} catch (Exception e) {
  					GuiUtils.ShowOpeningLocationError (this, uri, e.Message);
  				}
  			};
  			get_more_link.Show ();
  			Gtk.VBox tree_box = new Gtk.VBox (false, 0);
  			tree_box.Add (sw);
  			tree_box.PackEnd (get_more_link, false, false, 5);
  			tree_box.Show ();
  			hbox.PackStart (tree_box, true, true, 0);
  
  			// Action Buttons (right of TreeView)
  			Gtk.VButtonBox button_box = new Gtk.VButtonBox ();
  			button_box.Spacing = 4;
  			button_box.Layout = Gtk.ButtonBoxStyle.Start;
  
  			// TODO: In a future version, add in an "Install Add-ins..." button
  
  			// TODO: In a future version, add in a "Repositories..." button
  
  			enable_addin_button =
  			        new Gtk.Button (Catalog.GetString ("_Enable"));
  			enable_addin_button.Sensitive = false;
  			enable_addin_button.Clicked += OnEnableAddinButton;
  			enable_addin_button.Show ();
  
  			disable_addin_button =
  			        new Gtk.Button (Catalog.GetString ("_Disable"));
  			disable_addin_button.Sensitive = false;
  			disable_addin_button.Clicked += OnDisableAddinButton;
  			disable_addin_button.Show ();
  
  			addin_prefs_button =
  			        new Gtk.Button (Gtk.Stock.Preferences);
  			addin_prefs_button.Sensitive = false;
  			addin_prefs_button.Clicked += OnAddinPrefsButton;
  			addin_prefs_button.Show ();
  
  			addin_info_button =
  			        new Gtk.Button (Gtk.Stock.Info);
  			addin_info_button.Sensitive = false;
  			addin_info_button.Clicked += OnAddinInfoButton;
  			addin_info_button.Show ();
  
  			button_box.PackStart (enable_addin_button);
  			button_box.PackStart (disable_addin_button);
  			button_box.PackStart (addin_prefs_button);
  			button_box.PackStart (addin_info_button);
  
  			button_box.Show ();
  			hbox.PackStart (button_box, false, false, 0);
  
  			hbox.Show ();
  			vbox.PackStart (hbox, true, true, 0);
  			vbox.Show ();
  
  			tree.Selection.Changed += OnAddinTreeSelectionChanged;
  			LoadAddins ();
  
  			return vbox;
  		}
  
  		void OnAddinTreeSelectionChanged (object sender, EventArgs args)
  		{
  			UpdateAddinButtons ();
  		}
  
  		/// <summary>
  		/// Set the sensitivity of the buttons based on what is selected
  		/// </summary>
  		void UpdateAddinButtons ()
  		{
  			Mono.Addins.Addin sinfo =
  			        addin_tree.ActiveAddinData as Mono.Addins.Addin;
  
  			if (sinfo == null) {
  				enable_addin_button.Sensitive = false;
  				disable_addin_button.Sensitive = false;
  				addin_prefs_button.Sensitive = false;
  				addin_info_button.Sensitive = false;
  			} else {
  				enable_addin_button.Sensitive = !sinfo.Enabled;
  				disable_addin_button.Sensitive = sinfo.Enabled;
  				addin_prefs_button.Sensitive = addin_manager.IsAddinConfigurable (sinfo);
  				addin_info_button.Sensitive = true;
  			}
  		}
  
  		void LoadAddins ()
  		{
  			object s = addin_tree.SaveStatus ();
  
  			addin_tree.Clear ();
  			foreach (Mono.Addins.Addin ainfo in addin_manager.GetAllAddins ()) {
  				addin_tree.AddAddin (
  				        Mono.Addins.Setup.SetupService.GetAddinHeader (ainfo),
  				        ainfo,
  				        ainfo.Enabled,
  				        ainfo.IsUserAddin);
  			}
  
  			addin_tree.RestoreStatus (s);
  			UpdateAddinButtons ();
  		}
  
  		void OnEnableAddinButton (object sender, EventArgs args)
  		{
  			Mono.Addins.Addin sinfo =
  			        addin_tree.ActiveAddinData as Mono.Addins.Addin;
  
  			if (sinfo == null)
  				return;
  
  			EnableAddin (sinfo, true);
  		}
  
  		void OnDisableAddinButton (object sender, EventArgs args)
  		{
  			Mono.Addins.Addin sinfo =
  			        addin_tree.ActiveAddinData as Mono.Addins.Addin;
  
  			if (sinfo == null)
  				return;
  
  			EnableAddin (sinfo, false);
  		}
  
  		void EnableAddin (Mono.Addins.Addin addin, bool enable)
  		{
  			addin.Enabled = enable;
  			LoadAddins ();
  		}
  
  		void OnAddinPrefsButton (object sender, EventArgs args)
  		{
  			Gtk.Dialog dialog = null;
  			Mono.Addins.Addin addin =
  			        addin_tree.ActiveAddinData as Mono.Addins.Addin;
  
  			if (addin == null)
  				return;
  
  			if (addin_prefs_dialogs.ContainsKey (addin.Id) == false) {
  				// A preference dialog isn't open already so create a new one
  				Gtk.Image icon =
  				        new Gtk.Image (Gtk.Stock.Preferences, Gtk.IconSize.Dialog);
  				Gtk.Label caption = new Gtk.Label ();
  				caption.Markup = string.Format (
  				                         "<span size='large' weight='bold'>{0} {1}</span>",
  				                         addin.Name, addin.Version);
  				caption.Xalign = 0;
  				caption.UseMarkup = true;
  				caption.UseUnderline = false;
  
  				Gtk.Widget pref_widget =
  				        addin_manager.CreateAddinPreferenceWidget (addin);
  
  				if (pref_widget == null)
  					pref_widget = new Gtk.Label (Catalog.GetString ("Not Implemented"));
  
  				Gtk.HBox hbox = new Gtk.HBox (false, 6);
  				Gtk.VBox vbox = new Gtk.VBox (false, 6);
  				vbox.BorderWidth = 6;
  
  				hbox.PackStart (icon, false, false, 0);
  				hbox.PackStart (caption, true, true, 0);
  				vbox.PackStart (hbox, false, false, 0);
  
  				vbox.PackStart (pref_widget, true, true, 0);
  				vbox.ShowAll ();
  
  				dialog = new Gtk.Dialog (
  				        string.Format (Catalog.GetString ("{0} Preferences"),
  				                       addin.Name),
  				        this,
  				        Gtk.DialogFlags.DestroyWithParent | Gtk.DialogFlags.NoSeparator,
  				        Gtk.Stock.Close, Gtk.ResponseType.Close);
  
  				dialog.VBox.PackStart (vbox, true, true, 0);
  				dialog.DeleteEvent += AddinPrefDialogDeleted;
  				dialog.Response += AddinPrefDialogResponse;
  
  				// Store this dialog off in the dictionary so it can be
  				// presented again if the user clicks on the preferences button
  				// again before closing the preferences dialog.
  				dialog.Data ["AddinId"] = addin.Id;
  				addin_prefs_dialogs [addin.Id] = dialog;
  			} else {
  				// It's already opened so just present it again
  				dialog = addin_prefs_dialogs [addin.Id];
  			}
  
  			dialog.Present ();
  		}
  
  		[GLib.ConnectBeforeAttribute]
  		void AddinPrefDialogDeleted (object sender, Gtk.DeleteEventArgs args)
  		{
  			// Remove the addin from the addin_prefs_dialogs Dictionary
  			Gtk.Dialog dialog = sender as Gtk.Dialog;
  			dialog.Hide ();
  
  			if (dialog.Data.ContainsKey ("AddinId")) {
  				addin_prefs_dialogs.Remove (dialog.Data ["AddinId"] as String);
  			}
  
  			dialog.Destroy ();
  		}
  
  		void AddinPrefDialogResponse (object sender, Gtk.ResponseArgs args)
  		{
  			AddinPrefDialogDeleted (sender, null);
  		}
  
  		void OnAddinInfoButton (object sender, EventArgs args)
  		{
  			Mono.Addins.Addin addin =
  			        addin_tree.ActiveAddinData as Mono.Addins.Addin;
  
  			if (addin == null)
  				return;
  
  			Gtk.Dialog dialog = null;
  			if (addin_info_dialogs.ContainsKey (addin.Id) == false) {
  				dialog = new AddinInfoDialog (
  				        Mono.Addins.Setup.SetupService.GetAddinHeader (addin),
  				        this);
  				dialog.DeleteEvent += AddinInfoDialogDeleted;
  				dialog.Response += AddinInfoDialogResponse;
  
  				// Store this dialog off in a dictionary so it can be presented
  				// again if the user clicks on the Info button before closing
  				// the original dialog.
  				dialog.Data ["AddinId"] = addin.Id;
  				addin_info_dialogs [addin.Id] = dialog;
  			} else {
  				// It's already opened so just present it again
  				dialog = addin_info_dialogs [addin.Id];
  			}
  
  			dialog.Present ();
  		}
  
  		[GLib.ConnectBeforeAttribute]
  		void AddinInfoDialogDeleted (object sender, Gtk.DeleteEventArgs args)
  		{
  			// Remove the addin from the addin_prefs_dialogs Dictionary
  			Gtk.Dialog dialog = sender as Gtk.Dialog;
  			dialog.Hide ();
  
  			if (dialog.Data.ContainsKey ("AddinId")) {
  				addin_info_dialogs.Remove (dialog.Data ["AddinId"] as String);
  			}
  
  			dialog.Destroy ();
  		}
  
  		void AddinInfoDialogResponse (object sender, Gtk.ResponseArgs args)
  		{
  			AddinInfoDialogDeleted (sender, null);
  		}
  
  		void SetupPropertyEditor (IPropertyEditor peditor)
  		{
  			// Ensure the key exists
  			Preferences.Get (peditor.Key);
  			peditor.Setup ();
  		}
  
  		// Utilities...
  
  		static Gtk.Label MakeLabel (string label_text, params object[] args)
  		{
  			if (args.Length > 0)
  				label_text = String.Format (label_text, args);
  
  			Gtk.Label label = new Gtk.Label (label_text);
  
  			label.UseMarkup = true;
  			label.Justify = Gtk.Justification.Left;
  			label.SetAlignment (0.0f, 0.5f);
  			label.Show ();
  
  			return label;
  		}
  
  		static Gtk.CheckButton MakeCheckButton (string label_text)
  		{
  			Gtk.Label label = MakeLabel (label_text);
  
  			Gtk.CheckButton check = new Gtk.CheckButton ();
  			check.Add (label);
  			check.Show ();
  
  			return check;
  		}
  
  		static Gtk.Label MakeTipLabel (string label_text)
  		{
  			Gtk.Label label =  MakeLabel ("<small>{0}</small>", label_text);
  			label.LineWrap = true;
  			label.Xpad = 20;
  			return label;
  		}
  
  		// Font Change handler
  
  		void OnFontButtonClicked (object sender, EventArgs args)
  		{
  			Gtk.FontSelectionDialog font_dialog =
  			        new Gtk.FontSelectionDialog (
  			        Catalog.GetString ("Choose Note Font"));
  
  			string font_name = (string)
  			                   Preferences.Get (Preferences.CUSTOM_FONT_FACE);
  			font_dialog.SetFontName (font_name);
  
  			if ((int) Gtk.ResponseType.Ok == font_dialog.Run ()) {
  				if (font_dialog.FontName != font_name) {
  					Preferences.Set (Preferences.CUSTOM_FONT_FACE,
  					                 font_dialog.FontName);
  
  					UpdateFontButton (font_dialog.FontName);
  				}
  			}
  
  			font_dialog.Destroy ();
  		}
  
  		void UpdateFontButton (string font_desc)
  		{
  			Pango.FontDescription desc =
  			        Pango.FontDescription.FromString (font_desc);
  
  			// Set the size label
  			font_size.Text = (desc.Size / Pango.Scale.PangoScale).ToString ();
  
  			desc.UnsetFields (Pango.FontMask.Size);
  
  			// Set the font name label
  			font_face.Markup = String.Format ("<span font_desc='{0}'>{1}</span>",
  			                                  font_desc,
  			                                  desc.ToString ());
  		}
  
  		private void OnAdvancedSyncConfigButton (object sender, EventArgs args)
  		{
  			// Get saved behavior
  			SyncTitleConflictResolution savedBehavior = SyncTitleConflictResolution.Cancel;
  			object dlgBehaviorPref = Preferences.Get (Preferences.SYNC_CONFIGURED_CONFLICT_BEHAVIOR);
  			if (dlgBehaviorPref != null && dlgBehaviorPref is int) // TODO: Check range of this int
  				savedBehavior = (SyncTitleConflictResolution)dlgBehaviorPref;
  
  			// Create dialog
  			Gtk.Dialog advancedDlg =
  			        new Gtk.Dialog (Catalog.GetString ("Other Synchronization Options"),
  			                        this,
  			                        Gtk.DialogFlags.DestroyWithParent | Gtk.DialogFlags.Modal | Gtk.DialogFlags.NoSeparator,
  			                        Gtk.Stock.Close, Gtk.ResponseType.Close);
  			// Populate dialog
  			Gtk.Label label =
  			        new Gtk.Label (Catalog.GetString ("When a conflict is detected between " +
  			                                          "a local note and a note on the configured " +
  			                                          "synchronization server:"));
  			label.Wrap = true;
  			label.Xalign = 0;
  
  			promptOnConflictRadio =
  			        new Gtk.RadioButton (Catalog.GetString ("Always ask me what to do."));
  			promptOnConflictRadio.Toggled += OnConflictOptionToggle;
  
  			renameOnConflictRadio =
  			        new Gtk.RadioButton (promptOnConflictRadio, Catalog.GetString ("Rename my local note."));
  			renameOnConflictRadio.Toggled += OnConflictOptionToggle;
  
  			overwriteOnConflictRadio =
  			        new Gtk.RadioButton (promptOnConflictRadio, Catalog.GetString ("Replace my local note with the server's update."));
  			overwriteOnConflictRadio.Toggled += OnConflictOptionToggle;
  
  			switch (savedBehavior) {
  			case SyncTitleConflictResolution.RenameExistingNoUpdate:
  				renameOnConflictRadio.Active = true;
  				break;
  			case SyncTitleConflictResolution.OverwriteExisting:
  				overwriteOnConflictRadio.Active = true;
  				break;
  			default:
  				promptOnConflictRadio.Active = true;
  				break;
  			}
  
  			Gtk.VBox vbox = new Gtk.VBox ();
  			vbox.BorderWidth = 18;
  
  			vbox.PackStart (promptOnConflictRadio);
  			vbox.PackStart (renameOnConflictRadio);
  			vbox.PackStart (overwriteOnConflictRadio);
  
  			advancedDlg.VBox.PackStart (label, false, false, 6);
  			advancedDlg.VBox.PackStart (vbox, false, false, 0);
  
  			advancedDlg.ShowAll ();
  
  			// Run dialog
  			advancedDlg.Run ();
  			advancedDlg.Destroy ();
  		}
  
  		private void OnConflictOptionToggle (object sender, EventArgs args)
  		{
  			SyncTitleConflictResolution newBehavior = SyncTitleConflictResolution.Cancel;
  
  			if (renameOnConflictRadio.Active)
  				newBehavior = SyncTitleConflictResolution.RenameExistingNoUpdate;
  			else if (overwriteOnConflictRadio.Active)
  				newBehavior = SyncTitleConflictResolution.OverwriteExisting;
  
  			Preferences.Set (Preferences.SYNC_CONFIGURED_CONFLICT_BEHAVIOR,
  			                 (int) newBehavior);
  		}
  
  		private void OnAppAddinListChanged (object sender, EventArgs args)
  		{
  			SyncServiceAddin [] newAddinsArray = Tomboy.DefaultNoteManager.AddinManager.GetSyncServiceAddins ();
  			Array.Sort (newAddinsArray, CompareSyncAddinsByName);
  			List<SyncServiceAddin> newAddins = new List<SyncServiceAddin> (newAddinsArray);
  
  			// Build easier-to-navigate list if addins currently in the combo
  			List<SyncServiceAddin> currentAddins = new List<SyncServiceAddin> ();
  			foreach (object [] currentRow in syncAddinStore) {
  				SyncServiceAddin currentAddin = currentRow [0] as SyncServiceAddin;
  				if (currentAddin != null)
  					currentAddins.Add (currentAddin);
  			}
  
  			// Add new addins
  			// TODO: Would be nice to insert these alphabetically instead
  			foreach (SyncServiceAddin newAddin in newAddins) {
  				if (!currentAddins.Contains (newAddin)) {
  					Gtk.TreeIter iter = syncAddinStore.Append ();
  					syncAddinStore.SetValue (iter, 0, newAddin);
  					syncAddinIters [newAddin.Id] = iter;
  				}
  			}
  
  			// Remove deleted addins
  			foreach (SyncServiceAddin currentAddin in currentAddins) {
  				if (!newAddins.Contains (currentAddin)) {
  					Gtk.TreeIter iter = syncAddinIters [currentAddin.Id];
  					syncAddinStore.Remove (ref iter);
  					syncAddinIters.Remove (currentAddin.Id);
  
  					// FIXME: Lots of hacky stuff in here...rushing before freeze
  					if (currentAddin == selectedSyncAddin) {
  						if (syncAddinPrefsWidget != null &&
  						                !syncAddinPrefsWidget.Sensitive)
  							OnResetSyncAddinButton (null, null);
  
  						Gtk.TreeIter active_iter;
  						if (syncAddinStore.GetIterFirst (out active_iter) == true) {
  							syncAddinCombo.SetActiveIter (active_iter);
  						} else {
  							OnSyncAddinComboChanged (null, null);
  						}
  					}
  				}
  			}
  		}
  
  		void OnSyncAddinComboChanged (object sender, EventArgs args)
  		{
  			if (syncAddinPrefsWidget != null) {
  				syncAddinPrefsContainer.Remove (syncAddinPrefsWidget);
  				syncAddinPrefsWidget.Hide ();
  				syncAddinPrefsWidget.Destroy ();
  				syncAddinPrefsWidget = null;
  			}
  
  			Gtk.TreeIter iter;
  			if (syncAddinCombo.GetActiveIter (out iter)) {
  				SyncServiceAddin newAddin =
  				        syncAddinStore.GetValue (iter, 0) as SyncServiceAddin;
  				if (newAddin != null) {
  					selectedSyncAddin = newAddin;
  					syncAddinPrefsWidget = selectedSyncAddin.CreatePreferencesControl ();
  					if (syncAddinPrefsWidget == null) {
  						Gtk.Label l = new Gtk.Label (Catalog.GetString ("Not configurable"));
  						l.Yalign = 0.5f;
  						l.Yalign = 0.5f;
  						syncAddinPrefsWidget = l;
  					}
  
  					syncAddinPrefsWidget.Show ();
  					syncAddinPrefsContainer.PackStart (syncAddinPrefsWidget, false, false, 0);
  
  					resetSyncAddinButton.Sensitive = false;
  					saveSyncAddinButton.Sensitive = true;
  				}
  			} else {
  				selectedSyncAddin = null;
  				resetSyncAddinButton.Sensitive = false;
  				saveSyncAddinButton.Sensitive = false;
  			}
  
  		}
  
  		void OnResetSyncAddinButton (object sender, EventArgs args)
  		{
  			if (selectedSyncAddin == null)
  				return;
  
  			// User doesn't get a choice if this is invoked by disabling the addin
  			// FIXME: null sender check is lame!
  			if (sender != null) {
  				// Prompt the user about what they're about to do since
  				// it's not really recommended to switch back and forth
  				// between sync services.
  				HIGMessageDialog dialog =
  				        new HIGMessageDialog (null,
  				                              Gtk.DialogFlags.Modal,
  				                              Gtk.MessageType.Question,
  				                              Gtk.ButtonsType.YesNo,
  				                              Catalog.GetString ("Are you sure?"),
  				                              Catalog.GetString (
  				                                      "Clearing your synchronization settings is not recommended.  " +
  				                                      "You may be forced to synchronize all of your notes again " +
  				                                      "when you save new settings."));
  				int response = dialog.Run ();
  				dialog.Destroy ();
  				if (response != (int) Gtk.ResponseType.Yes)
  					return;
  			} else { // FIXME: Weird place for this to go.  User should be able to cancel disabling of addin, anyway
  				HIGMessageDialog dialog =
  				        new HIGMessageDialog (null,
  				                              Gtk.DialogFlags.Modal,
  				                              Gtk.MessageType.Info,
  				                              Gtk.ButtonsType.Ok,
  				                              Catalog.GetString ("Resetting Synchronization Settings"),
  				                              Catalog.GetString (
  				                                      "You have disabled the configured synchronization service.  " +
  				                                      "Your synchronization settings will now be cleared.  " +
  				                                      "You may be forced to synchronize all of your notes again " +
  				                                      "when you save new settings"));
  				dialog.Run ();
  				dialog.Destroy ();
  			}
  
  			try {
  				selectedSyncAddin.ResetConfiguration ();
  			} catch (Exception e) {
  				Logger.Debug ("Error calling {0}.ResetConfiguration: {1}\n{2}",
  				              selectedSyncAddin.Id, e.Message, e.StackTrace);
  			}
  
  			Preferences.Set (
  			        Preferences.SYNC_SELECTED_SERVICE_ADDIN,
  			        String.Empty);
  
  			// Reset conflict handling behavior
  			Preferences.Set (
  			        Preferences.SYNC_CONFIGURED_CONFLICT_BEHAVIOR,
  			        Preferences.GetDefault (Preferences.SYNC_CONFIGURED_CONFLICT_BEHAVIOR));
  
  			SyncManager.ResetClient ();
  
  			syncAddinCombo.Sensitive = true;
  			resetSyncAddinButton.Sensitive = false;
  			saveSyncAddinButton.Sensitive = true;
  			if (syncAddinPrefsWidget != null)
  				syncAddinPrefsWidget.Sensitive = true;
  		}
  
  		/// <summary>
  		/// Attempt to save/test the connection to the sync addin.
  		/// </summary>
  		void OnSaveSyncAddinButton (object sender, EventArgs args)
  		{
  
gt: 			if (selectedSyncAddin == null)