5
* Thomas Van Machelen <thomas.vanmachelen@gmail.com>
7
* Based on PicasaWebExport code from Stephane Delcroix.
9
* Copyright (C) 2006 Thomas Van Machelen
16
using System.Threading;
17
using System.Collections;
18
using System.Collections.Specialized;
31
namespace FSpotSmugMugExport {
32
public class SmugMugAccount {
33
private string username;
34
private string password;
35
private SmugMugApi smugmug_proxy;
37
public SmugMugAccount (string username, string password)
39
this.username = username;
40
this.password = password;
43
public SmugMugApi Connect ()
45
System.Console.WriteLine ("SmugMug.Connect() {0}", username);
46
SmugMugApi proxy = new SmugMugApi (username, password);
47
ServicePointManager.CertificatePolicy = new NoCheckCertificatePolicy ();
50
this.smugmug_proxy = proxy;
54
private void MarkChanged()
59
public bool Connected {
61
return smugmug_proxy.Connected;
65
public string Username {
70
if (username != value) {
77
public string Password {
82
if (password != value) {
89
public SmugMugApi SmugMug {
97
public class SmugMugAccountManager
99
private static SmugMugAccountManager instance;
100
private const string keyring_item_name = "SmugMug Account";
103
public delegate void AccountListChangedHandler (SmugMugAccountManager manager, SmugMugAccount changed_account);
104
public event AccountListChangedHandler AccountListChanged;
106
public static SmugMugAccountManager GetInstance ()
108
if (instance == null) {
109
instance = new SmugMugAccountManager ();
115
private SmugMugAccountManager ()
117
accounts = new ArrayList ();
121
public void MarkChanged ()
123
MarkChanged (true, null);
126
public void MarkChanged (bool write, SmugMugAccount changed_account)
131
if (AccountListChanged != null)
132
AccountListChanged (this, changed_account);
135
public ArrayList GetAccounts ()
140
public void AddAccount (SmugMugAccount account)
142
AddAccount (account, true);
145
public void AddAccount (SmugMugAccount account, bool write)
147
accounts.Add (account);
148
MarkChanged (write, account);
151
public void RemoveAccount (SmugMugAccount account)
153
string keyring = Ring.GetDefaultKeyring();
154
Hashtable request_attributes = new Hashtable();
155
request_attributes["name"] = keyring_item_name;
156
request_attributes["username"] = account.Username;
158
foreach(ItemData result in Ring.Find(ItemType.GenericSecret, request_attributes)) {
159
Ring.DeleteItem(keyring, result.ItemID);
161
} catch (Exception e) {
162
Console.WriteLine(e);
164
accounts.Remove (account);
168
public void WriteAccounts ()
170
string keyring = Ring.GetDefaultKeyring();
171
foreach (SmugMugAccount account in accounts) {
172
Hashtable update_request_attributes = new Hashtable();
173
update_request_attributes["name"] = keyring_item_name;
174
update_request_attributes["username"] = account.Username;
176
Ring.CreateItem(keyring, ItemType.GenericSecret, keyring_item_name, update_request_attributes, account.Password, true);
180
private void ReadAccounts ()
183
Hashtable request_attributes = new Hashtable();
184
request_attributes["name"] = keyring_item_name;
186
foreach(ItemData result in Ring.Find(ItemType.GenericSecret, request_attributes)) {
187
if(!result.Attributes.ContainsKey("name") || !result.Attributes.ContainsKey("username") ||
188
(result.Attributes["name"] as string) != keyring_item_name)
191
string username = (string)result.Attributes["username"];
192
string password = result.Secret;
194
if (username == null || username == String.Empty || password == null || password == String.Empty)
195
throw new ApplicationException ("Invalid username/password in keyring");
197
SmugMugAccount account = new SmugMugAccount(username, password);
199
AddAccount (account, false);
202
} catch (Exception e) {
203
Console.Error.WriteLine(e);
210
public class SmugMugAccountDialog {
211
public SmugMugAccountDialog (Gtk.Window parent) : this (parent, null) {
212
Dialog.Response += HandleAddResponse;
213
add_button.Sensitive = false;
216
public SmugMugAccountDialog (Gtk.Window parent, SmugMugAccount account)
218
xml = new Glade.XML (null, "SmugMugExport.glade", dialog_name, "f-spot");
219
xml.Autoconnect (this);
221
Dialog.Modal = false;
222
Dialog.TransientFor = parent;
223
Dialog.DefaultResponse = Gtk.ResponseType.Ok;
225
this.account = account;
227
password_entry.ActivatesDefault = true;
228
username_entry.ActivatesDefault = true;
230
if (account != null) {
231
password_entry.Text = account.Password;
232
username_entry.Text = account.Username;
233
add_button.Label = Gtk.Stock.Ok;
234
Dialog.Response += HandleEditResponse;
237
if (remove_button != null)
238
remove_button.Visible = account != null;
242
password_entry.Changed += HandleChanged;
243
username_entry.Changed += HandleChanged;
244
HandleChanged (null, null);
247
private void HandleChanged (object sender, System.EventArgs args)
249
password = password_entry.Text;
250
username = username_entry.Text;
252
add_button.Sensitive = !(password == String.Empty || username == String.Empty);
256
protected void HandleAddResponse (object sender, Gtk.ResponseArgs args)
258
if (args.ResponseId == Gtk.ResponseType.Ok) {
259
SmugMugAccount account = new SmugMugAccount (username, password);
260
SmugMugAccountManager.GetInstance ().AddAccount (account);
265
protected void HandleEditResponse (object sender, Gtk.ResponseArgs args)
267
if (args.ResponseId == Gtk.ResponseType.Ok) {
268
account.Username = username;
269
account.Password = password;
270
SmugMugAccountManager.GetInstance ().MarkChanged (true, account);
271
} else if (args.ResponseId == Gtk.ResponseType.Reject) {
272
// NOTE we are using Reject to signal the remove action.
273
SmugMugAccountManager.GetInstance ().RemoveAccount (account);
278
private Gtk.Dialog Dialog {
281
dialog = (Gtk.Dialog) xml.GetWidget (dialog_name);
287
private SmugMugAccount account;
288
private string password;
289
private string username;
290
private string dialog_name = "smugmug_add_dialog";
291
private Glade.XML xml;
294
[Glade.Widget] Gtk.Dialog dialog;
295
[Glade.Widget] Gtk.Entry password_entry;
296
[Glade.Widget] Gtk.Entry username_entry;
298
[Glade.Widget] Gtk.Button add_button;
299
[Glade.Widget] Gtk.Button remove_button;
302
public class SmugMugAddAlbum {
303
//[Glade.Widget] Gtk.OptionMenu album_optionmenu;
305
[Glade.Widget] Gtk.Dialog dialog;
306
[Glade.Widget] Gtk.Entry title_entry;
307
[Glade.Widget] Gtk.CheckButton public_check;
308
[Glade.Widget] Gtk.ComboBox category_combo;
310
[Glade.Widget] Gtk.Button add_button;
312
private string dialog_name = "smugmug_add_album_dialog";
313
private Glade.XML xml;
314
private SmugMugExport export;
315
private SmugMugApi smugmug;
316
private string title;
317
private ListStore category_store;
319
public SmugMugAddAlbum (SmugMugExport export, SmugMugApi smugmug)
321
xml = new Glade.XML (null, "SmugMugExport.glade", dialog_name, "f-spot");
322
xml.Autoconnect (this);
324
this.export = export;
325
this.smugmug = smugmug;
327
this.category_store = new ListStore (typeof(int), typeof(string));
328
CellRendererText display_cell = new CellRendererText();
329
category_combo.PackStart (display_cell, true);
330
category_combo.SetCellDataFunc (display_cell, new CellLayoutDataFunc (CategoryDataFunc));
331
this.category_combo.Model = category_store;
332
PopulateCategoryCombo ();
334
Dialog.Response += HandleAddResponse;
336
title_entry.Changed += HandleChanged;
337
HandleChanged (null, null);
340
private void HandleChanged (object sender, EventArgs args)
342
title = title_entry.Text;
344
if (title == String.Empty)
345
add_button.Sensitive = false;
347
add_button.Sensitive = true;
351
protected void HandleAddResponse (object sender, Gtk.ResponseArgs args)
353
if (args.ResponseId == Gtk.ResponseType.Ok) {
354
smugmug.CreateAlbum (title, CurrentCategoryId, public_check.Active);
355
export.HandleAlbumAdded (title);
360
void CategoryDataFunc (CellLayout layout, CellRenderer renderer, TreeModel model, TreeIter iter)
362
string name = (string)model.GetValue (iter, 1);
363
(renderer as CellRendererText).Text = name;
366
protected void PopulateCategoryCombo ()
368
SmugMugNet.Category[] categories = smugmug.GetCategories ();
370
foreach (SmugMugNet.Category category in categories) {
371
category_store.AppendValues (category.CategoryID, category.Title);
374
category_combo.Active = 0;
376
category_combo.ShowAll ();
379
protected int CurrentCategoryId
383
category_combo.GetActiveIter (out current);
384
return (int)category_combo.Model.GetValue (current, 0);
388
private Gtk.Dialog Dialog {
391
dialog = (Gtk.Dialog) xml.GetWidget (dialog_name);
399
public class SmugMugExport : FSpot.Extensions.IExporter {
400
public SmugMugExport ()
403
public void Run (IBrowsableCollection selection)
405
xml = new Glade.XML (null, "SmugMugExport.glade", dialog_name, "f-spot");
406
xml.Autoconnect (this);
408
this.items = selection.Items;
409
album_button.Sensitive = false;
410
FSpot.Widgets.IconView view = new FSpot.Widgets.IconView (selection);
411
view.DisplayDates = false;
412
view.DisplayTags = false;
414
Dialog.Modal = false;
415
Dialog.TransientFor = null;
416
Dialog.Close += HandleCloseEvent;
418
thumb_scrolledwindow.Add (view);
422
SmugMugAccountManager manager = SmugMugAccountManager.GetInstance ();
423
manager.AccountListChanged += PopulateSmugMugOptionMenu;
424
PopulateSmugMugOptionMenu (manager, null);
426
if (edit_button != null)
427
edit_button.Clicked += HandleEditGallery;
429
rh = new Gtk.ResponseHandler (HandleResponse);
430
Dialog.Response += HandleResponse;
432
HandleSizeActive (null, null);
435
scale_check.Toggled += HandleScaleCheckToggled;
437
LoadPreference (SCALE_KEY);
438
LoadPreference (SIZE_KEY);
439
LoadPreference (ROTATE_KEY);
440
LoadPreference (BROWSER_KEY);
443
Gtk.ResponseHandler rh;
447
private bool browser;
449
// private bool meta;
450
private bool connect = false;
452
private long approx_size = 0;
453
private long sent_bytes = 0;
455
IBrowsableItem [] items;
457
FSpot.ThreadProgressDialog progress_dialog;
460
private SmugMugAccount account;
463
private string dialog_name = "smugmug_export_dialog";
464
private Glade.XML xml;
467
private SmugMugAccountDialog gallery_add;
468
private SmugMugAddAlbum album_add;
471
[Glade.Widget] Gtk.Dialog dialog;
472
[Glade.Widget] Gtk.OptionMenu gallery_optionmenu;
473
[Glade.Widget] Gtk.OptionMenu album_optionmenu;
475
[Glade.Widget] Gtk.Label status_label;
477
[Glade.Widget] Gtk.CheckButton browser_check;
478
[Glade.Widget] Gtk.CheckButton scale_check;
479
[Glade.Widget] Gtk.CheckButton rotate_check;
481
[Glade.Widget] Gtk.SpinButton size_spin;
483
[Glade.Widget] Gtk.Button album_button;
484
[Glade.Widget] Gtk.Button edit_button;
486
[Glade.Widget] Gtk.Button export_button;
488
[Glade.Widget] Gtk.ScrolledWindow thumb_scrolledwindow;
490
System.Threading.Thread command_thread;
492
public const string EXPORT_SERVICE = "smugmug/";
493
public const string SCALE_KEY = Preferences.APP_FSPOT_EXPORT + EXPORT_SERVICE + "scale";
494
public const string SIZE_KEY = Preferences.APP_FSPOT_EXPORT + EXPORT_SERVICE + "size";
495
public const string ROTATE_KEY = Preferences.APP_FSPOT_EXPORT + EXPORT_SERVICE + "rotate";
496
public const string BROWSER_KEY = Preferences.APP_FSPOT_EXPORT + EXPORT_SERVICE + "browser";
498
private void HandleResponse (object sender, Gtk.ResponseArgs args)
500
if (args.ResponseId != Gtk.ResponseType.Ok) {
505
if (scale_check != null) {
506
scale = scale_check.Active;
507
size = size_spin.ValueAsInt;
511
browser = browser_check.Active;
512
rotate = rotate_check.Active;
513
// meta = meta_check.Active;
515
if (account != null) {
516
//System.Console.WriteLine ("history = {0}", album_optionmenu.History);
517
album = (Album) account.SmugMug.GetAlbums() [Math.Max (0, album_optionmenu.History)];
522
command_thread = new System.Threading.Thread (new System.Threading.ThreadStart (this.Upload));
523
command_thread.Name = Mono.Unix.Catalog.GetString ("Uploading Pictures");
525
progress_dialog = new FSpot.ThreadProgressDialog (command_thread, items.Length);
526
progress_dialog.Start ();
528
// Save these settings for next time
529
Preferences.Set (SCALE_KEY, scale);
530
Preferences.Set (SIZE_KEY, size);
531
Preferences.Set (ROTATE_KEY, rotate);
532
Preferences.Set (BROWSER_KEY, browser);
536
public void HandleSizeActive (object sender, EventArgs args)
538
size_spin.Sensitive = scale_check.Active;
541
private void Upload ()
546
System.Uri album_uri = null;
548
System.Console.WriteLine ("Starting Upload to Smugmug, album {0} - {1}", album.Title, album.AlbumID);
550
FilterSet filters = new FilterSet ();
551
filters.Add (new JpegFilter ());
554
filters.Add (new ResizeFilter ((uint)size));
557
filters.Add (new OrientationFilter ());
559
while (photo_index < items.Length) {
561
IBrowsableItem item = items[photo_index];
564
Console.WriteLine ("uploading {0}", photo_index);
566
progress_dialog.Message = String.Format (Catalog.GetString ("Uploading picture \"{0}\" ({1} of {2})"),
567
item.Name, photo_index+1, items.Length);
568
progress_dialog.ProgressText = string.Empty;
569
progress_dialog.Fraction = ((photo_index) / (double) items.Length);
572
FilterRequest request = new FilterRequest (item.DefaultVersionUri);
574
filters.Convert (request);
576
file_info = new FileInfo (request.Current.LocalPath);
578
if (approx_size == 0) //first image
579
approx_size = file_info.Length * items.Length;
581
approx_size = sent_bytes * items.Length / (photo_index - 1);
583
int image_id = account.SmugMug.Upload (request.Current.LocalPath, album.AlbumID);
584
if (Core.Database != null && item is Photo)
585
Core.Database.Exports.Create ((item as Photo).Id,
586
(item as Photo).DefaultVersionId,
587
ExportStore.SmugMugExportType,
588
account.SmugMug.GetAlbumUrl (image_id).ToString ());
590
sent_bytes += file_info.Length;
592
if (album_uri == null)
593
album_uri = account.SmugMug.GetAlbumUrl (image_id);
594
} catch (System.Exception e) {
595
progress_dialog.Message = String.Format (Mono.Unix.Catalog.GetString ("Error Uploading To Gallery: {0}"),
597
progress_dialog.ProgressText = Mono.Unix.Catalog.GetString ("Error");
598
System.Console.WriteLine (e);
600
if (progress_dialog.PerformRetrySkip ())
605
progress_dialog.Message = Catalog.GetString ("Done Sending Photos");
606
progress_dialog.Fraction = 1.0;
607
progress_dialog.ProgressText = Mono.Unix.Catalog.GetString ("Upload Complete");
608
progress_dialog.ButtonLabel = Gtk.Stock.Ok;
610
if (browser && album_uri != null) {
611
GnomeUtil.UrlShow (album_uri.ToString ());
615
private void HandleScaleCheckToggled (object o, EventArgs e)
617
rotate_check.Sensitive = !scale_check.Active;
620
private void PopulateSmugMugOptionMenu (SmugMugAccountManager manager, SmugMugAccount changed_account)
622
Gtk.Menu menu = new Gtk.Menu ();
623
this.account = changed_account;
626
accounts = manager.GetAccounts ();
627
if (accounts == null || accounts.Count == 0) {
628
Gtk.MenuItem item = new Gtk.MenuItem (Mono.Unix.Catalog.GetString ("(No Gallery)"));
630
gallery_optionmenu.Sensitive = false;
631
edit_button.Sensitive = false;
634
foreach (SmugMugAccount account in accounts) {
635
if (account == changed_account)
638
Gtk.MenuItem item = new Gtk.MenuItem (account.Username);
642
gallery_optionmenu.Sensitive = true;
643
edit_button.Sensitive = true;
647
gallery_optionmenu.Menu = menu;
648
gallery_optionmenu.SetHistory ((uint)pos);
651
private void Connect ()
656
private void Connect (SmugMugAccount selected)
658
Connect (selected, null);
661
private void Connect (SmugMugAccount selected, string text)
664
if (accounts.Count != 0 && connect) {
665
if (selected == null)
666
account = (SmugMugAccount) accounts [gallery_optionmenu.History];
670
if (!account.Connected)
673
PopulateAlbumOptionMenu (account.SmugMug);
675
} catch (System.Exception) {
676
System.Console.WriteLine ("Can not connect to SmugMug. Bad username ? password ? network connection ?");
677
//System.Console.WriteLine ("{0}",ex);
678
if (selected != null)
681
PopulateAlbumOptionMenu (account.SmugMug);
683
status_label.Text = String.Empty;
684
album_button.Sensitive = false;
686
new SmugMugAccountDialog (this.Dialog, account);
690
private void HandleAccountSelected (object sender, System.EventArgs args)
695
public void HandleAlbumAdded (string title) {
696
SmugMugAccount account = (SmugMugAccount) accounts [gallery_optionmenu.History];
697
PopulateAlbumOptionMenu (account.SmugMug);
699
// make the newly created album selected
700
Album[] albums = account.SmugMug.GetAlbums();
701
for (int i=0; i < albums.Length; i++) {
702
if (((Album)albums[i]).Title == title) {
703
album_optionmenu.SetHistory((uint)i);
708
private void PopulateAlbumOptionMenu (SmugMugApi smugmug)
710
Album[] albums = null;
711
if (smugmug != null) {
713
albums = smugmug.GetAlbums();
714
} catch (Exception) {
715
Console.WriteLine("Can't get the albums");
720
Gtk.Menu menu = new Gtk.Menu ();
722
bool disconnected = smugmug == null || !account.Connected || albums == null;
724
if (disconnected || albums.Length == 0) {
725
string msg = disconnected ? Mono.Unix.Catalog.GetString ("(Not Connected)")
726
: Mono.Unix.Catalog.GetString ("(No Albums)");
728
Gtk.MenuItem item = new Gtk.MenuItem (msg);
731
export_button.Sensitive = false;
732
album_optionmenu.Sensitive = false;
733
album_button.Sensitive = false;
735
foreach (Album album in albums) {
736
System.Text.StringBuilder label_builder = new System.Text.StringBuilder ();
738
label_builder.Append (album.Title);
740
Gtk.MenuItem item = new Gtk.MenuItem (label_builder.ToString ());
741
((Gtk.Label)item.Child).UseUnderline = false;
745
export_button.Sensitive = items.Length > 0;
746
album_optionmenu.Sensitive = true;
747
album_button.Sensitive = true;
751
album_optionmenu.Menu = menu;
754
public void HandleAddGallery (object sender, System.EventArgs args)
756
gallery_add = new SmugMugAccountDialog (this.Dialog);
759
public void HandleEditGallery (object sender, System.EventArgs args)
761
gallery_add = new SmugMugAccountDialog (this.Dialog, account);
764
public void HandleAddAlbum (object sender, System.EventArgs args)
767
throw new Exception (Catalog.GetString ("No account selected"));
769
album_add = new SmugMugAddAlbum (this, account.SmugMug);
772
void LoadPreference (string key)
774
object val = Preferences.Get (key);
779
//System.Console.WriteLine ("Setting {0} to {1}", key, val);
783
if (scale_check.Active != (bool) val) {
784
scale_check.Active = (bool) val;
785
rotate_check.Sensitive = !(bool) val;
790
size_spin.Value = (double) (int) val;
794
if (browser_check.Active != (bool) val)
795
browser_check.Active = (bool) val;
799
if (rotate_check.Active != (bool) val)
800
rotate_check.Active = (bool) val;
805
protected void HandleCloseEvent (object sender, System.EventArgs args)
807
account.SmugMug.Logout ();
810
private Gtk.Dialog Dialog {
813
dialog = (Gtk.Dialog) xml.GetWidget (dialog_name);