f-spot r4290 - in trunk: . extensions extensions/MergeDb



Author: sdelcroix
Date: Mon Aug 25 15:58:18 2008
New Revision: 4290
URL: http://svn.gnome.org/viewvc/f-spot?rev=4290&view=rev

Log:
new MergeDb extension, allowing (partial or full) db merge


Added:
   trunk/extensions/MergeDb/
   trunk/extensions/MergeDb/.gitignore
   trunk/extensions/MergeDb/Makefile.am
   trunk/extensions/MergeDb/MergeDb.addin.xml
   trunk/extensions/MergeDb/MergeDb.cs
   trunk/extensions/MergeDb/MergeDb.glade
Modified:
   trunk/configure.in
   trunk/extensions/Makefile.am

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Mon Aug 25 15:58:18 2008
@@ -367,6 +367,7 @@
 extensions/FolderExport/Makefile
 extensions/SmugMugExport/SmugMugNet/Makefile
 extensions/SmugMugExport/Makefile
+extensions/MergeDb/Makefile
 extensions/PicasaWebExport/Makefile
 extensions/PicasaWebExport/google-sharp/Makefile
 f-spot.pc

Modified: trunk/extensions/Makefile.am
==============================================================================
--- trunk/extensions/Makefile.am	(original)
+++ trunk/extensions/Makefile.am	Mon Aug 25 15:58:18 2008
@@ -6,6 +6,7 @@
 	GalleryExport		\
 	FlickrExport		\
 	FolderExport		\
+	MergeDb			\
  	PicasaWebExport		\
  	SmugMugExport
 

Added: trunk/extensions/MergeDb/.gitignore
==============================================================================
--- (empty file)
+++ trunk/extensions/MergeDb/.gitignore	Mon Aug 25 15:58:18 2008
@@ -0,0 +1,4 @@
+/Makefile
+/Makefile.in
+/MergeDb.dll
+/MergeDb.dll.mdb

Added: trunk/extensions/MergeDb/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/extensions/MergeDb/Makefile.am	Mon Aug 25 15:58:18 2008
@@ -0,0 +1,47 @@
+include $(top_srcdir)/Makefile.include
+
+PLUGIN_NAME = MergeDb
+
+PLUGIN_MANIFEST = $(PLUGIN_NAME).addin.xml
+
+PLUGIN_ASSEMBLY = $(PLUGIN_NAME).dll
+
+PLUGIN_SOURCES =			\
+	$(srcdir)/MergeDb.cs
+
+REFS =					\
+	-r:../../src/f-spot.exe		\
+	-r:../../src/FSpot.Core.dll	\
+	-r:../../src/FSpot.Utils.dll	\
+	-r:../../src/FSpot.Query.dll
+
+PKGS =					\
+	-pkg:gtk-sharp-2.0		\
+	-pkg:glade-sharp-2.0
+
+RESOURCES =				\
+	-resource:$(srcdir)/$(PLUGIN_MANIFEST)	\
+	-resource:$(srcdir)/$(PLUGIN_NAME).glade
+
+all: $(PLUGIN_ASSEMBLY)
+
+mpack: $(PLUGIN_ASSEMBLY)
+	mautil p $(PLUGIN_ASSEMBLY)
+
+$(PLUGIN_ASSEMBLY): $(PLUGIN_SOURCES) $(PLUGIN_MANIFEST)
+	$(CSC_LIB) -out:$@ $(PLUGIN_SOURCES) $(REFS) $(PKGS) $(ASSEMBLIES) $(RESOURCES)
+
+plugindir = $(pkglibdir)/extensions
+
+plugin_DATA =			\
+	$(PLUGIN_ASSEMBLY)
+
+EXTRA_DIST = 			\
+	$(PLUGIN_SOURCES)	\
+	$(PLUGIN_MANIFEST)	\
+	$(PLUGIN_NAME).glade
+
+CLEANFILES =			\
+	$(PLUGIN_ASSEMBLY)	\
+	$(PLUGIN_ASSEMBLY).mdb	\
+	*.mpack

Added: trunk/extensions/MergeDb/MergeDb.addin.xml
==============================================================================
--- (empty file)
+++ trunk/extensions/MergeDb/MergeDb.addin.xml	Mon Aug 25 15:58:18 2008
@@ -0,0 +1,16 @@
+<Addin namespace="FSpot"
+	id="MergeDb"
+	name="MergeDb"
+	version="0.4.4.99"
+	description="Merge another db back to the main one"
+	author="Stephane Delcroix"
+	url="http://f-spot.org/Extensions";
+	category="Tools"
+	defaultEnabled="false">
+	<Dependencies>
+		<Addin id="Core" version="0.4.4.102"/>
+	</Dependencies>
+	<Extension path = "/FSpot/Menus/Tools">
+		<Command id = "MergeDb" _label = "Merge Db" command_type = "MergeDbExtension.MergeDb" />
+	</Extension>
+</Addin>

Added: trunk/extensions/MergeDb/MergeDb.cs
==============================================================================
--- (empty file)
+++ trunk/extensions/MergeDb/MergeDb.cs	Mon Aug 25 15:58:18 2008
@@ -0,0 +1,231 @@
+/* FSpot.MergeDb.cs
+ *
+ * Author(s):
+ *	Stephane Delcroix  <stephane delcroix org>
+ *
+ * This is free software. See COPYING for details
+ */
+
+using System;
+using System.Collections.Generic;
+
+using Gtk;
+
+using FSpot;
+using FSpot.Extensions;
+using FSpot.Utils;
+using FSpot.Query;
+
+namespace MergeDbExtension
+{
+	public class MergeDb : ICommand
+	{
+		[Glade.Widget] Gtk.Dialog mergedb_dialog;
+		[Glade.Widget] Gtk.Button apply_button;
+		[Glade.Widget] Gtk.Button cancel_button;
+		[Glade.Widget] Gtk.FileChooserButton db_filechooser;
+		[Glade.Widget] Gtk.RadioButton newrolls_radio;
+		[Glade.Widget] Gtk.RadioButton allrolls_radio;
+		[Glade.Widget] Gtk.RadioButton singleroll_radio;
+		[Glade.Widget] Gtk.ComboBox rolls_combo;
+
+
+		Db from_db;
+		Db to_db;
+		PhotoQuery query;
+		Roll [] new_rolls;
+
+		Dictionary<uint, Tag> tag_map; //Key is a TagId from from_db, Value is a Tag from to_db
+		Dictionary<uint, uint> roll_map; 
+
+		public void Run (object o, EventArgs e)
+		{
+			from_db = new Db ();
+			to_db = Core.Database;
+
+			ShowDialog ();
+		}
+
+		public void ShowDialog () {
+			Glade.XML xml = new Glade.XML (null, "MergeDb.glade", "mergedb_dialog", "f-spot");
+			xml.Autoconnect (this);
+			mergedb_dialog.Modal = false;
+			mergedb_dialog.TransientFor = null;
+
+			db_filechooser.FileSet += HandleFileSet;
+
+			newrolls_radio.Toggled += HandleRollsChanged;
+			allrolls_radio.Toggled += HandleRollsChanged;
+			singleroll_radio.Toggled += HandleRollsChanged;
+
+			rolls_combo.Changed += HandleRollsChanged;
+
+			mergedb_dialog.Response += HandleResponse;
+			mergedb_dialog.ShowAll ();
+		}
+
+		void HandleFileSet (object o, EventArgs e)
+		{
+			Log.DebugFormat ("FileChooser Activated, trying to open {0}...", db_filechooser.Filename);
+			try {
+				from_db.Init (db_filechooser.Filename, true);
+				query = new PhotoQuery (from_db.Photos);
+			
+				CheckRolls ();
+				rolls_combo.Active = 0;
+
+				newrolls_radio.Sensitive = true;
+				allrolls_radio.Sensitive = true;
+				singleroll_radio.Sensitive = true;
+
+				apply_button.Sensitive = true;
+
+				newrolls_radio.Active = true;
+				HandleRollsChanged (null, null);
+			} catch (Exception ex) {
+				Log.Exception (ex);
+			}
+		}
+
+		void CheckRolls ()
+		{
+			List<Roll> from_rolls = new List<Roll> (from_db.Rolls.GetRolls ());
+			Roll [] to_rolls = to_db.Rolls.GetRolls ();
+			foreach (Roll tr in to_rolls)
+				foreach (Roll fr in from_rolls.ToArray ())
+					if (tr.Time == fr.Time)
+						from_rolls.Remove (fr);
+			new_rolls = from_rolls.ToArray ();
+
+			foreach (Roll r in from_rolls) {
+				uint numphotos = from_db.Rolls.PhotosInRoll (r);
+				DateTime date = r.Time.ToLocalTime ();
+				rolls_combo.AppendText (String.Format ("{0} ({1})", date.ToString("%dd %MMM, %HH:%mm"), numphotos));
+			}
+		}
+
+		void HandleRollsChanged (object o, EventArgs e)
+		{
+			rolls_combo.Sensitive = singleroll_radio.Active;
+
+			if (allrolls_radio.Active)
+				query.RollSet = null;
+
+			if (newrolls_radio.Active)
+				query.RollSet = new RollSet (new_rolls);
+
+			if (singleroll_radio.Active) {
+				Console.WriteLine (rolls_combo.Active);
+				query.RollSet = new RollSet (new_rolls [rolls_combo.Active]);
+			}
+		}
+
+		void HandleResponse (object obj, ResponseArgs args) {
+			if (args.ResponseId == ResponseType.Accept) {
+				Roll [] mergerolls = singleroll_radio.Active ? new Roll [] {new_rolls [rolls_combo.Active]} : new_rolls;
+				DoMerge (query, mergerolls, false);
+			}
+			mergedb_dialog.Destroy ();
+		}
+
+
+		public static void Merge (string path, Db to_db)
+		{
+			Log.WarningFormat ("Will merge db {0} into main f-spot db {1}", path, FSpot.Global.BaseDirectory + "/photos.db" );
+			Db from_db = new Db ();
+			from_db.Init (path, true);
+			//MergeDb mdb = new MergeDb (from_db, to_db);
+
+		}
+
+		void DoMerge (PhotoQuery query, Roll [] rolls, bool copy)
+		{
+			tag_map = new Dictionary<uint, Tag> ();
+			roll_map = new Dictionary<uint, uint> ();
+
+			Log.Warning ("Merging tags");
+			MergeTags (from_db.Tags.RootCategory);
+
+			Log.Warning ("Creating the rolls");
+			CreateRolls (rolls);
+
+			Log.Warning ("Importing photos");
+			ImportPhotos (query, copy);
+			
+		}
+
+		void MergeTags (Tag tag_to_merge)
+		{
+			TagStore from_store = from_db.Tags;
+			TagStore to_store = to_db.Tags;
+			
+			if (tag_to_merge != from_store.RootCategory) { //Do not merge RootCategory
+				Tag dest_tag = to_store.GetTagByName (tag_to_merge.Name);
+				if (dest_tag == null) {
+					Category parent = (tag_to_merge.Category == from_store.RootCategory) ? 
+							to_store.RootCategory : 
+							to_store.GetTagByName (tag_to_merge.Category.Name) as Category;
+					dest_tag = to_store.CreateTag (parent, tag_to_merge.Name);
+					//FIXME: copy the tag icon and commit
+				}
+				tag_map [tag_to_merge.Id] = dest_tag;
+			}
+
+			if (!(tag_to_merge is Category))
+				return;
+
+			foreach (Tag t in (tag_to_merge as Category).Children)
+				MergeTags (t);
+		}
+
+		void CreateRolls (Roll [] rolls)
+		{
+			RollStore from_store = from_db.Rolls;
+			RollStore to_store = to_db.Rolls;
+
+			foreach (Roll roll in rolls) {
+				if (from_store.PhotosInRoll (roll) == 0)
+					continue;
+				roll_map [roll.Id] = (to_store.Create (roll.Time).Id);
+			}
+		}
+
+		void ImportPhotos (PhotoQuery query, bool copy)
+		{
+			foreach (Photo p in query.Photos)
+				ImportPhoto (p, copy);
+		}
+
+		void ImportPhoto (Photo photo, bool copy)
+		{
+			Log.WarningFormat ("Importing {0}", photo.Name);
+			PhotoStore from_store = from_db.Photos;
+			PhotoStore to_store = to_db.Photos;
+
+			Gdk.Pixbuf pixbuf;
+			Photo newp = to_store.Create (photo.VersionUri (Photo.OriginalVersionId), roll_map [photo.RollId], out pixbuf);
+
+
+			foreach (Tag t in photo.Tags) {
+				Log.WarningFormat ("Tagging with {0}", t.Name);
+				newp.AddTag (tag_map [t.Id]);
+			}
+
+			foreach (uint version_id in photo.VersionIds)
+				if (version_id != Photo.OriginalVersionId) {
+					PhotoVersion version = photo.GetVersion (version_id) as PhotoVersion;
+					uint newv = newp.AddVersion (version.Uri, version.Name, version.IsProtected);
+					if (version_id == photo.DefaultVersionId)
+						newp.DefaultVersionId = newv;
+				}
+
+			//FIXME Import extra info (time, description, rating)
+			newp.Time = photo.Time;
+			newp.Description = photo.Description;
+			newp.Rating = photo.Rating;
+			
+			to_store.Commit (newp);
+		}
+	}
+}
+

Added: trunk/extensions/MergeDb/MergeDb.glade
==============================================================================
--- (empty file)
+++ trunk/extensions/MergeDb/MergeDb.glade	Mon Aug 25 15:58:18 2008
@@ -0,0 +1,269 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.3 on Mon Aug 25 17:35:47 2008 -->
+<glade-interface>
+  <widget class="GtkDialog" id="mergedb_dialog">
+    <property name="border_width">5</property>
+    <property name="title" translatable="yes">Merge another f-spot collection</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <widget class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <widget class="GtkTable" id="table1">
+            <property name="visible">True</property>
+            <property name="n_rows">9</property>
+            <property name="n_columns">3</property>
+            <property name="column_spacing">6</property>
+            <property name="row_spacing">6</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label5">
+                <property name="visible">True</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;Copy the images locally or keep them where they are. If you chose the later, be sure that this location will stay accessible from f-spot.&lt;/i&gt;&lt;/small&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="wrap">True</property>
+                <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">8</property>
+                <property name="bottom_attach">9</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkRadioButton" id="keep_radio">
+                <property name="visible">True</property>
+                <property name="sensitive">False</property>
+                <property name="can_focus">True</property>
+                <property name="label" translatable="yes">Keep the images at their original location</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
+                <property name="group">copy_radio</property>
+              </widget>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">7</property>
+                <property name="bottom_attach">8</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkRadioButton" id="copy_radio">
+                <property name="visible">True</property>
+                <property name="sensitive">False</property>
+                <property name="can_focus">True</property>
+                <property name="label" translatable="yes">Copy images to Photos/</property>
+                <property name="response_id">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </widget>
+              <packing>
+                <property name="right_attach">3</property>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label4">
+                <property name="visible">True</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;Choose what to import from the selected db. 
+"Everything" will import everything, creating duplicates if you already imported from that database.
+"New Rolls only" is the smart option that will avoid re-importing you could have imported during a previous operation.
+"A Single Import Roll" let you choose which roll you want to merge back.&lt;/i&gt;&lt;/small&gt;</property>
+                <property name="use_markup">True</property>
+                <property name="wrap">True</property>
+                <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">5</property>
+                <property name="bottom_attach">6</property>
+                <property name="y_options"></property>
+                <property name="y_padding">6</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkComboBox" id="rolls_combo">
+                <property name="visible">True</property>
+                <property name="sensitive">False</property>
+                <property name="items"></property>
+              </widget>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkRadioButton" id="allrolls_radio">
+                <property name="visible">True</property>
+                <property name="sensitive">False</property>
+                <property name="can_focus">True</property>
+                <property name="label" translatable="yes">Everything</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
+                <property name="group">newrolls_radio</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkRadioButton" id="singleroll_radio">
+                <property name="visible">True</property>
+                <property name="sensitive">False</property>
+                <property name="can_focus">True</property>
+                <property name="label" translatable="yes">A Single Import Roll</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
+                <property name="group">newrolls_radio</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkRadioButton" id="newrolls_radio">
+                <property name="visible">True</property>
+                <property name="sensitive">False</property>
+                <property name="can_focus">True</property>
+                <property name="label" translatable="yes">New Rolls Only</property>
+                <property name="response_id">0</property>
+                <property name="active">True</property>
+                <property name="draw_indicator">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label3">
+                <property name="visible">True</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">Import:</property>
+              </widget>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;Choose the location of the database you want to import from&lt;/i&gt;&lt;/small&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="y_options"></property>
+                <property name="y_padding">6</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkFileChooserButton" id="db_filechooser">
+                <property name="visible">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">Database Location:</property>
+              </widget>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <widget class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="cancel_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-6</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="apply_button">
+                <property name="visible">True</property>
+                <property name="sensitive">False</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-3</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>



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