Index: src/Widgets/InfoBox.cs
===================================================================
--- src/Widgets/InfoBox.cs	(revision 4209)
+++ src/Widgets/InfoBox.cs	(working copy)
@@ -201,6 +201,12 @@
 					}
 				}
 	
+				string imgPath = img.Uri.AbsolutePath;
+				if (img is VideoCanonFile) {
+					VideoCanonFile vcf = (VideoCanonFile)img;
+					width = vcf.GetVideoWidth ().ToString ();
+					height = vcf.GetVideoHeight ().ToString ();
+				}
 				if (img is JpegFile) {
 					int real_width;
 					int real_height;
Index: src/FileImportBackend.cs
===================================================================
--- src/FileImportBackend.cs	(revision 4209)
+++ src/FileImportBackend.cs	(working copy)
@@ -216,6 +216,11 @@
 				photo = store.Create (info.DestinationPath, roll.Id, out thumbnail);
 			} else {
 				System.IO.File.Copy (info.OriginalPath, destination);
+				string canon_thumbnail = System.IO.Path.ChangeExtension (info.OriginalPath, "thm");
+				if (System.IO.File.Exists (canon_thumbnail)) {
+					string destinationThumbnail = System.IO.Path.ChangeExtension (destination, "thm");
+					System.IO.File.Copy (canon_thumbnail, destinationThumbnail);
+				}
 				info.DestinationPath = destination;
 
 				photo = store.Create (info.DestinationPath, info.OriginalPath, roll.Id, out thumbnail);
Index: src/Imaging/ImageFile.cs
===================================================================
--- src/Imaging/ImageFile.cs	(revision 4209)
+++ src/Imaging/ImageFile.cs	(working copy)
@@ -4,23 +4,17 @@
 using Mono.Unix;
 
 namespace FSpot {
-	public class ImageFormatException : ApplicationException {
-		public ImageFormatException (string msg) : base (msg)
-		{
-		}
-	}
-
 	public class ImageFile : IDisposable {
 		protected Uri uri;
 
 		static System.Collections.Hashtable name_table;
 
-		public ImageFile (string path) 
+		protected ImageFile (string path)
 		{
 			this.uri = UriUtils.PathToFileUri (path);
 		}
 		
-		public ImageFile (Uri uri)
+		protected ImageFile (Uri uri)
 		{
 			this.uri = uri;
 		}
@@ -44,10 +38,11 @@
 
 		static ImageFile ()
 		{
+			// image
 			name_table = new System.Collections.Hashtable ();
 			name_table [".svg"] = typeof (FSpot.Svg.SvgFile);
-			name_table [".gif"] = typeof (ImageFile);
-			name_table [".bmp"] = typeof (ImageFile);
+			name_table [".gif"] = typeof (ImageFile0);
+			name_table [".bmp"] = typeof (ImageFile0);
 			name_table [".jpeg"] = typeof (JpegFile);
 			name_table [".jpg"] = typeof (JpegFile);
 			name_table [".png"] = typeof (FSpot.Png.PngFile);
@@ -67,6 +62,11 @@
 			name_table [".mrw"] = typeof (FSpot.Mrw.MrwFile);
 			name_table [".raf"] = typeof (FSpot.Raf.RafFile);
 			name_table [".x3f"] = typeof (FSpot.X3f.X3fFile);
+			// video
+			name_table [".avi"] = typeof (VideoFile);
+			name_table [".mov"] = typeof (VideoFile);
+			name_table [".mpeg"] = typeof (VideoFile);
+			name_table [".mpg"] = typeof (VideoFile);
 		}
 
 		public Uri Uri {
@@ -82,48 +82,27 @@
 			get { return null; }
 		}
 		
-		public virtual void Save (Gdk.Pixbuf pixbuf, System.IO.Stream stream)
+		public static System.Type GetType (Uri uri)
 		{
-			throw new NotImplementedException (Catalog.GetString ("Writing to this file format is not implemented"));
+			string extension = System.IO.Path.GetExtension (uri.AbsolutePath).ToLower ();
+			return (System.Type) name_table [extension];
 		}
 
-		protected Gdk.Pixbuf TransformAndDispose (Gdk.Pixbuf orig)
+		public virtual void Save (Gdk.Pixbuf pixbuf, System.IO.Stream stream)
 		{
-			if (orig == null)
-				return null;
-
-			Gdk.Pixbuf rotated = PixbufUtils.TransformOrientation (orig, this.Orientation, true);
-			//ValidateThumbnail (photo, rotated);
-			if (rotated != orig)
-				orig.Dispose ();
-			
-			return rotated;
+			throw new NotImplementedException (Catalog.GetString ("Writing to this file format is not implemented"));
 		}
-		
+
 		public virtual Gdk.Pixbuf Load ()
 		{
-			using (Stream stream = PixbufStream ()) {
-				Gdk.Pixbuf orig = new Gdk.Pixbuf (stream);
-				return TransformAndDispose (orig);
-			}
+			return null;
 		}
 		
 		public virtual Gdk.Pixbuf Load (int max_width, int max_height)
 		{
-			System.IO.Stream stream = PixbufStream ();
-			if (stream == null) {
-				Gdk.Pixbuf orig = this.Load ();
-				Gdk.Pixbuf scaled = PixbufUtils.ScaleToMaxSize (orig,  max_width, max_height);	
-				orig.Dispose ();
-				return scaled;
-			}
-
-			using (stream) {
-				PixbufUtils.AspectLoader aspect = new PixbufUtils.AspectLoader (max_width, max_height);
-				return aspect.Load (stream, Orientation);
-			}	
+			return null;
 		}
-	
+
 		public virtual PixbufOrientation GetOrientation () 
 		{
 			return PixbufOrientation.TopLeft;
@@ -151,6 +130,16 @@
 					return write;
 			}
 		}
+		
+		public virtual void SetOrientation (PixbufOrientation orientation)
+		{
+			throw new NotSupportedException ();
+		}
+			
+		public virtual Gdk.Pixbuf Print (Gdk.Pixbuf image)
+		{
+			throw new NotSupportedException();
+		}
 
 		[Obsolete ("use HasLoader (System.Uri) instead")]
 		public static bool HasLoader (string path)
@@ -178,6 +167,11 @@
 			string path = uri.AbsolutePath;
 			string extension = System.IO.Path.GetExtension (path).ToLower ();
 			System.Type t = (System.Type) name_table [extension];
+			if (t == typeof (VideoFile)) {
+				string canon_thumbnail = System.IO.Path.ChangeExtension (path, "thm");
+				if (System.IO.File.Exists (canon_thumbnail))
+					t = typeof (VideoCanonFile);
+			}
 			ImageFile img;
 
 			if (t != null)
@@ -216,33 +210,5 @@
 		protected virtual void Close ()
 		{
 		}
-
-		public static bool IsRaw (string name)
-		{
-			string [] raw_extensions = {
-				".arw",
-				".crw",
-				".cr2",
-				".dng",
-				".mrw",
-				".nef",
-				".orf", 
-				".pef", 
-				".raw",
-			};
-			foreach (string ext in raw_extensions)
-				if (ext == System.IO.Path.GetExtension (name).ToLower ())
-					return true;
-			return false;
-		}
-
-		public static bool IsJpeg (string name)
-		{
-			string [] jpg_extensions = {".jpg", ".jpeg"};
-			foreach (string ext in jpg_extensions)
-				if (ext == System.IO.Path.GetExtension (name).ToLower ())
-					return true;
-			return false;
-		}
-	} 
+	}
 }
Index: src/Imaging/PngFile.cs
===================================================================
--- src/Imaging/PngFile.cs	(revision 4209)
+++ src/Imaging/PngFile.cs	(working copy)
@@ -11,7 +11,7 @@
 #endif
 
 namespace FSpot.Png {
-	public class PngFile : ImageFile, SemWeb.StatementSource {
+	public class PngFile : ImageFile0, SemWeb.StatementSource {
 		PngHeader header;
 
                 // false seems a safe default
Index: src/Imaging/JpegFile.cs
===================================================================
--- src/Imaging/JpegFile.cs	(revision 4209)
+++ src/Imaging/JpegFile.cs	(working copy)
@@ -13,7 +13,7 @@
 		Gdk.Pixbuf GetEmbeddedThumbnail ();
 	}
 
-	public class JpegFile : ImageFile, IThumbnailContainer, SemWeb.StatementSource {
+	public class JpegFile : ImageFile0, IThumbnailContainer, SemWeb.StatementSource {
 		private Exif.ExifData exif_data;
 		private XmpFile xmp;
 		private JpegHeader header;
@@ -287,7 +287,7 @@
 			return orientation;
 		}
 		
-		public void SetOrientation (PixbufOrientation orientation)
+		public override void SetOrientation (PixbufOrientation orientation)
 		{
 			Exif.ExifEntry e = this.ExifData.GetContents (Exif.Ifd.Zero).GetEntry (Exif.Tag.Orientation);
 			// System.Console.WriteLine ("Saving orientation as {0}", orientation);
Index: src/Imaging/Tiff.cs
===================================================================
--- src/Imaging/Tiff.cs	(revision 4209)
+++ src/Imaging/Tiff.cs	(working copy)
@@ -2017,7 +2017,7 @@
 	}
 
 
-	public class TiffFile : ImageFile, SemWeb.StatementSource {
+	public class TiffFile : ImageFile0, SemWeb.StatementSource {
 		public Header Header;
 
                 // false seems a safe default
Index: src/Imaging/PnmFile.cs
===================================================================
--- src/Imaging/PnmFile.cs	(revision 4209)
+++ src/Imaging/PnmFile.cs	(working copy)
@@ -8,7 +8,7 @@
 #endif
 
 namespace FSpot.Pnm {
-	public class PnmFile : ImageFile, StatementSource {
+	public class PnmFile : ImageFile0, StatementSource {
 
                 // false seems a safe default
                 public bool Distinct {
Index: src/Imaging/SvgFile.cs
===================================================================
--- src/Imaging/SvgFile.cs	(revision 4209)
+++ src/Imaging/SvgFile.cs	(working copy)
@@ -1,7 +1,7 @@
 using System;
 
 namespace FSpot.Svg {
-	public class SvgFile : ImageFile // SemWeb.StatementSource 
+	public class SvgFile : ImageFile0 // SemWeb.StatementSource 
 	{
 		MetadataStore store;
 
Index: src/Imaging/DCRawFile.cs
===================================================================
--- src/Imaging/DCRawFile.cs	(revision 4209)
+++ src/Imaging/DCRawFile.cs	(working copy)
@@ -71,7 +71,7 @@
 		}
 	}
 
-	public class DCRawFile : ImageFile {
+	public class DCRawFile : ImageFile0 {
 		const string dcraw_command = "dcraw";
 
 		public DCRawFile (string path) : base (path)
Index: src/Imaging/MrwFile.cs
===================================================================
--- src/Imaging/MrwFile.cs	(revision 4209)
+++ src/Imaging/MrwFile.cs	(working copy)
@@ -169,7 +169,7 @@
 		
 	}
 	
-	public class MrwFile : ImageFile, SemWeb.StatementSource {
+	public class MrwFile : ImageFile0, SemWeb.StatementSource {
 		MrmBlock mrm;
 		FSpot.Tiff.Header header;
 
Index: src/Imaging/Ciff.cs
===================================================================
--- src/Imaging/Ciff.cs	(revision 4209)
+++ src/Imaging/Ciff.cs	(working copy)
@@ -311,7 +311,7 @@
 		}
 	}
 	
-	public class CiffFile : FSpot.ImageFile , SemWeb.StatementSource {
+	public class CiffFile : FSpot.ImageFile0 , SemWeb.StatementSource {
 		public ImageDirectory root;
 		private uint version;
 		bool little;
Index: src/Imaging/RafFile.cs
===================================================================
--- src/Imaging/RafFile.cs	(revision 4209)
+++ src/Imaging/RafFile.cs	(working copy)
@@ -19,7 +19,7 @@
 		}
 	}
 	
-	public class RafFile : ImageFile, SemWeb.StatementSource {
+	public class RafFile : ImageFile0, SemWeb.StatementSource {
 
                 // false seems a safe default
                 public bool Distinct {
Index: src/Jobs/SyncMetadataJob.cs
===================================================================
--- src/Jobs/SyncMetadataJob.cs	(revision 4209)
+++ src/Jobs/SyncMetadataJob.cs	(working copy)
@@ -47,25 +47,38 @@
 		void WriteMetadataToImage (Photo photo)
 		{
 			string path = photo.DefaultVersionUri.LocalPath;
+			string canon_thumbnail = System.IO.Path.ChangeExtension(path, "thm");
 	
-			using (FSpot.ImageFile img = FSpot.ImageFile.Create (photo.DefaultVersionUri)) {
-				if (img is FSpot.JpegFile) {
-					FSpot.JpegFile jimg = img as FSpot.JpegFile;
-				
-					jimg.SetDescription (photo.Description);
-					jimg.SetDateTimeOriginal (photo.Time.ToLocalTime ());
-					jimg.SetXmp (UpdateXmp (photo, jimg.Header.GetXmp ()));
-	
-					jimg.SaveMetaData (path);
-				} else if (img is FSpot.Png.PngFile) {
-					FSpot.Png.PngFile png = img as FSpot.Png.PngFile;
-				
-					if (img.Description != photo.Description)
-						png.SetDescription (photo.Description);
-				
-					png.SetXmp (UpdateXmp (photo, png.GetXmp ()));
-	
-					png.Save (path);
+			if (System.IO.Path.GetExtension (path) == ".avi") {
+				if (System.IO.File.Exists (canon_thumbnail)) {
+				       using (FSpot.VideoCanonFile vid = FSpot.VideoCanonFile.Create (photo.DefaultVersionUri)) {
+					       vid.SetDescription (photo.Description);
+					       vid.SetDateTimeOriginal (photo.Time.ToLocalTime ());
+					       vid.SetXmp (UpdateXmp (photo, vid.Header.GetXmp ()));
+					       
+					       vid.SaveMetaData (canon_thumbnail);
+				       }
+			       }
+		       } else {
+				using (FSpot.ImageFile img = FSpot.ImageFile.Create (photo.DefaultVersionUri)) {
+					if (img is FSpot.JpegFile) {
+						FSpot.JpegFile jimg = img as FSpot.JpegFile;
+					
+						jimg.SetDescription (photo.Description);
+						jimg.SetDateTimeOriginal (photo.Time.ToLocalTime ());
+						jimg.SetXmp (UpdateXmp (photo, jimg.Header.GetXmp ()));
+		
+						jimg.SaveMetaData (path);
+					} else if (img is FSpot.Png.PngFile) {
+						FSpot.Png.PngFile png = img as FSpot.Png.PngFile;
+					
+						if (img.Description != photo.Description)
+							png.SetDescription (photo.Description);
+					
+						png.SetXmp (UpdateXmp (photo, png.GetXmp ()));
+		
+						png.Save (path);
+					}
 				}
 			}
 		}
Index: src/PrintDialog.cs
===================================================================
--- src/PrintDialog.cs	(revision 4209)
+++ src/PrintDialog.cs	(working copy)
@@ -18,6 +18,12 @@
 			Userspace = (1 << 3)      /* Mathematical coordinates */
 		}
 
+		private enum IndividualNotification {
+			FirstRun = 1,
+			Notify = 2,
+			DoNotNotify = 3
+		}
+
 		public static string PAPER_SIZE                = "Settings.Output.Media.PhysicalSize"; /* Paper name, such as A4 or Letter */
 		public static string PAPER_WIDTH               = "Settings.Output.Media.PhysicalSize.Width"; /* Arbitrary units - use conversion */
 		public static string PAPER_HEIGHT              = "Settings.Output.Media.PhysicalSize.Height"; /* Arbitrary units - use conversion */
@@ -81,6 +87,7 @@
 			double page_width, page_height;
 			print_job.GetPageSize (out page_width, out page_height);
 			Gnome.PrintContext ctx = print_job.Context;
+			IndividualNotification notification_status = IndividualNotification.FirstRun;
 
 			ArrayList exceptions = new ArrayList ();
 
@@ -97,9 +104,16 @@
 					continue;
 				}
 
+				FSpot.ImageFile mediaFile = FSpot.ImageFile.Create (photo.DefaultVersionUri.LocalPath);
 				Gdk.Pixbuf flat = PixbufUtils.Flatten (image);
 				if (flat != null) {
-					image.Dispose ();
+					try {
+						image = mediaFile.Print(image);
+					} catch (NotSupportedException nse) {
+						if (notification_status != IndividualNotification.DoNotNotify)
+							notification_status = RunNotSupportedError (photo.DefaultVersionUri.LocalPath, notification_status);
+						continue;
+					}
 					image = flat;
 				}
 
@@ -198,6 +212,36 @@
 			RunGnomePrintDialog ();
 #endif
 		}
+		
+		private IndividualNotification RunNotSupportedError (string path, IndividualNotification notificate_status)
+		{
+			string longmsg;
+			
+			longmsg = String.Format (Catalog.GetString ("Print not supported for file {0}"),
+							System.IO.Path.GetFileName (path));
+
+			HigMessageDialog.RunHigMessageDialog (print_dialog, DialogFlags.DestroyWithParent,
+									MessageType.Warning, ButtonsType.Ok,
+									Catalog.GetString ("Print not supported"),
+									longmsg);
+
+
+			if (notificate_status != IndividualNotification.FirstRun)
+				return notificate_status;
+			else {
+				longmsg = String.Format (Catalog.GetString ("Do you want to get this notification for each selected file for which print is not supported?"),
+								System.IO.Path.GetFileName (path));
+			
+				Gtk.ResponseType response = HigMessageDialog.RunHigMessageDialog (print_dialog, 
+										DialogFlags.DestroyWithParent, MessageType.Question, 
+										ButtonsType.YesNo,	Catalog.GetString ("Individual notification"),
+										longmsg);
+				if (response == Gtk.ResponseType.Yes)
+					return IndividualNotification.Notify;
+				else
+					return IndividualNotification.DoNotNotify;
+			}
+		}
 	}
 }
 #endif
Index: src/PrintOperation.cs
===================================================================
--- src/PrintOperation.cs	(revision 4209)
+++ src/PrintOperation.cs	(working copy)
@@ -12,8 +12,10 @@
 using System;
 using System.Runtime.InteropServices;
 using Mono.Unix;
+using Gtk;
 
 using FSpot.Widgets;
+using FSpot.UI.Dialog;
 
 namespace FSpot
 {
@@ -25,11 +27,34 @@
 		bool repeat, white_borders, crop_marks;
 		string comment;
 
+		private enum IndividualNotification {
+			FirstRun = 1,
+			Notify = 2,
+			DoNotNotify = 3
+		}
+
 		public PrintOperation (IBrowsableItem [] selected_photos) : base ()
 		{
-			this.selected_photos = selected_photos;
+			IndividualNotification notification_status = IndividualNotification.FirstRun;
+			System.Collections.ArrayList selected_printable_photos = new System.Collections.ArrayList();
+
+			foreach (IBrowsableItem item in selected_photos) {
+				using (ImageFile img = ImageFile.Create (item.DefaultVersionUri))
+				{
+					Gdk.Pixbuf pixbuf = img.Load ();
+					try {
+						img.Print(pixbuf);
+					} catch (NotSupportedException nse) {
+						if (notification_status != IndividualNotification.DoNotNotify)
+							notification_status = RunNotSupportedError (img.Uri.LocalPath, notification_status);
+						continue;
+					}
+					selected_printable_photos.Add (item);
+				}
+			}
+			this.selected_photos = (IBrowsableItem []) selected_printable_photos.ToArray (typeof (IBrowsableItem));
 			CustomTabLabel = Catalog.GetString ("Image Settings");
-			NPages = selected_photos.Length;
+			NPages = this.selected_photos.Length;
 		}
 
 		protected override void OnBeginPrint (Gtk.PrintContext context)
@@ -101,7 +126,7 @@
 						DrawCropMarks (cr, x*w, y*h, w*.1);
 					if (x == ppx || y == ppy || p_index >= selected_photos.Length)
 						continue;
-					using (ImageFile img = new ImageFile (selected_photos[p_index].DefaultVersionUri))
+					using (ImageFile img = ImageFile.Create (selected_photos[p_index].DefaultVersionUri))
 					{
 						Gdk.Pixbuf pixbuf = img.Load ();
 						//Gdk.Pixbuf pixbuf = img.Load (100, 100);
@@ -222,6 +247,36 @@
 			IntPtr result = f_pixbuf_from_cairo_surface (s.Handle);
 			return (Gdk.Pixbuf) GLib.Object.GetObject (result, true);
 		}
+		
+		private IndividualNotification RunNotSupportedError (string path, IndividualNotification notificate_status)
+		{
+			string longmsg;
+			
+			longmsg = String.Format (Catalog.GetString ("Print not supported for file {0}"),
+							System.IO.Path.GetFileName (path));
+
+			HigMessageDialog.RunHigMessageDialog (null, DialogFlags.DestroyWithParent,
+									MessageType.Warning, ButtonsType.Ok,
+									Catalog.GetString ("Print not supported"),
+									longmsg);
+
+
+			if (notificate_status != IndividualNotification.FirstRun)
+				return notificate_status;
+			else {
+				longmsg = String.Format (Catalog.GetString ("Do you want to get this notification for each selected file for which print is not supported?"),
+								System.IO.Path.GetFileName (path));
+			
+				Gtk.ResponseType response = HigMessageDialog.RunHigMessageDialog (null, 
+										DialogFlags.DestroyWithParent, MessageType.Question, 
+										ButtonsType.YesNo,	Catalog.GetString ("Individual notification"),
+										longmsg);
+				if (response == Gtk.ResponseType.Yes)
+					return IndividualNotification.Notify;
+				else
+					return IndividualNotification.DoNotNotify;
+			}
+		}
 	}
 }
 #endif
Index: src/InfoDisplay.cs
===================================================================
--- src/InfoDisplay.cs	(revision 4209)
+++ src/InfoDisplay.cs	(working copy)
@@ -44,8 +44,13 @@
 					exif_info.Dispose ();
 
 				if (photo != null) {
-					if (File.Exists (photo.DefaultVersionUri.LocalPath))
-						exif_info = new Exif.ExifData (photo.DefaultVersionUri.LocalPath);
+					if (File.Exists (photo.DefaultVersionUri.LocalPath)) {
+						string metadata_file = System.IO.Path.ChangeExtension (photo.DefaultVersionUri.LocalPath, "thm");
+						if (File.Exists (metadata_file))
+							exif_info = new Exif.ExifData (metadata_file);
+						else
+							exif_info = new Exif.ExifData (photo.DefaultVersionUri.LocalPath);
+					}
 				} else {
 					exif_info = null;
 				}
Index: src/RotateCommand.cs
===================================================================
--- src/RotateCommand.cs	(revision 4209)
+++ src/RotateCommand.cs	(working copy)
@@ -105,6 +105,10 @@
 					}
 					File.Copy (backup, original_path, true);
 					File.Delete (backup);
+				} else if (img is VideoFile) {
+					FSpot.VideoFile vid = img as FSpot.VideoFile;
+					
+					vid.SetOrientation (PixbufOrientation.LeftBottom);
 				} else {
 					throw new RotateException (Catalog.GetString ("Unable to rotate this type of photo"), original_path);
 				}
@@ -160,15 +164,30 @@
 			index = 0;
 		}
 		
+		// returns false if no next item exists because last item reached
+		public bool SkipToNext ()
+		{
+			index++;
+			return (index >= items.Length);
+		}
+		
 		public override bool Step ()
 		{
+			bool no_more_version = false;
+			
 			if (index >= items.Length)  
 				return false;
 
 			if (op == null) 
 				op = new RotateOperation (items [index], direction);
 			
-			if (op.Step ())
+			try {
+				no_more_version = op.Step ();
+			} catch (NotSupportedException nse) {
+				op = null;
+				throw new NotSupportedException();
+			}
+			if (no_more_version)
 				return true;
 			else {
 				index++;
@@ -183,6 +202,12 @@
 public class RotateCommand {
 	private Gtk.Window parent_window;
 
+	private enum IndividualNotification {
+		FirstRun = 1,
+		Notify = 2,
+		DoNotNotify = 3
+	}
+
 	public RotateCommand (Gtk.Window parent_window)
 	{
 		this.parent_window = parent_window;
@@ -200,7 +225,8 @@
 	        RotateMultiple op = new RotateMultiple (items, direction);
 		int readonly_count = 0;
 		bool done = false;
-		int index = 0;
+		IndividualNotification notification_status = IndividualNotification.FirstRun;
+		int index = -1;
 
 		while (!done) {
 			if (progress_dialog != null && op.Index != -1 && index < items.Length) 
@@ -220,6 +246,10 @@
 				RunGenericError (e, op.Items [op.Index].DefaultVersionUri.LocalPath, Catalog.GetString ("Directory not found"));
 			} catch (FileNotFoundException e) {
 				RunGenericError (e, op.Items [op.Index].DefaultVersionUri.LocalPath, Catalog.GetString ("File not found"));
+			} catch (NotSupportedException nse) {
+				if (notification_status != IndividualNotification.DoNotNotify)
+					notification_status = RunNotSupportedError (op.Items [op.Index].DefaultVersionUri.LocalPath, notification_status);
+				done = op.SkipToNext();
 			} catch (Exception e) {
 				RunGenericError (e, op.Items [op.Index].DefaultVersionUri.LocalPath);
 			}
@@ -276,4 +306,34 @@
 		md.Run ();
 		md.Destroy ();
 	}
+	
+	private IndividualNotification RunNotSupportedError (string path, IndividualNotification notificate_status)
+	{
+		string longmsg;
+		
+		longmsg = String.Format (Catalog.GetString ("Rotation not supported for file {0}"),
+						System.IO.Path.GetFileName (path));
+
+		HigMessageDialog.RunHigMessageDialog (parent_window, DialogFlags.DestroyWithParent,
+								MessageType.Warning, ButtonsType.Ok,
+								Catalog.GetString ("Rotation not supported"),
+								longmsg);
+
+
+		if (notificate_status != IndividualNotification.FirstRun)
+			return notificate_status;
+		else {
+			longmsg = String.Format (Catalog.GetString ("Do you want to get this notification for each selected file for which rotation is not supported?"),
+							System.IO.Path.GetFileName (path));
+		
+			Gtk.ResponseType response = HigMessageDialog.RunHigMessageDialog (parent_window, 
+									DialogFlags.DestroyWithParent, MessageType.Question, 
+									ButtonsType.YesNo,	Catalog.GetString ("Individual notification"),
+									longmsg);
+			if (response == Gtk.ResponseType.Yes)
+				return IndividualNotification.Notify;
+			else
+				return IndividualNotification.DoNotNotify;
+		}
+	}
 }
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision 4209)
+++ src/Makefile.am	(working copy)
@@ -163,6 +163,9 @@
 	$(srcdir)/Imaging/X3fFile.cs		\
 	$(srcdir)/Imaging/XmpFile.cs		\
 	$(srcdir)/Imaging/Tiff.cs		\
+	$(srcdir)/Imaging/ImageFile0.cs	\
+	$(srcdir)/Imaging/VideoFile.cs	\
+	$(srcdir)/Imaging/VideoCanonFile.cs	\
 	$(srcdir)/JobStore.cs			\
 	$(srcdir)/Jobs/SyncMetadataJob.cs	\
 	$(srcdir)/Loupe.cs			\
Index: extensions/FacebookExport/FacebookExport.cs
===================================================================
--- extensions/FacebookExport/FacebookExport.cs	(revision 4209)
+++ extensions/FacebookExport/FacebookExport.cs	(working copy)
@@ -415,7 +415,7 @@
 				tag_image.Destroy ();
 			}
 
-			using (ImageFile image = new ImageFile (thumbnail_path)) {
+			using (ImageFile image = ImageFile.Create (thumbnail_path)) {
 				Gdk.Pixbuf data = image.Load ();
 				data = PixbufUtils.ScaleToMaxSize (data, 400, 400);
 				tag_image_height = data.Height;
--- /dev/null	2008-04-12 00:50:00.000000000 +0200
+++ src/Imaging/ImageFile0.cs	2008-07-28 08:01:40.000000000 +0200
@@ -0,0 +1,104 @@
+using System;
+using System.IO;
+using FSpot.Utils;
+using Mono.Unix;
+
+namespace FSpot {
+	public class ImageFormatException : ApplicationException {
+		public ImageFormatException (string msg) : base (msg)
+		{
+		}
+	}
+
+	public class ImageFile0 : ImageFile {
+
+		public ImageFile0 (Uri uri) : base (uri)
+		{
+		}
+		
+		public ImageFile0 (string path) : base (path)
+		{
+		}
+		
+		protected Gdk.Pixbuf TransformAndDispose (Gdk.Pixbuf orig)
+		{
+			if (orig == null)
+				return null;
+
+			Gdk.Pixbuf rotated = PixbufUtils.TransformOrientation (orig, this.Orientation, true);
+			//ValidateThumbnail (photo, rotated);
+			if (rotated != orig)
+				orig.Dispose ();
+			
+			return rotated;
+		}
+		
+		public override Gdk.Pixbuf Load ()
+		{
+			using (Stream stream = PixbufStream ()) {
+				Gdk.Pixbuf orig = new Gdk.Pixbuf (stream);
+				return TransformAndDispose (orig);
+			}
+		}
+		
+		public override Gdk.Pixbuf Load (int max_width, int max_height)
+		{
+			System.IO.Stream stream = PixbufStream ();
+			if (stream == null) {
+				Gdk.Pixbuf orig = this.Load ();
+				Gdk.Pixbuf scaled = PixbufUtils.ScaleToMaxSize (orig,  max_width, max_height);	
+				orig.Dispose ();
+				return scaled;
+			}
+
+			using (stream) {
+				PixbufUtils.AspectLoader aspect = new PixbufUtils.AspectLoader (max_width, max_height);
+				return aspect.Load (stream, Orientation);
+			}	
+		}
+	
+ 		public static ImageFile0 Create (string path)
+		{
+			return Create (UriUtils.PathToFileUri (path));
+		}
+
+ 		public static ImageFile0 Create (Uri uri)
+		{
+ 			return (ImageFile0) ImageFile.Create (uri);
+		}
+		
+		public static bool IsRaw (string name)
+		{
+			string [] raw_extensions = {
+				".arw",
+				".crw",
+				".cr2",
+				".dng",
+				".mrw",
+				".nef",
+				".orf", 
+				".pef", 
+				".raw",
+			};
+			foreach (string ext in raw_extensions)
+				if (ext == System.IO.Path.GetExtension (name).ToLower ())
+					return true;
+			return false;
+		}
+
+		public static bool IsJpeg (string name)
+		{
+			string [] jpg_extensions = {".jpg", ".jpeg"};
+			foreach (string ext in jpg_extensions)
+				if (ext == System.IO.Path.GetExtension (name).ToLower ())
+					return true;
+			return false;
+		}
+		
+		public override Gdk.Pixbuf Print(Gdk.Pixbuf image)
+		{
+			image.Dispose ();
+			return image;
+		}		
+	} 
+}
--- /dev/null	2008-04-12 00:50:00.000000000 +0200
+++ src/Imaging/VideoFile.cs	2008-07-28 08:01:40.000000000 +0200
@@ -0,0 +1,97 @@
+using System;
+using System.IO;
+using FSpot.Utils;
+
+namespace FSpot {
+	public class VideoFormatException : ApplicationException {
+		public VideoFormatException (string msg) : base (msg)
+		{
+		}
+	}
+
+	public class VideoFile : ImageFile {	
+		private const int TIMEOUT = 15000; // Timeout for thumbnailer process is 5 seconds
+		
+		public VideoFile (Uri uri) : base (uri)
+		{
+		}
+
+		public VideoFile (string path) : base (path)
+		{
+		}
+
+		public static new VideoFile Create (string path)
+		{
+			return Create (UriUtils.PathToFileUri (path));
+		}
+
+		public static new VideoFile Create (Uri uri)
+		{
+			return (VideoFile) ImageFile.Create (uri);
+		}
+
+
+		///<summary>Returns a full-size "thumbnail", or screen capture, of the video</summary>
+		///<returns>A Gdk.Pixbuf image of the screen capture</returns>
+		///NOTE: the current implementation only returns a still image.  Later versions should
+		/// set up GStreamer for playback and do the appropriate handling here
+		public override Gdk.Pixbuf Load ()
+		{
+			return Load (-1, -1);
+		}
+
+		///<summary>Loads a thumbnail of the video file using an external thumbnailer</summary>
+		///<param name="max_width">Width of the thumbnail in pixels</param>
+		///<param name="max_height">Height of the thumbnail in pixels</param>
+		///<returns>A Gdk.Pixbuf of the thumbnail image extracted from the video file</returns>
+		public override Gdk.Pixbuf Load (int max_width, int max_height)
+		{
+			Gdk.Pixbuf pixbuf = null;
+			try {
+				string temp_path = Path.GetTempFileName();
+				// string temp_path = GenerateTempPath ();
+				string thumbnailer_command;
+				
+				// Used the following for gnome-video-thumbnailer call string formatting:
+				// {0) = input file (eg. "video1.avi")
+				// {1} = output file (eg. "thumb1.png")
+				// {2} = width of thumbnail
+				// {3} = height of thumbnail
+				if (max_width == -1)
+					thumbnailer_command = String.Format ("gnome-video-thumbnailer \"{0}\" \"{1}\"", 
+						this.Uri.AbsolutePath, temp_path);
+				else
+					thumbnailer_command = String.Format ("gnome-video-thumbnailer -s {2} \"{0}\" \"{1}\"", 
+						this.Uri.AbsolutePath, temp_path, max_width);
+				
+				// Create a new process to run the external thumbnailer in, let it run until it
+				// ends or until TIMEOUT milliseconds elapse.
+				System.Diagnostics.Process thumbnailerProcess= new System.Diagnostics.Process ();
+				thumbnailerProcess.StartInfo.FileName=thumbnailer_command;
+				thumbnailerProcess.Start ();
+				thumbnailerProcess.WaitForExit (TIMEOUT);
+
+				pixbuf = new Gdk.Pixbuf (temp_path);
+				System.IO.File.Delete (temp_path);
+			} catch (System.Exception e) {
+				System.Console.WriteLine (e.ToString ());
+			}
+			return pixbuf;
+		}
+
+		///<summary>Uses the given Uri to generate a temporary, unique filename</summary>
+		///<returns>String of the absolute path for the temporary filename</returns>
+		private string GenerateTempPath ()
+		{
+			string result = null;
+			try {
+				result = "." + System.IO.Path.GetFileNameWithoutExtension (this.Uri.AbsolutePath) + ".png";
+				result = FileImportBackend.UniqueName (FSpot.Global.PhotoDirectory, result);
+			} catch (System.Exception e) {
+				System.Console.WriteLine (e.ToString ());
+			}
+			return result;
+		}
+
+	}
+}
--- /dev/null	2008-04-12 00:50:00.000000000 +0200
+++ src/Imaging/VideoCanonFile.cs	2008-07-29 08:09:10.000000000 +0200
@@ -0,0 +1,344 @@
+/*
+ * VideoCanonFile.cs
+ *
+ * Author(s):
+ *	Silvano Cirujano-Cuesta <silvanociru@gmail.com>
+ *	Michael Wayne Goodman
+ *	Alex Polvi
+ * 
+ * This is free software. See COPYING for details.
+ */
+ 
+#define USE_TIFF
+using System;
+using System.IO;
+using FSpot.Xmp;
+using FSpot.Tiff;
+
+namespace FSpot {
+	public class VideoCanonFile : VideoFile, SemWeb.StatementSource {
+		private Exif.ExifData exif_data;
+		private XmpFile xmp;
+		private JpegHeader header;
+		private FSpot.Tiff.Header exif_header;
+
+		// constructors
+		public VideoCanonFile (Uri uri) : base (uri)
+		{
+		}
+		
+		public VideoCanonFile (string path) : base (path)
+		{
+		}
+		
+		// creators
+		public static new VideoCanonFile Create (string path)
+		{
+			return Create (FSpot.Utils.UriUtils.PathToFileUri (path));
+		}
+		
+		public static new VideoCanonFile Create (Uri uri)
+		{
+			return (VideoCanonFile) VideoFile.Create (uri);
+		}
+		
+                // False seems a safe default
+                public bool Distinct {
+                        get { return false; }
+                }
+		
+#if USE_THM_THUMBNAILS
+		public override Gdk.Pixbuf Load ()
+		{
+			return this.Load (120,120);
+		}
+		
+		//get thumbnail of the video
+		public override Gdk.Pixbuf Load (int max_width, int max_height)
+		{
+			Gdk.Pixbuf pixbuf = null;
+			try {
+				string thumbnail = System.IO.Path.ChangeExtension (this.uri.AbsolutePath, "thm");
+				pixbuf = new Gdk.Pixbuf (thumbnail);
+			} catch (System.Exception e) {
+				System.Console.WriteLine (e.ToString ());
+			}
+			return pixbuf;
+		}
+#endif
+		
+		// get metadata of the video
+		public JpegHeader Header {
+			get {
+				if (header == null) {
+					string thmHeader = Path.ChangeExtension (this.uri.AbsolutePath, "thm");
+					using (Stream stream = new Gnome.Vfs.VfsStream (thmHeader, FileMode.Open)) {
+						header = new JpegHeader (stream, true);
+					}
+				}
+				return header;
+			}
+		}
+
+		public FSpot.Tiff.Header ExifHeader {
+			get {
+				if (exif_header == null) {
+					exif_header = Header.GetExifHeader ();
+				}
+				return exif_header;
+			}
+		}
+
+		public void Select (SemWeb.StatementSink sink)
+		{
+			Header.Select (sink);
+		}
+
+		// get video description
+		public override string Description {
+			get {
+#if USE_TIFF
+				try {
+					SubdirectoryEntry sub = (SubdirectoryEntry) ExifHeader.Directory.Lookup (TagId.ExifIfdPointer);
+					if (sub != null) {
+						DirectoryEntry entry = sub.Directory [0].Lookup (TagId.UserComment);
+						if (entry != null)
+							return entry.ValueAsString [0];
+					}
+				} catch (System.Exception e) {
+					Console.WriteLine (e);
+				}
+				return null;
+#else
+				try {
+					Exif.ExifContent exif_content = this.ExifData.GetContents (Exif.Ifd.Exif);
+					Exif.ExifEntry entry = exif_content.Lookup (Exif.Tag.UserComment);
+					
+					if (entry == null)
+						return null;
+					
+					UserComment comment = new UserComment (entry.Data, entry.ByteOrder == Exif.ByteOrder.Intel);
+					return comment.Value;
+				} catch (Exception e) {
+					// errors here shouldn't be fatal
+					return null;
+				}
+#endif				
+			}
+		}
+
+		public void SetDescription (string value)
+		{
+			Exif.ExifContent exif_content = this.ExifData.GetContents (Exif.Ifd.Exif);			
+			Exif.ExifEntry entry = exif_content.GetEntry (Exif.Tag.UserComment);
+
+			UserComment comment = new UserComment (value);
+			byte [] data = comment.GetBytes (entry.ByteOrder == Exif.ByteOrder.Intel);
+			entry.SetData (data);
+		}
+		
+		public void SetXmp (XmpFile xmp)
+		{
+			this.xmp = xmp;
+		}
+
+		private void UpdateMeta ()
+		{
+			Exif.ExifContent image_content = this.ExifData.GetContents (Exif.Ifd.Zero);
+			image_content.GetEntry (Exif.Tag.Software).SetData (FSpot.Defines.PACKAGE + " version " + FSpot.Defines.VERSION);
+
+			// set the write time in the datetime tag
+			image_content.GetEntry (Exif.Tag.DateTime).Reset ();
+		}
+
+		// save metadata in THM file
+		private void SaveMetaData (System.IO.Stream input, System.IO.Stream output)
+		{
+			JpegHeader header = new JpegHeader (input);
+			UpdateMeta ();
+			
+			// Console.WriteLine ("updated metadata");
+			header.SetExif (this.ExifData);
+			// Console.WriteLine ("set exif");
+			if (xmp != null)
+				header.SetXmp (xmp);
+			// Console.WriteLine ("set xmp");
+			header.Save (output);
+			// Console.WriteLine ("saved");
+		}
+		
+		public void SaveMetaData (string path)
+		{
+			UpdateMeta ();
+
+			//Get file permissions... (mkstemp does not keep permissions or ownership)
+			Mono.Unix.Native.Stat stat;
+			int stat_err = Mono.Unix.Native.Syscall.stat (path, out stat);
+
+			string  temp_path = path;
+			using (System.IO.FileStream stream = System.IO.File.OpenRead (path)) {
+				using (System.IO.Stream output = FSpot.Utils.Unix.MakeSafeTemp (ref temp_path)) {
+					SaveMetaData (stream, output);
+				}
+			}
+
+			File.SetAttributes (temp_path, File.GetAttributes (path));
+
+			if (FSpot.Utils.Unix.Rename (temp_path, path) < 0) {
+				System.IO.File.Delete (temp_path);
+				throw new System.Exception (System.String.Format ("Unable to rename {0} to {1}",
+										  temp_path, path));
+			}
+
+			//Set file permissions and gid...
+			if (stat_err == 0) 
+				try {
+					Mono.Unix.Native.Syscall.chmod (path, stat.st_mode |
+									      Mono.Unix.Native.FilePermissions.S_IRUSR | 
+									      Mono.Unix.Native.FilePermissions.S_IWUSR);
+					Mono.Unix.Native.Syscall.chown(path, Mono.Unix.Native.Syscall.getuid (), stat.st_gid);
+				} catch (Exception) {}
+		}
+
+		public uint GetVideoWidth ()
+		{
+			Exif.ExifEntry e;
+			Exif.ExifContent thumb_content;
+			
+			// update the thumbnail related image fields if they exist.
+			thumb_content = this.ExifData.GetContents (Exif.Ifd.One);
+			e = thumb_content.Lookup (Exif.Tag.RelatedImageWidth);
+			if (e != null)
+				return e.GetDataUInt () [0];
+			else
+				return 0;
+		}
+
+		public uint GetVideoHeight ()
+		{
+			Exif.ExifEntry e;
+			Exif.ExifContent thumb_content;
+	
+			// update the thumbnail related image fields if they exist.
+			thumb_content = this.ExifData.GetContents (Exif.Ifd.InterOperability);
+			e = thumb_content.Lookup (Exif.Tag.RelatedImageHeight);
+			if (e!=null)
+				return e.GetDataUInt () [0];
+			else
+				return 0;
+		}
+
+		public override void Save (Gdk.Pixbuf pixbuf, System.IO.Stream stream)
+		{
+
+			// Console.WriteLine ("starting save");
+			// First save the imagedata
+			int quality = Header.GuessQuality ();
+			quality = quality == 0 ? 75 : quality;
+			byte [] image_data = PixbufUtils.Save (pixbuf, "jpeg", new string [] {"quality" }, new string [] { quality.ToString () });
+			System.IO.MemoryStream buffer = new System.IO.MemoryStream ();
+			buffer.Write (image_data, 0, image_data.Length);
+			buffer.Position = 0;
+			
+			// Console.WriteLine ("setting thumbnail");
+//			SetThumbnail (pixbuf);
+//			SetDimensions (pixbuf.Width, pixbuf.Height);
+			pixbuf.Dispose ();
+			
+			// Console.WriteLine ("saving metatdata");
+			SaveMetaData (buffer, stream);
+			// Console.WriteLine ("done");
+			buffer.Close ();
+		}
+		
+		public Exif.ExifData ExifData {
+			get {
+				if (exif_data == null) {
+					exif_data = Header.Exif;
+
+					if (exif_data == null || exif_data.Handle.Handle == System.IntPtr.Zero)
+						exif_data = new Exif.ExifData ();
+				}
+				// System.Console.WriteLine ("loading exif data");
+				return exif_data;
+			}
+			set {
+				this.exif_data = value;
+			}
+		}
+
+		public override PixbufOrientation GetOrientation () 
+		{
+			PixbufOrientation orientation = PixbufOrientation.TopLeft;
+#if USE_TIFF
+			try {
+				DirectoryEntry e = ExifHeader.Directory.Lookup (TagId.Orientation);
+				orientation = (PixbufOrientation)e.ValueAsLong [0];
+			} catch {
+				System.Console.WriteLine ("error checking orientation");
+			}
+#else						     
+			Exif.ExifEntry e = this.ExifData.GetContents (Exif.Ifd.Zero).Lookup (Exif.Tag.Orientation);
+			
+			if (e != null) {
+				ushort [] value = e.GetDataUShort ();
+				orientation = (PixbufOrientation) value [0];
+			}
+#endif			
+			if (orientation < PixbufOrientation.TopLeft || orientation > PixbufOrientation.LeftBottom)
+				orientation = PixbufOrientation.TopLeft;
+
+			return orientation;
+		}
+		
+		public void SetDateTimeOriginal (DateTime time)
+		{
+			Exif.ExifEntry e = ExifData.LookupFirst (Exif.Tag.DateTimeOriginal);
+			if (e != null)
+				e.SetData (time);
+			else {
+				Exif.ExifContent exif_content = this.ExifData.GetContents (Exif.Ifd.Exif);
+				Exif.ExifEntry entry = exif_content.GetEntry (Exif.Tag.DateTimeOriginal);
+				entry.SetData (time);
+			}		
+		}
+
+		public override System.DateTime Date {
+			get {
+				System.DateTime time;
+				try {
+#if USE_TIFF
+					SubdirectoryEntry sub = (SubdirectoryEntry) ExifHeader.Directory.Lookup (TagId.ExifIfdPointer);
+					DirectoryEntry e;
+					
+					if (sub != null) {
+						e = sub.Directory [0].Lookup (TagId.DateTimeOriginal);
+						
+						if (e != null)
+							return DirectoryEntry.DateTimeFromString (e.StringValue).ToUniversalTime ();
+					}
+					
+					e = ExifHeader.Directory.Lookup (TagId.DateTime);
+					
+					if (e != null)
+						return DirectoryEntry.DateTimeFromString (e.StringValue).ToUniversalTime ();
+					
+					return base.Date;
+#else
+					string time_str = "";				
+					time_str = ExifData.LookupFirstValue (Exif.Tag.DateTimeOriginal);
+					
+					if (time_str == null || time_str == "") 
+						time_str = ExifData.LookupFirstValue (Exif.Tag.DateTime);
+					
+					time = Exif.ExifUtil.DateTimeFromString (time_str).ToUniversalTime (); 
+#endif
+				} catch (System.Exception e) {
+					Console.WriteLine (e);
+					time = base.Date;
+				}
+				return time;
+			}
+		}
+	}
+}
