F-Spot plug-ins



Hi everyone,

I'm quite proud to give you this patch, adding support for loading
plug-ins into F-Spot. I'll submit it to b.g.o. soon.

For now, all Plugins in all .dll in $HOME/.gnome2/f-spot/plugins are
loaded, but I plan to write another plugin to enable them at will.

The patch include Thomas's solution to #344534, so you can compile
plug-ins from outside the source tree using:

mcs -target:library -pkg:f-spot MyPlugin.cs

Find also attached below 2 plugins, one displaying a dialog about
plugins, and a first Export Plug-in, for sending mail (the export code
is just a cut and paste from F-Spot core code).

Those 2 plugins compile with:

mcs -target:library -pkg:f-spot -pkg:gnome-sharp-2.0 DialogPlugin.cs
mcs -target:library -pkg:f-spot -pkg:gnome-sharp-2.0 SendMailPlugin.cs

It's a first and very early version, so write a lot of comments about
it...

rgds,

Stephane
Index: Makefile.am
===================================================================
RCS file: /cvs/gnome/f-spot/Makefile.am,v
retrieving revision 1.13
diff -u -p -r1.13 Makefile.am
--- Makefile.am	17 Feb 2006 17:02:32 -0000	1.13
+++ Makefile.am	19 Jun 2006 15:54:03 -0000
@@ -17,6 +17,9 @@ desktop_in_files=	\
 desktop_files=$(desktop_in_files:.desktop.in=.desktop)
 @INTLTOOL_DESKTOP_RULE@
 
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = f-spot.pc
+
 Applicationsdir = $(datadir)/applications
 Applications_DATA = $(desktop_files)
 
@@ -30,6 +33,7 @@ EXTRA_DIST =			\
 	intltool-extract.in	\
 	intltool-merge.in	\
 	intltool-update.in	\
+	f-spot.pc.in		\
 	f-spot.spec		\
         $(desktop_in_files)     \
         $(desktop_files)
Index: configure.in
===================================================================
RCS file: /cvs/gnome/f-spot/configure.in,v
retrieving revision 1.102
diff -u -p -r1.102 configure.in
--- configure.in	24 May 2006 15:44:42 -0000	1.102
+++ configure.in	19 Jun 2006 15:54:03 -0000
@@ -182,6 +182,7 @@ po/Makefile.in
 src/Defines.cs
 src/f-spot.exe.config
 src/Makefile
+f-spot.pc
 f-spot.spec
 f-spot.desktop.in
 ])
Index: src/Global.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/Global.cs,v
retrieving revision 1.8
diff -u -p -r1.8 Global.cs
--- src/Global.cs	22 Mar 2006 19:14:41 -0000	1.8
+++ src/Global.cs	19 Jun 2006 15:54:03 -0000
@@ -18,6 +18,12 @@ namespace FSpot {
 			}
 		}
 
+		public static string PluginsDirectory {
+			get {
+				return System.IO.Path.Combine (BaseDirectory, "plugins");
+			}
+		}
+
 		public static void ModifyColors (Gtk.Widget widget)
 		{
 			try {
Index: src/MainWindow.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/MainWindow.cs,v
retrieving revision 1.298
diff -u -p -r1.298 MainWindow.cs
--- src/MainWindow.cs	9 Jun 2006 23:24:57 -0000	1.298
+++ src/MainWindow.cs	19 Jun 2006 15:54:05 -0000
@@ -44,6 +44,7 @@ public class MainWindow {
 	[Glade.Widget] MenuItem rename_version_menu_item;
 	
 	[Glade.Widget] MenuItem export;
+	[Glade.Widget] MenuItem export_menu_item;
 	[Glade.Widget] MenuItem print;
 	[Glade.Widget] MenuItem send_mail;
 
@@ -107,6 +108,8 @@ public class MainWindow {
 
 	PhotoVersionMenu versions_submenu;
 
+	ExportMenu export_submenu;
+
 	Gtk.ToggleButton browse_button;
 	Gtk.ToggleButton edit_button;
 
@@ -376,6 +379,10 @@ public class MainWindow {
 		// When the icon_view is loaded, set it's initial scroll position
 		icon_view.SizeAllocated += HandleIconViewReady;
 
+System.Console.WriteLine("###############################################");
+FSpot.Plugins.Plugger plugger = new FSpot.Plugins.Plugger();
+System.Console.WriteLine("###############################################");
+
 		UpdateToolbar ();
 	}
 
@@ -1463,7 +1470,8 @@ public class MainWindow {
 			"Joshua Tauberer",
 			"Joerg Buesse",
 			"Jakub Steiner",
-			"Xavier Bouchoux"
+			"Xavier Bouchoux",
+			"Stephane Delcroix"
 		};
 
                 // Translators should localize the following string
@@ -2495,6 +2503,9 @@ public class MainWindow {
 			version_menu_item.Submenu = versions_submenu;
 		}
 
+		export_submenu = new ExportMenu ();
+		export_menu_item.Submenu = export_submenu;
+
 		set_as_background.Sensitive = single_active;
 		adjust_color.Sensitive = single_active;
 		adjust_time.Sensitive = active_selection;
@@ -2905,4 +2916,12 @@ public class MainWindow {
 	{
 		toolTips.SetTip (widget, tip, null);
 	}
+
+	//
+	//Hooks for plugin
+	//
+	public void HandleExportWithPlugin (FSpot.Plugins.ExportPlugin ex_plugin) {
+		ex_plugin.DoExport(new FSpot.PhotoArray (SelectedPhotos ()));
+	}
+	
 }
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/f-spot/src/Makefile.am,v
retrieving revision 1.63
diff -u -p -r1.63 Makefile.am
--- src/Makefile.am	26 Apr 2006 20:31:07 -0000	1.63
+++ src/Makefile.am	19 Jun 2006 15:54:06 -0000
@@ -25,6 +25,7 @@ F_SPOT_CSDISTFILES =				\
 	$(srcdir)/DirectoryCollection.cs	\
 	$(srcdir)/ExceptionDialog.cs		\
 	$(srcdir)/Exif.cs			\
+	$(srcdir)/ExportMenu.cs			\
 	$(srcdir)/FlickrExport.cs		\
 	$(srcdir)/FlickrRemote.cs		\
 	$(srcdir)/FileImportBackend.cs		\
@@ -79,6 +80,7 @@ F_SPOT_CSDISTFILES =				\
 	$(srcdir)/PixbufUtils.cs		\
 	$(srcdir)/PixbufCache.cs		\
 	$(srcdir)/PixelBuffer.cs		\
+	$(srcdir)/Plugins.cs		\
 	$(srcdir)/PreferenceDialog.cs		\
 	$(srcdir)/Preferences.cs 		\
 	$(srcdir)/PreviewPopup.cs 		\
Index: src/f-spot.glade
===================================================================
RCS file: /cvs/gnome/f-spot/src/f-spot.glade,v
retrieving revision 1.164
diff -u -p -r1.164 f-spot.glade
--- src/f-spot.glade	6 Jun 2006 18:09:47 -0000	1.164
+++ src/f-spot.glade	19 Jun 2006 15:54:20 -0000
@@ -7250,6 +7250,20 @@ Photo Details</property>
 			      <signal name="activate" handler="HandleExportToCD" last_modification_time="Wed, 12 Jan 2005 22:49:52 GMT"/>
 			    </widget>
 			  </child>
+
+			  <child>
+			    <widget class="GtkSeparatorMenuItem" id="separator116">
+			      <property name="visible">True</property>
+			    </widget>
+			  </child>
+
+			  <child>
+			    <widget class="GtkMenuItem" id="export_menu_item">
+			      <property name="visible">True</property>
+			      <property name="label" translatable="yes">Export plugins</property>
+			      <property name="use_underline">True</property>
+			    </widget>
+			  </child>
 			</widget>
 		      </child>
 		    </widget>
@@ -7272,7 +7286,7 @@ Photo Details</property>
 		      <signal name="activate" handler="HandleSendMailCommand" last_modification_time="Mon, 07 Jun 2004 22:31:01 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image40">
+			<widget class="GtkImage" id="image43">
 			  <property name="visible">True</property>
 			  <property name="stock">gnome-stock-mail-fwd</property>
 			  <property name="icon_size">1</property>
@@ -7297,8 +7311,8 @@ Photo Details</property>
 		      <property name="label" translatable="yes">_Close</property>
 		      <property name="use_underline">True</property>
 		      <signal name="activate" handler="HandleCloseCommand" last_modification_time="Tue, 09 Dec 2003 20:59:54 GMT"/>
-		      <accelerator key="q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
 		      <accelerator key="w" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+		      <accelerator key="q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
 		    </widget>
 		  </child>
 		</widget>
@@ -7635,7 +7649,7 @@ Photo Details</property>
 			      <property name="visible">True</property>
 			      <property name="label" translatable="yes">_Folder</property>
 			      <property name="use_underline">True</property>
-			      <property name="active">False</property>
+			      <property name="active">True</property>
 			      <property name="group">month</property>
 			      <signal name="activate" handler="HandleArrangeByDirectory" last_modification_time="Fri, 20 Aug 2004 22:26:32 GMT"/>
 			    </widget>
--- /dev/null	2006-06-19 09:02:49.376262000 +0200
+++ src/Plugins.cs	2006-06-19 17:38:29.000000000 +0200
@@ -0,0 +1,120 @@
+/*
+ * Plugins.cs
+ *
+ * Authors:
+ *   Stephane Delcroix <stephane delcroix org>
+ *
+ * Copyright (C) 2006 Stephane Delcroix
+ *
+ */
+
+
+using System;
+using System.Reflection;
+
+using System.Collections;
+
+using FSpot;
+
+namespace FSpot.Plugins {
+
+	public class Plugger {
+		private static System.Collections.Hashtable plugins = new System.Collections.Hashtable();
+
+		public static string [] PluginsList {
+			get {
+				string [] list = new String[plugins.Count];
+				plugins.Keys.CopyTo(list,0);
+				return list;
+			}
+		}
+
+		public static string [] LoadedPlugins (System.Type type) {
+			ArrayList loadedplugins = new ArrayList();
+			foreach (string plugin in PluginsList){
+				if ( ((Plugin)plugins[plugin]).IsLoaded && (plugins[plugin]).GetType().IsSubclassOf(type))
+					loadedplugins.Add(plugin);
+			}
+			return (string [])loadedplugins.ToArray(typeof(System.String));
+		}
+
+		public static string [] LoadedPlugins() { return LoadedPlugins(typeof(FSpot.Plugins.Plugin)); }
+
+		public static Plugin Plugin(string ShortName) 
+		{
+			return (Plugin)plugins[ShortName];
+		}
+
+		public Plugger ()
+		{
+			LoadPluginsFromDirectory(FSpot.Global.PluginsDirectory);
+			InitializePlugins(PluginsList);
+		}
+
+		public void LoadPluginsFromDirectories (string [] directories)
+		{
+			foreach ( String directory in directories )
+				LoadPluginsFromDirectory (directory);
+		}
+
+		private void LoadPluginsFromDirectory (string path)
+		{
+			foreach ( String dll in System.IO.Directory.GetFiles(path, "*.dll") )
+				LoadPluginsFromFile(dll);
+		}
+
+		private void LoadPluginsFromFile(string pluginfile) 
+		{
+			Console.WriteLine ("Loading plugins from {0}...", pluginfile);
+			Assembly assembly = Assembly.LoadFile(pluginfile);
+			Type [] ts = assembly.GetTypes();
+			foreach (Type t in ts){
+				if ( t.IsSubclassOf(typeof(FSpot.Plugins.Plugin)) ){
+					Plugin plugin = (Plugin)assembly.CreateInstance(t.ToString());
+					Console.WriteLine("{0} available", t);
+					//FIXME: check if ShortName already exists in plugins[]
+					plugins [plugin.ShortName] = plugin;
+				} else
+					Console.WriteLine("{0} is NOT a Plugin", t);
+			}
+		}
+
+		public void InitializePlugins(string [] pluginslist)
+		{
+			foreach (String plugin in pluginslist) {
+				((Plugin)plugins[plugin]).Load();
+			}
+		}
+	}
+	
+	public abstract class Plugin {
+		public abstract string DisplayName { get; }
+		public virtual string ShortName { get { return DisplayName; } }
+		public abstract string Description { get; }
+		private bool Loaded = false;
+
+		public bool IsLoaded {
+			get { return Loaded; }	
+		}
+
+		public Plugin ()
+		{
+		}
+
+		public void Load () {
+			PluginInitialize();
+			Loaded = true;
+		}
+
+		protected abstract void PluginInitialize();
+	}
+
+	public abstract class ExportPlugin: Plugin {
+		public abstract string MenuEntryName { get; }			
+		public void HandleMenuItemActivated(object sender, EventArgs args)
+		{
+			MainWindow.Toplevel.HandleExportWithPlugin(this);
+		}
+		public abstract void DoExport(IBrowsableCollection selectedphotos);
+	}
+}
--- /dev/null	2006-06-19 09:02:49.376262000 +0200
+++ src/ExportMenu.cs	2006-06-19 16:30:49.000000000 +0200
@@ -0,0 +1,28 @@
+using Gtk;
+using GtkSharp;
+using System;
+
+namespace FSpot {
+	public class ExportMenu : Menu {
+		public ExportMenu ()
+		{
+			string [] exportplugins = FSpot.Plugins.Plugger.LoadedPlugins(typeof(FSpot.Plugins.ExportPlugin));
+
+			if ( exportplugins == null || exportplugins.Length == 0 ) {
+				MenuItem menu_item = new MenuItem ("No Export Plug-in available");
+				menu_item.Show();
+				menu_item.Sensitive = false;
+				Append(menu_item);
+			}
+			foreach (string shortname in exportplugins) {
+				FSpot.Plugins.ExportPlugin plugin = (FSpot.Plugins.ExportPlugin)FSpot.Plugins.Plugger.Plugin(shortname);
+				MenuItem menu_item = new MenuItem (plugin.MenuEntryName);
+				menu_item.Show();
+				menu_item.Sensitive = true;
+				menu_item.Activated += new EventHandler (plugin.HandleMenuItemActivated);
+
+				Append(menu_item);
+			}
+		}
+	}
+}
using System;

using FSpot;
using FSpot.Plugins;

namespace FSpot.Plugins {

	public class DialogPlugin: FSpot.Plugins.Plugin
	{
		public override string DisplayName { get { return "Dialog Plugin"; } }
		public override string ShortName { get { return "DialogPlugin"; } }
		public override string Description { get { return "Warn the user about using plugins"; } }

		protected override void PluginInitialize()
		{
			Console.WriteLine("Initializing Dialog Plugin");	
			String header = "Plug-ins enabled version of F-Spot";
			String msg = "You are running a plug-ins enabled version of F-Spot" +
				"\nPlug-ins can crash your F-Spot, delete all your images, and " +
				"completely destroy your database." +
				"\nYou have been warned! Don't fill any bug report " +
				"regarding plug-ins";
			HigMessageDialog.RunHigMessageDialog(MainWindow.Toplevel.Window,
								Gtk.DialogFlags.DestroyWithParent,
								Gtk.MessageType.Warning,
								Gtk.ButtonsType.Ok,header,msg);
		}
	}

}
using System;

using FSpot;
using FSpot.Plugins;

namespace FSpot.Plugins {
	public class SendMailPlugin: FSpot.Plugins.ExportPlugin
	{
		public override string DisplayName { get { return "Send Mail Plugin"; } }
		public override string ShortName { get { return "SendMailPlugin"; } }
		public override string Description { get { return "Create an e-mail with your photos attached"; } }
		public override string MenuEntryName { get { return "Send Mail...";} }
		protected override void PluginInitialize()
		{
			Console.WriteLine("Initializing Send Mail Plugin");	
		}
		public override void DoExport (IBrowsableCollection sel_photos)
		{
			Photo [] photos = (Photo [])sel_photos.Items;
			System.Text.StringBuilder url = new System.Text.StringBuilder ("mailto:?subject=my%20photos";);
			foreach (Photo p in photos) {
				url.Append ("&attach=" + UriList.EscapeString (p.DefaultVersionUri.LocalPath, true, true, true));
			}
			Gnome.Url.Show (url.ToString ());

			Console.WriteLine ("Exporting {0} pictures", sel_photos.Count);	
		}
	}
}


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