Index: Tomboy/Preferences.cs
===================================================================
RCS file: /cvs/gnome/tomboy/Tomboy/Preferences.cs,v
retrieving revision 1.15
diff -u -r1.15 Preferences.cs
--- Tomboy/Preferences.cs	27 Nov 2006 23:12:05 -0000	1.15
+++ Tomboy/Preferences.cs	28 Nov 2006 17:49:46 -0000
@@ -122,8 +122,19 @@
 		Gtk.Button font_button;
 		Gtk.Label font_face;
 		Gtk.Label font_size;
+		NoteManager manager;
+		
+		Gtk.ComboBox plugins_combo;
+		Gtk.ListStore plugins_store;
+		Gtk.VBox plugin_widget;
+		Gtk.Notebook plugin_notebook;
+		Gtk.Label plugin_name;
+		Gtk.Label plugin_description;
+		Gtk.Label plugin_author;
+		Gtk.Label plugin_website;
+		Gtk.Label plugin_filename;
 
-		public PreferencesDialog ()
+		public PreferencesDialog (NoteManager manager)
 			: base ()
 		{
 			IconName = "tomboy";
@@ -131,6 +142,7 @@
 			BorderWidth = 5;
 			Resizable = false;
 			Title = Catalog.GetString ("Tomboy Preferences");
+			this.manager = manager;
 
 			VBox.Spacing = 5;
 			ActionArea.Layout = Gtk.ButtonBoxStyle.End;
@@ -144,10 +156,13 @@
 			notebook.Show ();
 
 			notebook.AppendPage (MakeEditingPane (), 
-					     new Gtk.Label (Catalog.GetString ("Editing")));
+				new Gtk.Label (Catalog.GetString ("Editing")));
 
 			notebook.AppendPage (MakeHotkeysPane (), 
-					     new Gtk.Label (Catalog.GetString ("Hotkeys")));
+				new Gtk.Label (Catalog.GetString ("Hotkeys")));
+			
+			notebook.AppendPage (MakePluginsPane (),
+				new Gtk.Label (Catalog.GetString ("Plugins")));
 
 			VBox.PackStart (notebook, true, true, 0);
 
@@ -390,6 +405,151 @@
 
 			return hotkeys_list;
 		}
+		
+		// Page 3
+		// Plugin Preferences
+		public Gtk.Widget MakePluginsPane ()
+		{
+			Gtk.VBox vbox = new Gtk.VBox (false, 12);
+			vbox.BorderWidth = 12;
+			vbox.Show ();
+			
+			// Set up the ComboBox to hold the list of configurable plugins
+			plugins_combo = new Gtk.ComboBox ();
+			Gtk.CellRendererText text_cr = new Gtk.CellRendererText ();
+			plugins_combo.PackStart (text_cr, true);
+			plugins_combo.SetCellDataFunc (text_cr, ShowPluginName);
+			
+			Gtk.HBox hbox = new Gtk.HBox (false, 12);
+			vbox.PackStart (hbox, false, false, 0);
+			Gtk.Label l = new Gtk.Label (Catalog.GetString ("Active _Plugins:"));
+			l.MnemonicWidget = plugins_combo;
+			hbox.PackStart (l, false, false, 0);
+			hbox.PackStart (plugins_combo, false, false, 0);
+			hbox.PackStart (new Gtk.Label (" "), true, true, 0); // spacer
+			Gtk.Button open_plugins_dir_button = new Gtk.Button (
+						Catalog.GetString ("_Open Plugins Folder"));
+			open_plugins_dir_button.Clicked += OpenPluginsDirectory;
+			hbox.PackStart (open_plugins_dir_button, false, false, 0);
+			
+			// Store the list of configurable plugins
+			Gtk.TreeIter iter;
+			plugins_store = new Gtk.ListStore (typeof (NotePlugin));
+			NotePlugin [] plugins =
+				manager.PluginManager.Plugins;
+			if (plugins != null && plugins.Length > 0) {
+				foreach (NotePlugin plugin in plugins) {
+					iter = plugins_store.Append ();
+					plugins_store.SetValue (iter, 0, plugin);
+				}
+			}
+			
+			// Set up the notebook that will display the plugin information
+			plugin_notebook = new Gtk.Notebook ();
+			plugin_notebook.HomogeneousTabs = false;
+			plugin_notebook.TabPos = Gtk.PositionType.Bottom;
+			
+			plugin_notebook.AppendPage (CreatePluginConfigPage (),
+							new Gtk.Label (Catalog.GetString ("Configuration")));
+			plugin_notebook.AppendPage (CreatePluginDetailsPage (),
+							new Gtk.Label (Catalog.GetString ("Details")));
+			
+			vbox.PackStart (plugin_notebook, true, true, 0);
+
+			plugins_combo.Changed += SelectedPluginChanged;
+			plugins_combo.Model = plugins_store;
+			
+			// Select the first plugin (if available)
+			if (plugins_store.GetIterFirst (out iter))
+				plugins_combo.SetActiveIter (iter);
+			
+			vbox.ShowAll ();
+			
+			return vbox;
+		}
+		
+		Gtk.Widget CreatePluginConfigPage ()
+		{
+			plugin_widget = new Gtk.VBox (false, 0);
+			return plugin_widget;
+		}
+		
+		Gtk.Widget CreatePluginDetailsPage ()
+		{
+			Gtk.VBox vbox = new Gtk.VBox (false, 0);
+			vbox.BorderWidth = 5;
+
+			plugin_name = new Gtk.Label ();
+			plugin_name.UseMarkup = true;
+			plugin_name.UseUnderline = false;
+			
+			vbox.PackStart (plugin_name, false, false, 0);
+			
+			Gtk.Table table = new Gtk.Table (4, 2, false);
+			table.ColumnSpacing = 5;
+			table.RowSpacing = 5;
+			
+			// Description
+			Gtk.Label l = new Gtk.Label (
+				string.Format ("<span weight=\"bold\">{0}</span>", 
+								Catalog.GetString ("Description:")));
+			l.UseMarkup = true;
+			l.Xalign = 0;
+			table.Attach (l, 0, 1, 0, 1, Gtk.AttachOptions.Fill, 0, 0, 0);
+
+			plugin_description = new Gtk.Label ();
+			plugin_description.UseUnderline = false;
+			plugin_description.Wrap = true;
+			plugin_description.Xalign = 0;
+			table.Attach (plugin_description, 1, 2, 0, 1,
+				Gtk.AttachOptions.Expand | Gtk.AttachOptions.Fill, 0, 0, 0);
+			
+			// Author
+			l = new Gtk.Label (
+				string.Format ("<span weight=\"bold\">{0}</span>",
+								Catalog.GetString ("Written by:")));
+			l.UseMarkup = true;
+			l.Xalign = 0;
+			table.Attach (l, 0, 1, 1, 2, Gtk.AttachOptions.Fill, 0, 0, 0);
+
+			plugin_author = new Gtk.Label ();
+			plugin_author.UseUnderline = false;
+			plugin_author.Xalign = 0;
+			table.Attach (plugin_author, 1, 2, 1, 2,
+				Gtk.AttachOptions.Expand | Gtk.AttachOptions.Fill, 0, 0, 0);
+			
+			// Web site
+			l = new Gtk.Label (
+				string.Format ("<span weight=\"bold\">{0}</span>",
+								Catalog.GetString ("Web site:")));
+			l.UseMarkup = true;
+			l.Xalign = 0;
+			table.Attach (l, 0, 1, 2, 3, Gtk.AttachOptions.Fill, 0, 0, 0);
+
+			plugin_website = new Gtk.Label ();
+			plugin_website.UseUnderline = false;
+			plugin_website.Xalign = 0;
+			table.Attach (plugin_website, 1, 2, 2, 3,
+				Gtk.AttachOptions.Expand | Gtk.AttachOptions.Fill, 0, 0, 0);
+			
+			// File name
+			l = new Gtk.Label (
+				string.Format ("<span weight=\"bold\">{0}</span>",
+								Catalog.GetString ("File name:")));
+			l.UseMarkup = true;
+			l.Xalign = 0;
+			table.Attach (l, 0, 1, 3, 4, Gtk.AttachOptions.Fill, 0, 0, 0);
+
+			plugin_filename = new Gtk.Label ();
+			plugin_filename.UseUnderline = false;
+			plugin_filename.Xalign = 0;
+			table.Attach (plugin_filename, 1, 2, 3, 4,
+				Gtk.AttachOptions.Expand | Gtk.AttachOptions.Fill, 0, 0, 0);
+			
+			vbox.PackStart (table, true, false, 12);
+			
+			return vbox;
+		}
 
 		void SetupPropertyEditor (PropertyEditor peditor)
 		{
@@ -452,7 +612,7 @@
 
 			font_dialog.Destroy ();
 		}
-
+		
 		void UpdateFontButton (string font_desc)
 		{
 			Pango.FontDescription desc = Pango.FontDescription.FromString (font_desc);
@@ -466,6 +626,71 @@
 			font_face.Markup = String.Format ("<span font_desc='{0}'>{1}</span>",
 							  font_desc,
 							  desc.ToString ());
+		}
+		
+		void ShowPluginName (Gtk.CellLayout cell_layout, Gtk.CellRenderer renderer,
+								Gtk.TreeModel model, Gtk.TreeIter iter)
+		{
+			NotePlugin plugin =
+				model.GetValue (iter, 0) as NotePlugin;
+			
+			((Gtk.CellRendererText) renderer).Text = plugin.Name;
+		}
+		
+		void SelectedPluginChanged (object sender, EventArgs args)
+		{
+			// Clear out a previous plugin's GUI
+			Gtk.Widget child;
+			Gtk.Widget [] children = plugin_widget.Children;
+			if (children != null && children.Length > 0) {
+				child = children [0];
+				if (child != null) {
+					plugin_widget.Remove (child);
+					child.Hide ();
+					child.Destroy ();
+				}
+			}
+			
+			NotePlugin plugin = GetSelectedPlugin ();
+			if (plugin == null)
+				return;
+			
+			if (plugin is IConfigurablePlugin) {
+				child = ((IConfigurablePlugin) plugin).CreatePreferencesWidget ();
+			} else {
+				string msg = Catalog.GetString ("This plugin is not configurable.");
+				child = new Gtk.Label (msg);
+			}
+			
+			child.ShowAll ();
+			
+			plugin_widget.PackStart (child, true, true, 0);
+			plugin_widget.ShowAll ();
+			
+			plugin_name.Markup = string.Format (
+					"<span size=\"large\" weight=\"bold\">{0} {1}</span>",
+					plugin.Name,
+					plugin.Version);
+			
+			plugin_description.Text = plugin.Description;
+			plugin_author.Text = plugin.Author;
+			plugin_website.Text = plugin.WebSite;
+			plugin_filename.Text = plugin.FileName;
+		}
+
+		void OpenPluginsDirectory (object sender, EventArgs args)
+		{
+			manager.PluginManager.ShowPluginsDirectory ();
+		}
+		
+		NotePlugin GetSelectedPlugin ()
+		{
+			Gtk.TreeIter iter;
+			
+			if (!plugins_combo.GetActiveIter (out iter))
+				return null;
+			
+			return plugins_store.GetValue (iter, 0) as NotePlugin;
 		}
 	}
 }
Index: Tomboy/Tray.cs
===================================================================
RCS file: /cvs/gnome/tomboy/Tomboy/Tray.cs,v
retrieving revision 1.55
diff -u -r1.55 Tray.cs
--- Tomboy/Tray.cs	22 Nov 2006 09:58:06 -0000	1.55
+++ Tomboy/Tray.cs	28 Nov 2006 17:49:46 -0000
@@ -358,7 +358,7 @@
 		public void ShowPreferences ()
 		{
 			if (prefs_dlg == null) {
-				prefs_dlg = new PreferencesDialog ();
+				prefs_dlg = new PreferencesDialog (manager);
 				prefs_dlg.Response += OnPreferencesResponse;
 			}
 			prefs_dlg.Present ();
Index: Tomboy/PluginManager.cs
===================================================================
RCS file: /cvs/gnome/tomboy/Tomboy/PluginManager.cs,v
retrieving revision 1.18
diff -u -r1.18 PluginManager.cs
--- Tomboy/PluginManager.cs	6 Sep 2006 18:47:51 -0000	1.18
+++ Tomboy/PluginManager.cs	28 Nov 2006 17:49:46 -0000
@@ -13,7 +13,46 @@
 		Note note;
 		ArrayList plugin_menu_items;
 		ArrayList text_menu_items;
-
+		
+		// Override this property in your plugin to provide a human-readable name.
+		public virtual string Name
+		{
+			get {
+				// Use reflection to figure out the Class name of the plugin
+				return GetType ().ToString ();
+			}
+		}
+		
+		// Override this property in your plugin to provide a description.
+		public virtual string Description
+		{
+			get { return String.Empty; }
+		}
+		
+		// Override this property in your plugin to provide a version string.
+		public virtual string Version
+		{
+			get { return Defines.VERSION; }
+		}
+		
+		// Override this property in your plugin to proivde an author.
+		public virtual string Author
+		{
+			get { return String.Empty; }
+		}
+		
+		// Override this property in your plugin to provide a web site.
+		public virtual string WebSite
+		{
+			get { return String.Empty; }
+		}
+		
+		// Returns the path to the plugin's assembly.
+		public string FileName
+		{
+			get { return GetType ().Assembly.Location; }
+		}
+		
 		public void Initialize (Note note)
 		{
 			this.note = note;
@@ -114,6 +153,19 @@
 			}
 		}
 	}
+	
+	/// <summary>
+	/// Implement this interface if your plugin needs user configuration
+	/// from Tomboy's Preferences Dialog.
+	/// </summary>
+	public interface IConfigurablePlugin
+	{
+		/// <summary>
+		/// Returns a Gtk.Widget that will be placed in Tomboy's preferences
+		/// dialog.
+		/// </summary>
+		Gtk.Widget CreatePreferencesWidget ();
+	}
 
 	public class PluginManager
 	{
@@ -137,6 +189,25 @@
 				// typeof (NoteRelatedToWatcher),
 				// typeof (IndentWatcher),
 			};
+		
+		public NotePlugin [] Plugins
+		{
+			get {
+				ArrayList plugins = new ArrayList ();
+
+				foreach (Type type in plugin_types) {
+					try {
+						NotePlugin plugin = (NotePlugin) 
+							Activator.CreateInstance (type);
+						if (plugin != null && !plugin.Name.StartsWith ("Tomboy.")) {
+							plugins.Add (plugin);
+						}
+					} catch {}
+				}
+				
+				return plugins.ToArray (typeof (NotePlugin)) as NotePlugin [];
+			}
+		}
 
 		public PluginManager (string plugins_dir)
 		{
Index: Tomboy/Plugins/Bugzilla.cs
===================================================================
RCS file: /cvs/gnome/tomboy/Tomboy/Plugins/Bugzilla.cs,v
retrieving revision 1.3
diff -u -r1.3 Bugzilla.cs
--- Tomboy/Plugins/Bugzilla.cs	16 Nov 2006 07:05:10 -0000	1.3
+++ Tomboy/Plugins/Bugzilla.cs	28 Nov 2006 17:49:46 -0000
@@ -153,13 +153,33 @@
 	}
 }
 
-public class BugzillaPlugin : NotePlugin
+public class BugzillaPlugin : NotePlugin, IConfigurablePlugin
 {
 	static int last_bug;
 
 	static BugzillaPlugin ()
 	{
 		last_bug = -1;
+	}
+	
+	public override string Name
+	{
+		get { return "Bugzilla Plugin"; }
+	}
+	
+	public override string Description
+	{
+		get { return "FIXME: Does cool stuff with URLs from Bugzilla."; }
+	}
+	
+	public override string Author
+	{
+		get { return "David Trowbridge <trowbrds@gmail.com>"; }
+	}
+	
+	public Gtk.Widget CreatePreferencesWidget ()
+	{
+		return new Gtk.Label ("FIXME: Implement BugzillaPlugin.CreatePreferencesWidget");
 	}
 
 	protected override void Initialize ()
