[postr] Allow the creation of a new photoset in an upload session



commit f30db6b248bfd69f6682dba80e5e201b8a8d1516
Author: David Ignacio <deignacio gmail com>
Date:   Mon Dec 14 16:05:07 2009 -0300

    Allow the creation of a new photoset in an upload session
    
    Fix #507232.
    
    This patch adds another default entry in the "Add to Set" combobox
    to create a photoset w/the upload.  By default, the photoset will
    be named, "new photoset (%m-%d-%y)" but can be renamed via the
    "rename" button that appears next to it when this option is selected.
    
    If the upload is interrupted, or if the upload session is saved,
    the new photoset's name will be preserved on load.  The newly created
    photoset behaves the same way as an already existing set, in that all
    photos must be specified to the new set in order to be included.
    Only one new photoset can be created per upload.
    
    Signed-off-by: Germán Póo-Caamaño <gpoo gnome org>

 src/SetCombo.py |   72 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 src/postr.glade |   20 ++++++++++++++-
 src/postr.py    |   57 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 140 insertions(+), 9 deletions(-)
---
diff --git a/src/SetCombo.py b/src/SetCombo.py
index 968618c..553cbf3 100644
--- a/src/SetCombo.py
+++ b/src/SetCombo.py
@@ -15,9 +15,21 @@
 # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
 # St, Fifth Floor, Boston, MA 02110-1301 USA
 
+import datetime
 import gobject, gtk
 from twisted.web.client import getPage
 
+_NO_PHOTOSET_ID = "-1"
+_NO_PHOTOSET_LABEL = _("None")
+_DEFAULT_NEW_PHOTOSET_LABEL = _("Create Photoset \"%s\"")
+_DEFAULT_NEW_PHOTOSET_NAME = datetime.datetime.strftime(datetime.datetime.today(),
+                                                        _("new photoset (%m-%d-%y)"))
+
+# Column Indexes
+( COL_SETID,
+  COL_SETLABEL,
+  COL_THUMBNAIL ) = range(0, 3)
+
 class SetCombo(gtk.ComboBox):
     def __init__(self, flickr):
         gtk.ComboBox.__init__(self)
@@ -30,18 +42,21 @@ class SetCombo(gtk.ComboBox):
 
         # ID, name, thumbnail
         self.model =  gtk.ListStore (gobject.TYPE_STRING, gobject.TYPE_STRING, gtk.gdk.Pixbuf)
-        self.model.set (self.model.append(), 0, None, 1, "None")
+        self.model.set (self.model.append(),
+                        COL_SETID, None,
+                        COL_SETLABEL, _NO_PHOTOSET_LABEL)
+        self._create_new_photoset_iter()
 
         self.set_model(self.model)
         self.set_active (-1)
 
         renderer = gtk.CellRendererPixbuf()
         self.pack_start (renderer, expand=False)
-        self.set_attributes(renderer, pixbuf=2)
+        self.set_attributes(renderer, pixbuf=COL_THUMBNAIL)
         
         self.text_renderer = gtk.CellRendererText()
         self.pack_start (self.text_renderer, expand=False)
-        self.set_attributes(self.text_renderer, text=1)
+        self.set_attributes(self.text_renderer, text=COL_SETLABEL)
 
     def style_set(self, widget, old_style):
         self.thumb_size = self.text_renderer.get_size(self, None)[3]
@@ -57,7 +72,7 @@ class SetCombo(gtk.ComboBox):
         loader.set_size (self.thumb_size, self.thumb_size)
         loader.write(page)
         loader.close()
-        self.model.set (it, 2, loader.get_pixbuf())
+        self.model.set (it, COL_THUMBNAIL, loader.get_pixbuf())
     
     def __got_photosets(self, rsp):
         """Callback for the photosets.getList call"""
@@ -75,7 +90,7 @@ class SetCombo(gtk.ComboBox):
 
     def get_id_for_iter(self, it):
         if it is None: return None
-        return self.model.get(it, 0)
+        return self.model.get(it, COL_SETID)
 
     # This is needed for imports to behave correctly.  The
     #   index of the iterator on export might no longer be valid
@@ -83,8 +98,53 @@ class SetCombo(gtk.ComboBox):
     def get_iter_for_set(self, set_id):
         iter = self.model.get_iter_root()
         while iter:
-            iter_set_id = self.model.get(iter, 0)
+            iter_set_id = self.model.get(iter, COL_SETID)
             if iter_set_id[0] == set_id:
                 return iter
             iter = self.model.iter_next(iter)
         return None
+
+    def _get_new_photoset_iter(self):
+        return self.model.get_iter(1)
+
+    def _create_new_photoset_iter(self):
+        self.model.set(self.model.insert(1))
+        self.update_new_photoset("", id=_NO_PHOTOSET_ID)
+
+    def update_new_photoset(self, new_photoset_name, id=None):
+        self.new_photoset_name = new_photoset_name \
+            if new_photoset_name else _DEFAULT_NEW_PHOTOSET_NAME
+        new_set_label = _DEFAULT_NEW_PHOTOSET_LABEL % self.new_photoset_name
+        it = self._get_new_photoset_iter()
+        if id is not None:
+            self.model.set_value(it, COL_SETID, id)
+        self.model.set_value(it, COL_SETLABEL, new_set_label)
+
+    def _response_to_dialog(self, entry, dialog, response):
+        dialog.response(response)
+
+    def name_new_photoset(self):
+        dialog = gtk.MessageDialog(None,
+                                   gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+                                   gtk.MESSAGE_QUESTION,
+                                   gtk.BUTTONS_OK_CANCEL,
+                                   None)
+        dialog.set_markup(_("Name for the new photoset:"))
+        entry = gtk.Entry()
+        entry.set_text(self.new_photoset_name)
+        # so that you can press 'enter' to close dialog
+        entry.connect("activate", self._response_to_dialog, dialog, gtk.RESPONSE_OK)
+        dialog.vbox.pack_end(entry, True, True, 0)
+        dialog.show_all()
+
+        response = dialog.run()
+        dialog.destroy()
+        if response == gtk.RESPONSE_OK:
+            text = entry.get_text()
+            self.update_new_photoset(text.strip())
+        return self.new_photoset_name
+
+    def set_recently_created_photoset(self, photoset_name, photoset_id):
+        if photoset_name == self.new_photoset_name and photoset_id:
+            self.update_new_photoset(photoset_name, id=photoset_id)
+            self._create_new_photoset_iter()
diff --git a/src/postr.glade b/src/postr.glade
index 9a07319..4696f6a 100644
--- a/src/postr.glade
+++ b/src/postr.glade
@@ -392,7 +392,7 @@
               </packing>
             </child>
             <child>
-              <widget class="GtkTable" id="table1">
+              <widget class="GtkTable" id="info_table">
                 <property name="visible">True</property>
                 <property name="border_width">6</property>
                 <property name="n_rows">7</property>
@@ -725,6 +725,24 @@
                   </packing>
                 </child>
                 <child>
+                  <widget class="GtkButton" id="rename_button">
+                    <property name="visible">True</property>
+		    <property name="sensitive">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="label" translatable="yes">Rename</property>
+                    <property name="response_id">0</property>
+                    <signal name="clicked" handler="on_rename_activate"/>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">2</property>
+                    <property name="right_attach">3</property>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
                   <widget class="GtkImage" id="thumbnail_image">
                     <property name="visible">True</property>
                     <property name="yalign">0</property>
diff --git a/src/postr.py b/src/postr.py
index fdbe5ff..12bfd58 100644
--- a/src/postr.py
+++ b/src/postr.py
@@ -87,10 +87,12 @@ class Postr(UniqueApp):
                             "avatar_image",
                             "statusbar",
                             "thumbnail_image",
+                            "info_table",
                             "title_entry",
                             "desc_view",
                             "tags_entry",
                             "set_combo",
+                            "rename_button",
                             "group_selector",
                             "privacy_combo",
                             "safety_combo",
@@ -362,12 +364,31 @@ class Postr(UniqueApp):
     def on_set_combo_changed(self, combo):
         """Callback when the set combo is changed."""
         set_it = self.set_combo.get_active_iter()
+
+        (id, ) = self.set_combo.get_id_for_iter(set_it) if set_it else (None, )
+        self._update_rename_button(id)
+
         selection = self.thumbview.get_selection()
         (model, items) = selection.get_selected_rows()
         for path in items:
             it = self.model.get_iter(path)
             self.model.set_value(it, ImageStore.COL_SET, set_it)
-    
+
+    def _update_rename_button(self, id):
+        if id == '-1':
+            self.info_table.child_set(self.set_combo,
+                                      "right-attach",
+                                      2)
+            self.rename_button.set_sensitive(True)
+        else:
+            self.info_table.child_set(self.set_combo,
+                                      "right-attach",
+                                      3)
+            self.rename_button.set_sensitive(False)
+
+    def on_rename_activate(self, button):
+        self.set_combo.name_new_photoset()
+
     def on_add_photos_activate(self, widget):
         """Callback from the File->Add Photos menu item or Add button."""
         dialog = gtk.FileChooserDialog(title=_("Add Photos"), parent=self.window,
@@ -515,6 +536,7 @@ class Postr(UniqueApp):
         self.upload_button.set_sensitive(False)
         self.remove_menu.set_sensitive(False)
         self.remove_button.set_sensitive(False)
+        self.rename_button.set_sensitive(False)
         self.uploading = True
         self.thumbview.set_sensitive(False)
         self.progress_dialog.show()
@@ -897,8 +919,14 @@ class Postr(UniqueApp):
         # Lookup the set ID from the iterator
         if set_it:
             (set_id,) = self.set_combo.get_id_for_iter(set_it)
+            if set_id == '-1':
+                new_photoset_name = self.set_combo.new_photoset_name
+                set_id = 0
+            else:
+                new_photoset_name = None
         else:
             set_id = 0
+            new_photoset_name = None
 
         if privacy_it:
             (is_public, is_family, is_friend) = self.privacy_combo.get_acls_for_iter(privacy_it)
@@ -948,7 +976,26 @@ class Postr(UniqueApp):
             d.addCallback(self.add_to_groups, groups)
         if license is not None: # 0 is a valid license.
             d.addCallback(self.set_license, license)
-        d.addCallbacks(self.upload, self.upload_error)
+        # creating a new photoset has implications on subsequent uploads,
+        # so this has to finish before starting the next upload
+        if new_photoset_name:
+            d.addCallback(self.create_photoset_then_continue, new_photoset_name)
+        else:
+            d.addCallbacks(self.upload, self.upload_error)
+
+    def create_photoset_then_continue(self, rsp, photoset_name):
+        photo_id=rsp.find("photoid").text
+        create_photoset = self.flickr.photosets_create(primary_photo_id=photo_id, title=photoset_name)
+        create_photoset.addCallback(self._process_photoset_creation, photoset_name)
+        create_photoset.addErrback(self.upload_error)
+        return rsp
+
+    def _process_photoset_creation(self, create_rsp, photoset_name):
+        photoset = create_rsp.find("photoset")
+        id = photoset.get("id")
+        self.set_combo.set_recently_created_photoset(photoset_name, id)
+        self.upload(create_rsp)
+        return create_rsp
 
     def on_row_activated(self, treeview, iter, path, entry):
         """This callback is used to focus the entry title after
@@ -1020,6 +1067,9 @@ class Postr(UniqueApp):
                 if username:
                     dest["username"] = username
 
+            if self.set_combo.new_photoset_name:
+                dest["new_photoset_name"] = self.set_combo.new_photoset_name
+
             iter = self.model.get_iter_root()
             while iter:
                 path = self.model.get_string_from_iter(iter)
@@ -1143,6 +1193,9 @@ class Postr(UniqueApp):
                             should_ignore_photosets = True
                         confirm_dialog.destroy()
 
+                if source.has_key("new_photoset_name"):
+                    self.set_combo.update_new_photoset(source["new_photoset_name"])
+
                 # the model's dirty state should not be changed
                 # when loading an upload set.
                 model_was_dirty = self.model.dirty()



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