[f-spot/replace-import] Start replacing import by a more clean version.
- From: Ruben Vermeersch <rubenv src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [f-spot/replace-import] Start replacing import by a more clean version.
- Date: Fri, 4 Jun 2010 23:56:04 +0000 (UTC)
commit 76544991b61fcfc0b5146f1c7ccd20079e29a727
Author: Ruben Vermeersch <ruben savanne be>
Date: Sat Jun 5 01:48:35 2010 +0200
Start replacing import by a more clean version.
src/Core/Global.cs | 9 +-
src/FileImportBackend.cs | 22 +-
src/Import/FileImportSource.cs | 123 +++++++++++++
src/Import/ImportController.cs | 307 +++++++++++++++++++++++++++++++
src/Import/ImportSource.cs | 22 +++
src/ImportCommand.cs | 12 +-
src/MainWindow.cs | 19 ++-
src/Makefile.am | 5 +
src/PhotoStore.cs | 13 +-
src/Term.cs | 1 -
src/UI.Dialog/ImportDialog.cs | 319 ++++++++++++++++++++++++++++++++
src/UI.Dialog/PreferenceDialog.cs | 9 +-
src/UI.Dialog/ThreadProgressDialog.cs | 2 -
src/f-spot.glade | 305 -------------------------------
src/main.cs | 12 +-
src/ui/import.ui | 325 +++++++++++++++++++++++++++++++++
16 files changed, 1154 insertions(+), 351 deletions(-)
---
diff --git a/src/Core/Global.cs b/src/Core/Global.cs
index d7aef6a..a92e014 100644
--- a/src/Core/Global.cs
+++ b/src/Core/Global.cs
@@ -5,6 +5,7 @@
*
*/
using System;
+using Hyena;
namespace FSpot {
public static class Global {
@@ -20,10 +21,10 @@ namespace FSpot {
set { base_dir = value; }
}
- private static string photo_directory;
- public static string PhotoDirectory {
- get { return photo_directory; }
- set { photo_directory = value; }
+ private static SafeUri photo_uri;
+ public static SafeUri PhotoUri {
+ get { return photo_uri; }
+ set { photo_uri = value; }
}
public static string HelpDirectory {
diff --git a/src/FileImportBackend.cs b/src/FileImportBackend.cs
index 550edd8..d0ab7f4 100644
--- a/src/FileImportBackend.cs
+++ b/src/FileImportBackend.cs
@@ -100,7 +100,7 @@ public class FileImportBackend : ImportBackend {
}
- public static SafeUri UniqueName (string path, string filename)
+/* public static SafeUri UniqueName (string path, string filename)
{
int i = 1;
string dest = System.IO.Path.Combine (path, filename);
@@ -115,7 +115,7 @@ public class FileImportBackend : ImportBackend {
}
return new SafeUri ("file://"+dest, true);
- }
+ }*/
public static SafeUri ChooseLocation (SafeUri uri)
{
@@ -124,14 +124,14 @@ public class FileImportBackend : ImportBackend {
private static SafeUri ChooseLocation (SafeUri uri, Stack created_directories)
{
- string name = uri.GetFilename ();
+/* string name = uri.GetFilename ();
DateTime time;
using (FSpot.ImageFile img = FSpot.ImageFile.Create (uri)) {
time = img.Date;
}
string dest_dir = String.Format ("{0}{1}{2}{1}{3:D2}{1}{4:D2}",
- FSpot.Global.PhotoDirectory,
+ FSpot.Global.PhotoUri, // FIXME broken
System.IO.Path.DirectorySeparatorChar,
time.Year,
time.Month,
@@ -159,15 +159,15 @@ public class FileImportBackend : ImportBackend {
}
info = System.IO.Directory.CreateDirectory (dest_dir);
- }
+ }*/
// If the destination we'd like to use is the file itself return that
- if ("file://" + Path.Combine (dest_dir, name) == uri.ToString ())
- return uri;
+ //if ("file://" + Path.Combine (dest_dir, name) == uri.ToString ())
+ // return uri;
- var dest = UniqueName (dest_dir, name);
+ //var dest = UniqueName (dest_dir, name);
- return dest;
+ return uri;
}
public override bool Step (out StepStatusInfo status_info)
@@ -195,7 +195,7 @@ public class FileImportBackend : ImportBackend {
info.DestinationUri = destination;
if (detect_duplicates)
- photo = store.CheckForDuplicate (destination);
+ photo = null;//store.CheckForDuplicate (destination);
if (photo == null)
photo = store.Create (info.DestinationUri, roll.Id);
@@ -208,7 +208,7 @@ public class FileImportBackend : ImportBackend {
info.DestinationUri = destination;
if (detect_duplicates)
- photo = store.CheckForDuplicate (destination);
+ photo = null;// store.CheckForDuplicate (destination);
if (photo == null)
{
diff --git a/src/Import/FileImportSource.cs b/src/Import/FileImportSource.cs
new file mode 100644
index 0000000..8239bb7
--- /dev/null
+++ b/src/Import/FileImportSource.cs
@@ -0,0 +1,123 @@
+using Hyena;
+using System;
+using System.Threading;
+using System.Collections.Generic;
+using FSpot.Utils;
+
+namespace FSpot.Import
+{
+ internal class FileImportSource : ImportSource {
+ public string Name { get; set; }
+ public string IconName { get; set; }
+ public SafeUri Root { get; set; }
+
+ public Thread PhotoScanner;
+
+ public FileImportSource (SafeUri root, string name, string icon_name)
+ {
+ Log.Debug ("Added source "+Name);
+ Root = root;
+ Name = name;
+
+ if (IsIPodPhoto) {
+ IconName = "multimedia-player";
+ } else if (IsCamera) {
+ IconName = "media-flash";
+ } else {
+ IconName = icon_name;
+ }
+ }
+
+ public void StartPhotoScan (ImportController controller)
+ {
+ if (PhotoScanner != null)
+ PhotoScanner.Abort ();
+
+ PhotoScanner = ThreadAssist.Spawn (() => ScanPhotos (controller));
+ }
+
+ void ScanPhotos (ImportController controller)
+ {
+ var infos = new List<FileImportInfo> ();
+ var enumerator = new RecursiveFileEnumerator (Root, controller.RecurseSubdirectories, true);
+ foreach (var file in enumerator) {
+ if (ImageFile.HasLoader (new SafeUri (file.Uri, true))) {
+ infos.Add (new FileImportInfo (new SafeUri(file.Uri, true)));
+ }
+
+ if (infos.Count % 10 == 0) {
+ var to_add = infos; // prevents race condition
+ ThreadAssist.ProxyToMain (() => controller.Photos.Add (to_add.ToArray ()));
+ infos = new List<FileImportInfo> ();
+ }
+ }
+
+ if (infos.Count > 0) {
+ ThreadAssist.ProxyToMain (() => controller.Photos.Add (infos.ToArray ()));
+ }
+
+ controller.PhotoScanFinished ();
+ }
+
+ public void Deactivate ()
+ {
+ if (PhotoScanner != null) {
+ PhotoScanner.Abort (); // FIXME: abort is not nice
+ PhotoScanner = null;
+ }
+ }
+
+ private bool IsCamera {
+ get {
+ try {
+ var file = GLib.FileFactory.NewForUri (Root.Append ("DCIM"));
+ return file.Exists;
+ } catch {
+ return false;
+ }
+ }
+ }
+
+ private bool IsIPodPhoto {
+ get {
+ try {
+ var file = GLib.FileFactory.NewForUri (Root.Append ("Photos"));
+ var file2 = GLib.FileFactory.NewForUri (Root.Append ("iPod_Control"));
+ return file.Exists && file2.Exists;
+ } catch {
+ return false;
+ }
+ }
+ }
+ }
+
+ internal class FileImportInfo : IBrowsableItem {
+ public FileImportInfo (SafeUri original)
+ {
+ DefaultVersion = new ImportInfoVersion () {
+ BaseUri = original.GetBaseUri (),
+ Filename = original.GetFilename ()
+ };
+
+ try {
+ using (FSpot.ImageFile img = FSpot.ImageFile.Create (original)) {
+ Time = img.Date;
+ }
+ } catch (Exception) {
+ Time = DateTime.Now;
+ }
+ }
+
+ public IBrowsableItemVersion DefaultVersion { get; private set; }
+ public SafeUri DestinationUri { get; set; }
+
+ public System.DateTime Time { get; private set; }
+
+ public Tag [] Tags { get { throw new NotImplementedException (); } }
+ public string Description { get { throw new NotImplementedException (); } }
+ public string Name { get { throw new NotImplementedException (); } }
+ public uint Rating { get { return 0; } }
+
+ internal uint PhotoId { get; set; }
+ }
+}
diff --git a/src/Import/ImportController.cs b/src/Import/ImportController.cs
new file mode 100644
index 0000000..6e04597
--- /dev/null
+++ b/src/Import/ImportController.cs
@@ -0,0 +1,307 @@
+using Hyena;
+using FSpot.Utils;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace FSpot.Import
+{
+ public enum ImportEvent {
+ SourceChanged,
+ PhotoScanStarted,
+ PhotoScanFinished,
+ ImportStarted,
+ ImportFinished,
+ ImportError
+ }
+
+ public class ImportController
+ {
+ public PhotoList Photos { get; private set; }
+
+ public ImportController ()
+ {
+ Photos = new PhotoList ();
+ LoadPreferences ();
+ }
+
+ ~ImportController ()
+ {
+ DeactivateSource (ActiveSource);
+ }
+
+#region Import Preferences
+
+ private bool copy_files;
+ private bool recurse_subdirectories;
+ private bool duplicate_detect;
+
+ public bool CopyFiles {
+ get { return copy_files; }
+ set { copy_files = value; SavePreferences (); }
+ }
+
+ public bool RecurseSubdirectories {
+ get { return recurse_subdirectories; }
+ set { recurse_subdirectories = value; SavePreferences (); RescanPhotos (); }
+ }
+
+ public bool DuplicateDetect {
+ get { return duplicate_detect; }
+ set { duplicate_detect = value; SavePreferences (); }
+ }
+
+ void LoadPreferences ()
+ {
+ copy_files = Preferences.Get<bool> (Preferences.IMPORT_COPY_FILES);
+ recurse_subdirectories = Preferences.Get<bool> (Preferences.IMPORT_INCLUDE_SUBFOLDERS);
+ duplicate_detect = Preferences.Get<bool> (Preferences.IMPORT_CHECK_DUPLICATES);
+ }
+
+ void SavePreferences ()
+ {
+ Preferences.Set(Preferences.IMPORT_COPY_FILES, copy_files);
+ Preferences.Set(Preferences.IMPORT_INCLUDE_SUBFOLDERS, recurse_subdirectories);
+ Preferences.Set(Preferences.IMPORT_CHECK_DUPLICATES, duplicate_detect);
+ }
+
+#endregion
+
+#region Source Scanning
+
+ private List<ImportSource> sources;
+ public List<ImportSource> Sources {
+ get {
+ if (sources == null)
+ sources = ScanSources ();
+ return sources;
+ }
+ }
+
+ List<ImportSource> ScanSources ()
+ {
+ var monitor = GLib.VolumeMonitor.Default;
+ var sources = new List<ImportSource> ();
+ foreach (var mount in monitor.Mounts) {
+ var root = new SafeUri (mount.Root.Uri, true);
+ var icon = (mount.Icon as GLib.ThemedIcon).Names [0];
+ sources.Add (new FileImportSource (root, mount.Name, icon));
+ }
+ return sources;
+ }
+
+#endregion
+
+#region Status Reporting
+
+ public delegate void ImportProgressHandler (int current, int total);
+ public event ImportProgressHandler ProgressUpdated;
+
+ public delegate void ImportEventHandler (ImportEvent evnt);
+ public event ImportEventHandler StatusEvent;
+
+ void FireEvent (ImportEvent evnt)
+ {
+ var h = StatusEvent;
+ if (h != null)
+ h (evnt);
+ }
+
+ void ReportProgress (int current, int total)
+ {
+ var h = ProgressUpdated;
+ if (h != null)
+ h (current, total);
+ }
+
+#endregion
+
+#region Source Switching
+
+ private ImportSource active_source;
+ public ImportSource ActiveSource {
+ set {
+ if (value == active_source)
+ return;
+ var old_source = active_source;
+ active_source = value;
+ FireEvent (ImportEvent.SourceChanged);
+ RescanPhotos ();
+ DeactivateSource (old_source);
+ }
+ get {
+ return active_source;
+ }
+ }
+
+ void DeactivateSource (ImportSource source)
+ {
+ if (source == null)
+ return;
+ source.Deactivate ();
+ }
+
+ void RescanPhotos ()
+ {
+ Photos.Clear ();
+ ActiveSource.StartPhotoScan (this);
+ FireEvent (ImportEvent.PhotoScanStarted);
+ }
+
+#endregion
+
+#region Source Progress Signalling
+
+ // These are callbacks that should be called by the sources.
+
+ public void PhotoScanFinished ()
+ {
+ FireEvent (ImportEvent.PhotoScanFinished);
+ }
+
+#endregion
+
+#region Importing
+
+ Thread ImportThread;
+
+ public void StartImport ()
+ {
+ if (ImportThread != null)
+ throw new Exception ("Import already running!");
+
+ FireEvent (ImportEvent.ImportStarted);
+ ImportThread = ThreadAssist.Spawn (() => DoImport ());
+ }
+
+ public void CancelImport ()
+ {
+
+ }
+
+ Stack<SafeUri> created_directories;
+ List<uint> imported_photos;
+ PhotoStore store = App.Instance.Database.Photos;
+ RollStore rolls = FSpot.App.Instance.Database.Rolls;
+
+ void DoImport ()
+ {
+ created_directories = new Stack<SafeUri> ();
+ imported_photos = new List<uint> ();
+ Roll roll = rolls.Create ();
+
+ EnsureDirectory (Global.PhotoUri);
+
+ try {
+ int i = 0;
+ int total = Photos.Count;
+ foreach (var info in Photos.Items) {
+ ThreadAssist.ProxyToMain (() => ReportProgress (i++, total));
+ ImportPhoto (info, roll.Id);
+ }
+
+ FinishImport ();
+ } catch (Exception e) {
+ RollbackImport ();
+ throw e;
+ } finally {
+ if (imported_photos.Count == 0)
+ rolls.Remove (roll);
+ imported_photos = null;
+ created_directories = null;
+ Photo.ResetMD5Cache ();
+ DeactivateSource (ActiveSource);
+ Photos.Clear ();
+ System.GC.Collect ();
+ }
+ }
+
+ void FinishImport ()
+ {
+ ImportThread = null;
+ FireEvent (ImportEvent.ImportFinished);
+ }
+
+ void RollbackImport ()
+ {
+ }
+
+ void ImportPhoto (IBrowsableItem item, uint roll_id)
+ {
+ var destination = FindImportDestination (item.DefaultVersion.Uri);
+
+ // Do duplicate detection
+ if (DuplicateDetect && store.CheckForDuplicate (item.DefaultVersion.Uri, destination)) {
+ return;
+ }
+
+ // Copy into photo folder.
+ if (item.DefaultVersion.Uri != destination) {
+ var file = GLib.FileFactory.NewForUri (item.DefaultVersion.Uri);
+ var new_file = GLib.FileFactory.NewForUri (destination);
+ file.Copy (new_file, GLib.FileCopyFlags.AllMetadata, null, null);
+ }
+
+ // Import photo
+ var photo = store.Create (destination,
+ item.DefaultVersion.Uri,
+ roll_id);
+
+ // FIXME: Add tags, import xmp crap
+ imported_photos.Add (photo.Id);
+ }
+
+ SafeUri FindImportDestination (SafeUri uri)
+ {
+ if (!CopyFiles)
+ return uri; // Keep it at the same place
+
+ // Find a new unique location inside the photo folder
+ string name = uri.GetFilename ();
+ DateTime time;
+ using (FSpot.ImageFile img = FSpot.ImageFile.Create (uri)) {
+ time = img.Date;
+ }
+
+ var dest_uri = Global.PhotoUri.Append (time.Year.ToString ())
+ .Append (String.Format ("{0:D2}", time.Month))
+ .Append (String.Format ("{0:D2}", time.Day));
+ EnsureDirectory (dest_uri);
+
+ // If the destination we'd like to use is the file itself return that
+ if (dest_uri.Append (name) == uri)
+ return uri;
+
+ // Find an unused name
+ int i = 1;
+ var dest = dest_uri.Append (name);
+ var file = GLib.FileFactory.NewForUri (dest);
+ while (file.Exists) {
+ var filename = uri.GetFilenameWithoutExtension ();
+ var extension = uri.GetExtension ();
+ dest = dest_uri.Append (String.Format ("{0}-{1}{2}", filename, i++, extension));
+ file = GLib.FileFactory.NewForUri (dest);
+ }
+
+ return dest;
+ }
+
+ void EnsureDirectory (SafeUri uri)
+ {
+ var parts = uri.AbsolutePath.Split('/');
+ SafeUri current = new SafeUri (uri.Scheme + ":///", true);
+ for (int i = 0; i < parts.Length; i++) {
+ current = current.Append (parts [i]);
+ var file = GLib.FileFactory.NewForUri (current);
+ if (!file.Exists) {
+ created_directories.Push (current);
+ Log.Debug ("Creating "+current);
+ file.MakeDirectory (null);
+ }
+ }
+ }
+
+#endregion
+
+ }
+}
diff --git a/src/Import/ImportSource.cs b/src/Import/ImportSource.cs
new file mode 100644
index 0000000..5c6f370
--- /dev/null
+++ b/src/Import/ImportSource.cs
@@ -0,0 +1,22 @@
+using Hyena;
+using System;
+
+namespace FSpot.Import
+{
+ public interface ImportSource {
+ string Name { get; }
+ string IconName { get; }
+
+ void StartPhotoScan (ImportController controller);
+ void Deactivate ();
+ }
+
+ public class ImportInfoVersion : IBrowsableItemVersion {
+ public string Name { get { return String.Empty; } }
+ public bool IsProtected { get { return true; } }
+ public SafeUri BaseUri { get; set; }
+ public string Filename { get; set; }
+
+ public SafeUri Uri { get { return BaseUri.Append (Filename); } }
+ }
+}
diff --git a/src/ImportCommand.cs b/src/ImportCommand.cs
index cbd0119..97762bd 100644
--- a/src/ImportCommand.cs
+++ b/src/ImportCommand.cs
@@ -335,19 +335,19 @@ public class ImportCommand : GladeDialog
private void UpdateProgressBar (int count, int total)
{
- if (progress_bar == null)
+/* if (progress_bar == null)
return;
if (count > 0)
progress_bar.Show ();
progress_bar.Text = String.Format (loading_string, count, total);
- progress_bar.Fraction = (double) count / System.Math.Max (total, 1);
+ progress_bar.Fraction = (double) count / System.Math.Max (total, 1);*/
}
private void HandleTraySelectionChanged (FSpot.IBrowsableCollection coll)
{
- if (tray.Selection.Count > 0)
- photo_view.Item.Index = tray.Selection.Ids[0];
+// if (tray.Selection.Count > 0)
+// photo_view.Item.Index = tray.Selection.Ids[0];
}
@@ -493,7 +493,7 @@ public class ImportCommand : GladeDialog
private void LoadPreferences ()
{
- if (FSpot.Preferences.Get<int> (FSpot.Preferences.IMPORT_WINDOW_WIDTH) > 0)
+ /* if (FSpot.Preferences.Get<int> (FSpot.Preferences.IMPORT_WINDOW_WIDTH) > 0)
this.Dialog.Resize (FSpot.Preferences.Get<int> (FSpot.Preferences.IMPORT_WINDOW_WIDTH), FSpot.Preferences.Get<int> (FSpot.Preferences.IMPORT_WINDOW_HEIGHT));
if (FSpot.Preferences.Get<int> (FSpot.Preferences.IMPORT_WINDOW_PANE_POSITION) > 0)
@@ -501,7 +501,7 @@ public class ImportCommand : GladeDialog
copy_check.Active = Preferences.Get<bool> (Preferences.IMPORT_COPY_FILES);
recurse_check.Active = Preferences.Get<bool> (Preferences.IMPORT_INCLUDE_SUBFOLDERS);
- duplicate_check.Active = Preferences.Get<bool> (Preferences.IMPORT_CHECK_DUPLICATES);
+ duplicate_check.Active = Preferences.Get<bool> (Preferences.IMPORT_CHECK_DUPLICATES);*/
}
public int ImportFromUri (PhotoStore store, SafeUri uri)
diff --git a/src/MainWindow.cs b/src/MainWindow.cs
index 3a95e94..d2f393b 100644
--- a/src/MainWindow.cs
+++ b/src/MainWindow.cs
@@ -27,6 +27,7 @@ using FSpot.Widgets;
using FSpot.Utils;
using FSpot.UI.Dialog;
using FSpot.Platform;
+using FSpot.Import;
namespace FSpot
{
@@ -1149,11 +1150,12 @@ namespace FSpot
public void ImportFile (SafeUri uri)
{
- ImportCommand command = new ImportCommand (main_window);
- if (command.ImportFromUri (Database.Photos, uri) > 0) {
- query.RollSet = new RollSet (Database.Rolls.GetRolls (1)[0]);
- UpdateQuery ();
- }
+ // FIXME: disabled!
+ //ImportCommand command = new ImportCommand (main_window);
+ //if (command.ImportFromUri (Database.Photos, uri) > 0) {
+ // query.RollSet = new RollSet (Database.Rolls.GetRolls (1)[0]);
+ // UpdateQuery ();
+ //}
}
void HandleIconViewDragDataReceived (object sender, DragDataReceivedArgs args)
@@ -1450,13 +1452,16 @@ namespace FSpot
void HandleImportCommand (object sender, EventArgs e)
{
- Database.Sync = false;
+ /*FIXMEDatabase.Sync = false;
ImportCommand command = new ImportCommand (main_window);
if (command.ImportFromUri (Database.Photos, null) > 0) {
query.RollSet = new RollSet (Database.Rolls.GetRolls (1)[0]);
UpdateQuery ();
}
- Database.Sync = true;
+ Database.Sync = true; */
+ var controller = new ImportController ();
+ var import_window = new ImportDialog (controller);
+ import_window.Show ();
}
void HandlePageSetupActivated (object o, EventArgs e)
diff --git a/src/Makefile.am b/src/Makefile.am
index 9d46a94..8d48bb5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -82,6 +82,9 @@ SOURCES = \
ImageLoaderThread.cs \
ImportBackend.cs \
ImportCommand.cs \
+ Import/ImportController.cs \
+ Import/ImportSource.cs \
+ Import/FileImportSource.cs \
InfoOverlay.cs \
InternalProcess.cs \
IOChannel.cs \
@@ -157,6 +160,7 @@ SOURCES = \
UI.Dialog/ExceptionDialog.cs \
UI.Dialog/GladeDialog.cs \
UI.Dialog/HigMessageDialog.cs \
+ UI.Dialog/ImportDialog.cs \
UI.Dialog/LastRollDialog.cs \
UI.Dialog/PreferenceDialog.cs \
UI.Dialog/ProgressDialog.cs \
@@ -215,6 +219,7 @@ RESOURCES = \
dces.rdf \
f-spot.glade \
ui/main_window.ui \
+ ui/import.ui \
UI.Dialog/ui/AdjustTimeDialog.ui \
UI.Dialog/ui/DateRangeDialog.ui \
UI.Dialog/ui/EditTagDialog.ui \
diff --git a/src/PhotoStore.cs b/src/PhotoStore.cs
index 5a3a732..de1d047 100644
--- a/src/PhotoStore.cs
+++ b/src/PhotoStore.cs
@@ -99,13 +99,13 @@ public class PhotoStore : DbStore<Photo> {
Database.ExecuteNonQuery ("CREATE INDEX idx_photos_roll_id ON photos(roll_id)");
}
- public Photo CheckForDuplicate (SafeUri uri) {
+ public bool CheckForDuplicate (SafeUri uri, SafeUri dest_uri) {
// Here we can go wild in comparing photos,
// for now we check on uri and md5
- Photo found = GetByUri (uri);
+ Photo found = GetByUri (dest_uri);
if (found != null)
- return found;
+ return true;
string md5 = Photo.GenerateMD5 (uri);
var file = GLib.FileFactory.NewForUri (uri);
@@ -126,10 +126,10 @@ public class PhotoStore : DbStore<Photo> {
// TODO? load pixbuf and compare sizes?
- return match;
+ return true;
}
- return null;
+ return false;
}
public Photo Create (SafeUri uri, uint roll_id)
@@ -314,8 +314,6 @@ public class PhotoStore : DbStore<Photo> {
{
Photo photo = null;
- uint timer = Log.DebugTimerStart ();
-
var base_uri = uri.GetBaseUri ();
var filename = uri.GetFilename ();
@@ -342,7 +340,6 @@ public class PhotoStore : DbStore<Photo> {
}
reader.Close();
- Log.DebugTimerPrint (timer, "GetByUri query took {0}");
if (photo == null)
return null;
diff --git a/src/Term.cs b/src/Term.cs
index d76b12f..64f4fff 100644
--- a/src/Term.cs
+++ b/src/Term.cs
@@ -17,7 +17,6 @@ namespace FSpot {
public abstract class Term {
private ArrayList sub_terms = new ArrayList ();
private Term parent = null;
- private string separator;
protected bool is_negated = false;
protected Tag tag = null;
diff --git a/src/UI.Dialog/ImportDialog.cs b/src/UI.Dialog/ImportDialog.cs
new file mode 100644
index 0000000..4fee53b
--- /dev/null
+++ b/src/UI.Dialog/ImportDialog.cs
@@ -0,0 +1,319 @@
+using FSpot.UI.Dialog;
+using FSpot.Widgets;
+using FSpot.Utils;
+using FSpot.Import;
+using Gtk;
+using Hyena;
+using System;
+using System.Collections.Generic;
+using Mono.Unix;
+
+namespace FSpot.UI.Dialog
+{
+ public class ImportDialog : BuilderDialog
+ {
+ static readonly string select_folder_label = Catalog.GetString ("Choose Folder...");
+ private ImportController Controller { get; set; }
+ private TreeStore Sources { get; set; }
+
+ private static Dictionary<string, ImportSource> history_sources = new Dictionary<string, ImportSource> ();
+
+ [GtkBeans.Builder.Object] Button cancel_button;
+ [GtkBeans.Builder.Object] Button import_button;
+ [GtkBeans.Builder.Object] CheckButton copy_check;
+ [GtkBeans.Builder.Object] CheckButton duplicate_check;
+ [GtkBeans.Builder.Object] CheckButton recurse_check;
+ [GtkBeans.Builder.Object] ComboBox sources_combo;
+ [GtkBeans.Builder.Object] HBox tagentry_box;
+ [GtkBeans.Builder.Object] HPaned import_hpaned;
+ [GtkBeans.Builder.Object] ProgressBar progress_bar;
+ [GtkBeans.Builder.Object] ScrolledWindow icon_scrolled;
+ [GtkBeans.Builder.Object] ScrolledWindow photo_scrolled;
+
+ private PhotoImageView photo_view;
+
+ public ImportDialog (ImportController controller) : base ("import.ui", "import_dialog")
+ {
+ Controller = controller;
+ BuildUI ();
+ ResetPreview ();
+ LoadPreferences ();
+ ScanSources ();
+ ConnectEvents ();
+ }
+
+ void BuildUI ()
+ {
+ photo_view = new PhotoImageView (Controller.Photos);
+ photo_scrolled.Add (photo_view);
+ photo_scrolled.SetSizeRequest (200, 200);
+ photo_view.Show ();
+
+ GtkUtil.ModifyColors (photo_scrolled);
+ GtkUtil.ModifyColors (photo_view);
+
+ var tray = new ScalingIconView (Controller.Photos);
+ tray.Selection.Changed += (c) => {
+ if (tray.Selection.Count > 0)
+ photo_view.Item.Index = tray.Selection.Ids[0];
+ };
+ icon_scrolled.Add (tray);
+ tray.DisplayTags = false;
+ tray.Show ();
+
+ progress_bar.Hide ();
+
+ import_button.Sensitive = false;
+
+ var tag_entry = new FSpot.Widgets.TagEntry (App.Instance.Database.Tags, false);
+ tag_entry.UpdateFromTagNames (new string []{});
+ tagentry_box.Add (tag_entry);
+ tag_entry.Show ();
+ }
+
+ void ResetPreview ()
+ {
+ photo_view.Pixbuf = GtkUtil.TryLoadIcon (FSpot.Global.IconTheme, "f-spot", 128, (Gtk.IconLookupFlags)0);
+ photo_view.ZoomFit (false);
+ }
+
+ void LoadPreferences ()
+ {
+ if (Preferences.Get<int> (Preferences.IMPORT_WINDOW_WIDTH) > 0) {
+ Resize (Preferences.Get<int> (Preferences.IMPORT_WINDOW_WIDTH), Preferences.Get<int> (Preferences.IMPORT_WINDOW_HEIGHT));
+ }
+
+ if (FSpot.Preferences.Get<int> (Preferences.IMPORT_WINDOW_PANE_POSITION) > 0) {
+ import_hpaned.Position = Preferences.Get<int> (Preferences.IMPORT_WINDOW_PANE_POSITION);
+ }
+
+ copy_check.Active = Controller.CopyFiles;
+ recurse_check.Active = Controller.RecurseSubdirectories;
+ duplicate_check.Active = Controller.DuplicateDetect;
+ }
+
+ void ScanSources ()
+ {
+ // Populates the source combo box
+ Sources = new TreeStore (typeof(ImportSource), typeof(string), typeof(string), typeof(bool));
+ sources_combo.Model = Sources;
+ sources_combo.RowSeparatorFunc = (m, i) => m.GetValue (i, 1) == String.Empty;
+ var render = new CellRendererPixbuf ();
+ sources_combo.PackStart (render, false);
+ sources_combo.SetAttributes (render, "icon-name", 2, "sensitive", 3);
+ var render2 = new CellRendererText ();
+ sources_combo.PackStart (render2, true);
+ sources_combo.SetAttributes (render2, "text", 1, "sensitive", 3);
+
+ GLib.Idle.Add (() => {
+ PopulateSourceCombo (null);
+ return false;
+ });
+ }
+
+ void PopulateSourceCombo (ImportSource source_to_activate)
+ {
+ int activate_index = 0;
+ sources_combo.Changed -= OnSourceComboChanged;
+ Sources.Clear ();
+ Sources.AppendValues (null, Catalog.GetString ("Choose Import source..."), String.Empty, false);
+ Sources.AppendValues (null, select_folder_label, "folder", true);
+ Sources.AppendValues (null, String.Empty, String.Empty);
+ bool mount_added = false;
+ foreach (var source in Controller.Sources) {
+ if (source == source_to_activate) {
+ activate_index = Sources.IterNChildren ();
+ }
+ Sources.AppendValues (source, source.Name, source.IconName, true);
+ mount_added = true;
+ }
+ if (!mount_added) {
+ Sources.AppendValues (null, Catalog.GetString ("(No Cameras Detected)"), String.Empty, false);
+ }
+
+ if (history_sources.Count > 0) {
+ Sources.AppendValues (null, String.Empty, String.Empty);
+ foreach (var source in history_sources.Values) {
+ if (source == source_to_activate) {
+ activate_index = Sources.IterNChildren ();
+ }
+ Sources.AppendValues (source, source.Name, source.IconName, true);
+ }
+ }
+ sources_combo.Changed += OnSourceComboChanged;
+ sources_combo.Active = activate_index;
+ }
+
+ void ConnectEvents ()
+ {
+ Controller.StatusEvent += OnControllerStatusEvent;
+ Controller.ProgressUpdated += OnControllerProgressUpdated;
+ copy_check.Toggled += (o, args) => { Controller.CopyFiles = copy_check.Active; };
+ recurse_check.Toggled += (o, args) => { Controller.RecurseSubdirectories = recurse_check.Active; };
+ duplicate_check.Toggled += (o, args) => { Controller.DuplicateDetect = duplicate_check.Active; };
+ import_button.Clicked += (o, args) => StartImport ();
+ cancel_button.Clicked += (o, args) => CancelImport ();
+ Response += (o, args) => {
+ if (args.ResponseId == ResponseType.DeleteEvent) {
+ CancelImport ();
+ }
+ };
+ }
+
+ void ShowFolderSelector ()
+ {
+ var file_chooser = new FileChooserDialog (
+ Catalog.GetString ("Import"), this,
+ FileChooserAction.SelectFolder,
+ Stock.Cancel, ResponseType.Cancel,
+ Stock.Open, ResponseType.Ok);
+
+ file_chooser.SelectMultiple = false;
+ file_chooser.LocalOnly = false;
+
+ int response = file_chooser.Run ();
+ if ((ResponseType) response == ResponseType.Ok) {
+ var uri = new SafeUri (file_chooser.Uri, true);
+ SwitchToFolderSource (uri);
+ }
+
+ file_chooser.Destroy ();
+ }
+
+ void SwitchToFolderSource (SafeUri uri)
+ {
+ ImportSource source = null;
+ if (!history_sources.TryGetValue (uri, out source)) {
+ var name = uri.GetFilename ();
+ source = new FileImportSource (uri, name, "folder");
+ history_sources[uri] = source;
+ }
+
+ PopulateSourceCombo (source);
+ Controller.ActiveSource = source;
+ }
+
+ int current_index = -1;
+ void OnSourceComboChanged (object sender, EventArgs args)
+ {
+ // Prevent double firing.
+ if (sources_combo.Active == current_index) {
+ Log.Debug ("Skipping double fire!");
+ return;
+ } else {
+ current_index = sources_combo.Active;
+ }
+
+ TreeIter iter;
+ sources_combo.GetActiveIter (out iter);
+ var source = Sources.GetValue (iter, 0) as ImportSource;
+ if (source == null) {
+ var label = (string) Sources.GetValue (iter, 1);
+ if (label == select_folder_label) {
+ ShowFolderSelector ();
+ return;
+ } else {
+ sources_combo.Active = 0;
+ return;
+ }
+ }
+ Controller.ActiveSource = source;
+ }
+
+ void OnControllerStatusEvent (ImportEvent evnt)
+ {
+ Log.DebugFormat ("Received controller event: {0}", evnt);
+
+ switch (evnt) {
+ case ImportEvent.SourceChanged:
+ HideScanSpinner ();
+ ResetPreview ();
+ import_button.Sensitive = true;
+ break;
+
+ case ImportEvent.PhotoScanStarted:
+ ShowScanSpinner ();
+ break;
+
+ case ImportEvent.PhotoScanFinished:
+ HideScanSpinner ();
+ break;
+
+ case ImportEvent.ImportStarted:
+ import_button.Sensitive = false;
+ OptionsSensitive = false;
+ ShowImportProgress ();
+ break;
+
+ case ImportEvent.ImportFinished:
+ Controller = null;
+ Destroy ();
+ break;
+
+ case ImportEvent.ImportError:
+ // TODO
+ break;
+ }
+ }
+
+ void OnControllerProgressUpdated (int current, int total)
+ {
+ var importing_label = Catalog.GetString ("Importing Photos: {0} of {1}...");
+ progress_bar.Text = String.Format (importing_label, current, total);
+ progress_bar.Fraction = (double) current / Math.Max (total, 1);
+ }
+
+ void StartImport ()
+ {
+ Controller.StartImport ();
+ }
+
+ void CancelImport ()
+ {
+ Controller.CancelImport ();
+ Controller = null;
+ Destroy ();
+ }
+
+ bool pulse_timeout_running = false;
+
+ void ShowImportProgress ()
+ {
+ progress_bar.Text = Catalog.GetString ("Importing photos...");
+ progress_bar.Show ();
+ }
+
+ void ShowScanSpinner ()
+ {
+ // TODO: Using a GtkSpinner would be nicer here.
+ progress_bar.Text = Catalog.GetString ("Searching for photos...");
+ progress_bar.Show ();
+ pulse_timeout_running = true;
+ GLib.Timeout.Add (40, () => {
+ if (!pulse_timeout_running) {
+ return false;
+ }
+
+ progress_bar.Pulse ();
+ return pulse_timeout_running;
+ });
+ }
+
+ void HideScanSpinner ()
+ {
+ pulse_timeout_running = false;
+ progress_bar.Hide ();
+ }
+
+ public bool OptionsSensitive
+ {
+ set {
+ sources_combo.Sensitive = value;
+ copy_check.Sensitive = value;
+ recurse_check.Sensitive = value;
+ duplicate_check.Sensitive = value;
+ tagentry_box.Sensitive = value;
+ }
+ }
+ }
+}
diff --git a/src/UI.Dialog/PreferenceDialog.cs b/src/UI.Dialog/PreferenceDialog.cs
index c0191bd..bd4634f 100644
--- a/src/UI.Dialog/PreferenceDialog.cs
+++ b/src/UI.Dialog/PreferenceDialog.cs
@@ -17,6 +17,7 @@ using System.Collections.Generic;
using System.Linq;
using Gtk;
using Mono.Unix;
+using Hyena;
using FSpot.Widgets;
@@ -38,11 +39,11 @@ namespace FSpot.UI.Dialog {
TransientFor = parent;
//Photos Folder
- if (Global.PhotoDirectory == Preferences.Get<string> (Preferences.STORAGE_PATH)) {
- photosdir_chooser.SetCurrentFolder (Global.PhotoDirectory);
+ if (Global.PhotoUri == new SafeUri (Preferences.Get<string> (Preferences.STORAGE_PATH))) {
+ photosdir_chooser.SetCurrentFolderUri (Global.PhotoUri);
photosdir_chooser.CurrentFolderChanged += HandlePhotosdirChanged;
} else {
- photosdir_chooser.SetCurrentFolder(Global.PhotoDirectory);
+ photosdir_chooser.SetCurrentFolderUri (Global.PhotoUri);
photosdir_chooser.Sensitive = false;
}
@@ -193,7 +194,7 @@ namespace FSpot.UI.Dialog {
photosdir_chooser.CurrentFolderChanged -= HandlePhotosdirChanged;
Preferences.Set (Preferences.STORAGE_PATH, photosdir_chooser.Filename);
photosdir_chooser.CurrentFolderChanged += HandlePhotosdirChanged;
- Global.PhotoDirectory = photosdir_chooser.Filename;
+ Global.PhotoUri = new SafeUri (photosdir_chooser.Uri, true);
}
void HandleWritemetadataGroupChanged (object sender, System.EventArgs args)
diff --git a/src/UI.Dialog/ThreadProgressDialog.cs b/src/UI.Dialog/ThreadProgressDialog.cs
index 273321b..55ed22a 100644
--- a/src/UI.Dialog/ThreadProgressDialog.cs
+++ b/src/UI.Dialog/ThreadProgressDialog.cs
@@ -28,7 +28,6 @@ namespace FSpot.UI.Dialog {
Gtk.Button skip_button;
Gtk.ResponseType error_response;
AutoResetEvent error_response_event;
- AutoResetEvent error_response_ack_event;
object syncHandle = new object ();
@@ -150,7 +149,6 @@ namespace FSpot.UI.Dialog {
RetrySkipVisible = true;
error_response_event = new AutoResetEvent (false);
- error_response_ack_event = new AutoResetEvent (false);
error_response_event.WaitOne ();
RetrySkipVisible = false;
diff --git a/src/f-spot.glade b/src/f-spot.glade
index 777d280..2513371 100644
--- a/src/f-spot.glade
+++ b/src/f-spot.glade
@@ -1816,311 +1816,6 @@
</widget>
</child>
</widget>
- <widget class="GtkDialog" id="import_dialog">
- <property name="title" translatable="yes">Import</property>
- <property name="modal">True</property>
- <property name="default_width">664</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-vbox14">
- <property name="visible">True</property>
- <child>
- <widget class="GtkVBox" id="vbox62">
- <property name="visible">True</property>
- <property name="border_width">6</property>
- <property name="spacing">6</property>
- <child>
- <widget class="GtkVBox" id="vbox65">
- <property name="visible">True</property>
- <property name="spacing">6</property>
- <child>
- <widget class="GtkHBox" id="hbox59">
- <property name="visible">True</property>
- <property name="spacing">6</property>
- <child>
- <widget class="GtkLabel" id="import_label">
- <property name="visible">True</property>
- <property name="label" translatable="yes" comments="Translators: this string means 'source of import'">Import Source:</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkOptionMenu" id="source_option_menu">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="response_id">0</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkHPaned" id="import_hpaned">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <widget class="GtkScrolledWindow" id="icon_scrolled">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <child>
- <placeholder/>
- </child>
- </widget>
- <packing>
- <property name="resize">False</property>
- <property name="shrink">True</property>
- </packing>
- </child>
- <child>
- <widget class="GtkScrolledWindow" id="photo_scrolled">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <child>
- <placeholder/>
- </child>
- </widget>
- <packing>
- <property name="resize">True</property>
- <property name="shrink">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <widget class="GtkProgressBar" id="progress_bar">
- <property name="visible">True</property>
- <property name="pulse_step">0.10000000149</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <widget class="GtkTable" id="table19">
- <property name="visible">True</property>
- <property name="n_rows">2</property>
- <property name="n_columns">2</property>
- <property name="column_spacing">6</property>
- <property name="row_spacing">6</property>
- <child>
- <widget class="GtkHBox" id="hbox57">
- <property name="visible">True</property>
- <property name="spacing">6</property>
- <child>
- <widget class="GtkLabel" id="source_label">
- <property name="visible">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label136">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- </widget>
- <packing>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkHBox" id="tagentry_box">
- <property name="visible">True</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options">GTK_FILL</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label228">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Attach Tags:</property>
- </widget>
- <packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">GTK_FILL</property>
- <property name="y_options"></property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <widget class="GtkCheckButton" id="duplicate_check">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Detect duplicates</property>
- <property name="use_underline">True</property>
- <property name="response_id">0</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">3</property>
- </packing>
- </child>
- <child>
- <widget class="GtkCheckButton" id="copy_check">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Copy files to the Photos folder</property>
- <property name="use_underline">True</property>
- <property name="response_id">0</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">4</property>
- </packing>
- </child>
- <child>
- <widget class="GtkCheckButton" id="recurse_check">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label" translatable="yes">Include subfolders</property>
- <property name="use_underline">True</property>
- <property name="response_id">0</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="pack_type">GTK_PACK_END</property>
- <property name="position">5</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area14">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
- <child>
- <widget class="GtkButton" id="okbutton7">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="can_default">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="response_id">-6</property>
- </widget>
- </child>
- <child>
- <widget class="GtkButton" id="ok_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="can_default">True</property>
- <property name="response_id">-5</property>
- <child>
- <widget class="GtkAlignment" id="alignment49">
- <property name="visible">True</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <child>
- <widget class="GtkHBox" id="hbox64">
- <property name="visible">True</property>
- <property name="spacing">2</property>
- <child>
- <widget class="GtkImage" id="image15">
- <property name="visible">True</property>
- <property name="stock">gtk-ok</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label157">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Import</property>
- <property name="use_underline">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </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>
<widget class="GtkWindow" id="single_view">
<property name="visible">True</property>
<property name="title" translatable="yes">F-Spot View</property>
diff --git a/src/main.cs b/src/main.cs
index d8cfba0..fba545f 100644
--- a/src/main.cs
+++ b/src/main.cs
@@ -62,6 +62,7 @@ namespace FSpot
List<string> uris = new List<string> ();
Unix.SetProcessName (Defines.PACKAGE);
ThreadAssist.InitializeMainThread ();
+ ThreadAssist.ProxyToMainHandler = RunIdle;
XdgThumbnailSpec.DefaultLoader = (uri) => {
using (var file = ImageFile.Create (uri))
return file.Load ();
@@ -76,7 +77,7 @@ namespace FSpot
GLib.GType.Init ();
Catalog.Init ("f-spot", Defines.LOCALE_DIR);
- FSpot.Global.PhotoDirectory = Preferences.Get<string> (Preferences.STORAGE_PATH);
+ FSpot.Global.PhotoUri = new SafeUri (Preferences.Get<string> (Preferences.STORAGE_PATH));
for (int i = 0; i < args.Length && !shutdown; i++) {
switch (args [i]) {
case "-h": case "-?": case "-help": case "--help": case "-usage":
@@ -102,8 +103,8 @@ namespace FSpot
Log.Error ("f-spot: -photodir option takes one argument");
return 1;
}
- FSpot.Global.PhotoDirectory = System.IO.Path.GetFullPath (args [++i]);
- Log.InformationFormat ("PhotoDirectory is now {0}", FSpot.Global.PhotoDirectory);
+ FSpot.Global.PhotoUri = new SafeUri (args [++i]);
+ Log.InformationFormat ("PhotoDirectory is now {0}", FSpot.Global.PhotoUri);
break;
case "-i": case "-import": case "--import":
@@ -253,5 +254,10 @@ namespace FSpot
}
return 0;
}
+
+ public static void RunIdle (InvokeHandler handler)
+ {
+ GLib.Idle.Add (delegate { handler (); return false; });
+ }
}
}
diff --git a/src/ui/import.ui b/src/ui/import.ui
new file mode 100644
index 0000000..1c9cbf2
--- /dev/null
+++ b/src/ui/import.ui
@@ -0,0 +1,325 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 2.12 -->
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkDialog" id="import_dialog">
+ <property name="title" translatable="yes">Import</property>
+ <property name="modal">True</property>
+ <property name="default_width">664</property>
+ <property name="type_hint">dialog</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox14">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkVBox" id="vbox62">
+ <property name="visible">True</property>
+ <property name="border_width">6</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkVBox" id="vbox65">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox59">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="import_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes" comments="Translators: this string means 'source of import'">Import from:</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="sources_combo">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHPaned" id="import_hpaned">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <object class="GtkScrolledWindow" id="icon_scrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="photo_scrolled">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">automatic</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="progress_bar">
+ <property name="visible">True</property>
+ <property name="pulse_step">0.02</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkTable" id="table19">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">6</property>
+ <property name="row_spacing">6</property>
+ <child>
+ <object class="GtkHBox" id="hbox57">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="source_label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label136">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="tagentry_box">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label228">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Attach Tags:</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="duplicate_check">
+ <property name="label" translatable="yes">Detect duplicates</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="copy_check">
+ <property name="label" translatable="yes">Copy files to the Photos folder</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="recurse_check">
+ <property name="label" translatable="yes">Include subfolders</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area14">
+ <property name="visible">True</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="import_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <child>
+ <object class="GtkAlignment" id="alignment49">
+ <property name="visible">True</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <object class="GtkHBox" id="hbox64">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkImage" id="image15">
+ <property name="visible">True</property>
+ <property name="stock">gtk-ok</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label157">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Import</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel_button</action-widget>
+ <action-widget response="-5">import_button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]