~ubuntu-branches/ubuntu/trusty/postr/trusty

« back to all changes in this revision

Viewing changes to src/postr.py

  • Committer: Bazaar Package Importer
  • Author(s): Nicolai Spohrer
  • Date: 2008-06-26 17:27:41 UTC
  • mfrom: (1.1.4 upstream) (5.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080626172741-3jm2i1cx3ppe81nl
Tags: 0.12.2-1ubuntu1
* Merge with Debian unstable (LP: #240191), remaining changes:
  - debian/control:
    + removed python-elementtree from Depends as it is in
       python 2.5
    + added python-nautilus to Depends
    + Modified Maintainer field as per spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Postr, a Flickr Uploader
2
2
#
3
 
# Copyright (C) 2006-2007 Ross Burton <ross@burtonini.com>
 
3
# Copyright (C) 2006-2008 Ross Burton <ross@burtonini.com>
4
4
#
5
5
# This program is free software; you can redistribute it and/or modify it under
6
6
# the terms of the GNU General Public License as published by the Free Software
20
20
from os.path import basename
21
21
 
22
22
import pygtk; pygtk.require ("2.0")
23
 
import gobject, gtk, gtk.glade
 
23
import gobject, gtk, gtk.glade, gconf
24
24
 
25
25
from AboutDialog import AboutDialog
26
26
from AuthenticationDialog import AuthenticationDialog
27
27
from ProgressDialog import ProgressDialog
28
28
from ErrorDialog import ErrorDialog
29
 
import ImageStore, ImageList, StatusBar
 
29
import ImageStore, ImageList, StatusBar, PrivacyCombo, SafetyCombo, GroupSelector
30
30
 
31
31
from flickrest import Flickr
32
32
from twisted.web.client import getPage
57
57
            self.connect("message", self.on_message)
58
58
        except AttributeError:
59
59
            pass
 
60
 
 
61
        self.is_connected = False
60
62
        
61
63
        self.flickr = Flickr(api_key="c53cebd15ed936073134cec858036f1d",
62
64
                             secret="7db1b8ef68979779",
70
72
        get_glade_widgets (glade, self,
71
73
                           ("window",
72
74
                            "upload_menu",
 
75
                            "upload_button",
73
76
                            "statusbar",
74
77
                            "thumbnail_image",
75
78
                            "title_entry",
76
 
                            "desc_entry",
 
79
                            "desc_view",
77
80
                            "tags_entry",
78
81
                            "set_combo",
 
82
                            "group_selector",
 
83
                            "privacy_combo",
 
84
                            "safety_combo",
 
85
                            "visible_check",
79
86
                            "thumbview")
80
87
                           )
 
88
        align_labels(glade, ("title_label", "desc_label", "tags_label", "set_label", "privacy_label", "safety_label"))
81
89
        
82
90
        # Just for you, Daniel.
83
91
        try:
87
95
            pass
88
96
        
89
97
        self.model = ImageStore.ImageStore ()
 
98
        self.model.connect("row-inserted", self.on_model_changed)
 
99
        self.model.connect("row-deleted", self.on_model_changed)
 
100
        
90
101
        self.thumbview.set_model(self.model)
91
102
        self.thumbview.connect("drag_data_received", self.on_drag_data_received)
92
103
 
93
104
        selection = self.thumbview.get_selection()
94
105
        selection.connect("changed", self.on_selection_changed)
95
106
 
 
107
        # TODO: remove this
96
108
        self.current_it = None
97
109
        self.last_folder = None
98
110
        self.upload_quota = None
 
111
 
 
112
        self.thumbnail_image.clear()
 
113
        self.thumbnail_image.set_size_request(128, 128)
99
114
        
100
 
        self.change_signals = []
 
115
        self.change_signals = [] # List of (widget, signal ID) tuples
101
116
        self.change_signals.append((self.title_entry, self.title_entry.connect('changed', self.on_field_changed, ImageStore.COL_TITLE)))
102
 
        self.change_signals.append((self.desc_entry, self.desc_entry.connect('changed', self.on_field_changed, ImageStore.COL_DESCRIPTION)))
 
117
        self.change_signals.append((self.desc_view.get_buffer(), self.desc_view.get_buffer().connect('changed', self.on_field_changed, ImageStore.COL_DESCRIPTION)))
103
118
        self.change_signals.append((self.tags_entry, self.tags_entry.connect('changed', self.on_field_changed, ImageStore.COL_TAGS)))
 
119
        self.change_signals.append((self.group_selector, self.group_selector.connect('changed', self.on_field_changed, ImageStore.COL_GROUPS)))
 
120
        self.change_signals.append((self.privacy_combo, self.privacy_combo.connect('changed', self.on_field_changed, ImageStore.COL_PRIVACY)))
 
121
        self.change_signals.append((self.safety_combo, self.safety_combo.connect('changed', self.on_field_changed, ImageStore.COL_SAFETY)))
 
122
        self.change_signals.append((self.visible_check, self.visible_check.connect('toggled', self.on_field_changed, ImageStore.COL_VISIBLE)))
 
123
        
104
124
        self.thumbnail_image.connect('size-allocate', self.update_thumbnail)
105
125
        self.old_thumb_allocation = None
106
 
    
 
126
 
107
127
        # The set selector combo
108
128
        self.sets = gtk.ListStore (gobject.TYPE_STRING, # ID
109
129
                                   gobject.TYPE_STRING, # Name
111
131
        self.sets.set (self.sets.append(), 0, None, 1, "None")
112
132
        self.set_combo.set_model (self.sets)
113
133
        self.set_combo.set_active (-1)
114
 
        
 
134
 
 
135
        self.on_selection_changed(selection)
 
136
 
115
137
        renderer = gtk.CellRendererPixbuf()
116
138
        self.set_combo.pack_start (renderer, expand=False)
117
139
        self.set_combo.set_attributes(renderer, pixbuf=2)
128
150
        self.progress_dialog = ProgressDialog(cancel)
129
151
        self.progress_dialog.set_transient_for(self.window)
130
152
        # Disable the Upload menu until the user has authenticated
131
 
        self.upload_menu.set_sensitive(False)
 
153
        self.update_upload()
 
154
 
 
155
        # Update the proxy configuration
 
156
        client = gconf.client_get_default()
 
157
        client.add_dir("/system/http_proxy", gconf.CLIENT_PRELOAD_RECURSIVE)
 
158
        client.notify_add("/system/http_proxy", self.proxy_changed)
 
159
        self.proxy_changed(client, 0, None, None)
132
160
        
133
161
        # Connect to flickr, go go go
134
162
        self.flickr.authenticate_1().addCallbacks(self.auth_open_url, self.twisted_error)
135
 
 
 
163
    
136
164
    def twisted_error(self, failure):
 
165
        self.update_upload()
 
166
        
137
167
        dialog = ErrorDialog(self.window)
138
168
        dialog.set_from_failure(failure)
139
 
        dialog.show()
 
169
        dialog.show_all()
 
170
 
 
171
    def proxy_changed(self, client, cnxn_id, entry, something):
 
172
        if client.get_bool("/system/http_proxy/use_http_proxy"):
 
173
            host = client.get_string("/system/http_proxy/host")
 
174
            port = client.get_int("/system/http_proxy/port")
 
175
            if host is None or host == "" or port == 0:
 
176
                self.flickr.set_proxy(None)
 
177
                return
 
178
            
 
179
            if client.get_bool("/system/http_proxy/use_authentication"):
 
180
                user = client.get_string("/system/http_proxy/authentication_user")
 
181
                password = client.get_string("/system/http_proxy/authentication_password")
 
182
                if user and user != "":
 
183
                    url = "http://%s:%s@%s:%d" % (user, password, host, port)
 
184
                else:
 
185
                    url = "http://%s:%d" % (host, port)
 
186
            else:
 
187
                url = "http://%s:%d" % (host, port)
 
188
 
 
189
            self.flickr.set_proxy(url)
 
190
        else:
 
191
            self.flickr.set_proxy(None)
140
192
    
141
193
    def get_custom_handler(self, glade, function_name, widget_name, str1, str2, int1, int2):
142
194
        """libglade callback to create custom widgets."""
143
 
        handler = getattr(self, function_name)
144
 
        return handler(str1, str2, int1, int2)
 
195
        handler = getattr(self, function_name, None)
 
196
        if handler:
 
197
            return handler(str1, str2, int1, int2)
 
198
        else:
 
199
            widget = eval(function_name)
 
200
            widget.show()
 
201
            return widget
 
202
 
 
203
    def group_selector_new (self, *args):
 
204
        w = GroupSelector.GroupSelector(self.flickr)
 
205
        w.show()
 
206
        return w
145
207
    
146
208
    def image_list_new (self, *args):
147
209
        """Custom widget creation function to make the image list."""
162
224
        else:
163
225
            return gtkunique.RESPONSE_ABORT
164
226
 
 
227
    def on_model_changed(self, *args):
 
228
        # We don't care about the arguments, because we just want to know when
 
229
        # the model was changed, not what was changed.
 
230
        self.update_upload()
 
231
    
165
232
    def auth_open_url(self, state):
166
233
        """Callback from midway through Flickr authentication.  At this point we
167
234
        either have cached tokens so can carry on, or need to open a web browser
176
243
    
177
244
    def connected(self, connected):
178
245
        """Callback when the Flickr authentication completes."""
 
246
        self.is_connected = connected
179
247
        if connected:
180
 
            self.upload_menu.set_sensitive(True)
 
248
            self.update_upload()
181
249
            self.statusbar.update_quota()
 
250
            self.group_selector.update()
182
251
            self.flickr.photosets_getList().addCallbacks(self.got_photosets, self.twisted_error)
183
252
 
 
253
    def update_upload(self):
 
254
        connected = self.is_connected and self.model.iter_n_children(None) > 0
 
255
        self.upload_menu.set_sensitive(connected)
 
256
        self.upload_button.set_sensitive(connected)
 
257
 
184
258
    def update_statusbar(self):
185
259
        """Recalculate how much is to be uploaded, and update the status bar."""
186
260
        size = 0
206
280
            url = "http://static.flickr.com/%s/%s_%s%s.jpg" % (photoset.get("server"), photoset.get("primary"), photoset.get("secret"), "_s")
207
281
            getPage (url).addCallback (self.got_set_thumb, it).addErrback(self.twisted_error)
208
282
    
209
 
    def on_field_changed(self, entry, column):
 
283
    def on_field_changed(self, widget, column):
210
284
        """Callback when the entry fields are changed."""
 
285
        if isinstance(widget, gtk.Entry) or isinstance(widget, gtk.TextBuffer):
 
286
            value = widget.get_property("text")
 
287
        elif isinstance(widget, gtk.ToggleButton):
 
288
            value = widget.get_active()
 
289
        elif isinstance(widget, gtk.ComboBox):
 
290
            value = widget.get_active_iter()
 
291
        elif isinstance(widget, GroupSelector.GroupSelector):
 
292
            value = widget.get_selected_groups()
 
293
        else:
 
294
            raise "Unhandled widget type %s" % widget
 
295
        
211
296
        selection = self.thumbview.get_selection()
212
297
        (model, items) = selection.get_selected_rows()
213
298
        for path in items:
214
299
            it = self.model.get_iter(path)
215
 
            self.model.set_value (it, column, entry.get_text())
216
 
            (title, desc, tags) = self.model.get(it,
217
 
                                                 ImageStore.COL_TITLE,
218
 
                                                 ImageStore.COL_DESCRIPTION,
219
 
                                                 ImageStore.COL_TAGS)
220
 
            self.model.set_value (it, ImageStore.COL_INFO, self.get_image_info(title, desc, tags))
 
300
            self.model.set_value (it, column, value)
221
301
 
 
302
    # TODO: remove this and use the field-changed logic
222
303
    def on_set_combo_changed(self, combo):
223
304
        """Callback when the set combo is changed."""
224
305
        set_it = self.set_combo.get_active_iter()
228
309
            it = self.model.get_iter(path)
229
310
            self.model.set_value (it, ImageStore.COL_SET, set_it)
230
311
    
231
 
    def on_add_photos_activate(self, menuitem):
232
 
        """Callback from the File->Add Photos menu item."""
 
312
    def on_add_photos_activate(self, widget):
 
313
        """Callback from the File->Add Photos menu item or Add button."""
233
314
        dialog = gtk.FileChooserDialog(title=_("Add Photos"), parent=self.window,
234
315
                                       action=gtk.FILE_CHOOSER_ACTION_OPEN,
235
316
                                       buttons=(gtk.STOCK_CANCEL,
284
365
            dialog.destroy()
285
366
            if response == gtk.RESPONSE_CANCEL:
286
367
                return True
287
 
        
 
368
        elif self.is_connected and self.model.iter_n_children(None) > 0:
 
369
            dialog = gtk.MessageDialog(type=gtk.MESSAGE_WARNING, parent=self.window)
 
370
            dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
 
371
                               gtk.STOCK_QUIT, gtk.RESPONSE_OK)
 
372
            dialog.set_markup(_('<b>Photos to be uploaded</b>'))
 
373
            dialog.format_secondary_text(_('There are photos pending to '
 
374
                                         'be uploaded. '
 
375
                                         'Are you sure you want to quit?'))
 
376
            response = dialog.run()
 
377
            dialog.destroy()
 
378
            if response == gtk.RESPONSE_CANCEL:
 
379
                return True
 
380
 
288
381
        import twisted.internet.reactor
289
382
        twisted.internet.reactor.stop()
290
383
    
291
 
    def on_remove_activate(self, menuitem):
292
 
        """Callback from File->Remove."""
 
384
    def on_remove_activate(self, widget):
 
385
        """Callback from File->Remove or Remove button."""
293
386
        selection = self.thumbview.get_selection()
294
387
        (model, items) = selection.get_selected_rows()
295
388
        
330
423
            else:
331
424
                selection.select_iter(row.iter)
332
425
 
 
426
    def on_switch_activate(self, menuitem):
 
427
        """Callback from File->Switch User."""
 
428
        self.flickr.clear_cached()
 
429
        self.flickr.authenticate_1().addCallbacks(self.auth_open_url, self.twisted_error)
 
430
    
333
431
    def on_upload_activate(self, menuitem):
334
432
        """Callback from File->Upload."""
335
433
        if self.uploading:
341
439
            print "Upload should be disabled, no photos"
342
440
            return
343
441
 
344
 
        menuitem.set_sensitive(False)
 
442
        self.upload_menu.set_sensitive(False)
 
443
        self.upload_button.set_sensitive(False)
345
444
        self.uploading = True
346
445
        self.thumbview.set_sensitive(False)
347
446
        self.progress_dialog.show()
376
475
 
377
476
            self.old_thumb_allocation = allocation
378
477
 
379
 
            (image, simage, filename) = self.model.get(self.current_it,
380
 
                                                       ImageStore.COL_IMAGE,
381
 
                                                       ImageStore.COL_PREVIEW,
382
 
                                                       ImageStore.COL_FILENAME)
383
 
 
 
478
            (simage,) = self.model.get(self.current_it, ImageStore.COL_PREVIEW)
 
479
            
384
480
            tw = allocation.width
385
481
            th = allocation.height
386
482
            # Clamp the size to 512
398
494
        preview."""
399
495
        [obj.handler_block(i) for obj,i in self.change_signals]
400
496
        
401
 
        def enable_field(field, text):
 
497
        def enable_field(field, value):
402
498
            field.set_sensitive(True)
403
 
            field.set_text(text)
 
499
            if isinstance(field, gtk.Entry):
 
500
                field.set_text(value)
 
501
            elif isinstance(field, gtk.TextView):
 
502
                field.get_buffer().set_text (value)
 
503
            elif isinstance(field, gtk.ToggleButton):
 
504
                field.set_active(value)
 
505
            elif isinstance(field, gtk.ComboBox):
 
506
                if value:
 
507
                    field.set_active_iter(value)
 
508
                else:
 
509
                    # This means the default value is always the first
 
510
                    field.set_active(0)
 
511
            elif isinstance(field, GroupSelector.GroupSelector):
 
512
                field.set_selected_groups(value)
 
513
            else:
 
514
                raise "Unhandled widget type %s" % field
404
515
        def disable_field(field):
405
516
            field.set_sensitive(False)
406
 
            field.set_text("")
 
517
            if isinstance(field, gtk.Entry):
 
518
                field.set_text("")
 
519
            elif isinstance(field, gtk.TextView):
 
520
                field.get_buffer().set_text ("")
 
521
            elif isinstance(field, gtk.ToggleButton):
 
522
                field.set_active(True)
 
523
            elif isinstance(field, gtk.ComboBox):
 
524
                field.set_active(-1)
 
525
            elif isinstance(field, GroupSelector.GroupSelector):
 
526
                field.set_selected_groups(())
 
527
            else:
 
528
                raise "Unhandled widget type %s" % field
407
529
 
408
530
        (model, items) = selection.get_selected_rows()
409
531
        
410
532
        if items:
411
533
            # TODO: do something clever with multiple selections
412
534
            self.current_it = self.model.get_iter(items[0])
413
 
            (title, desc, tags, set_it) = self.model.get(self.current_it,
414
 
                                                      ImageStore.COL_TITLE,
415
 
                                                      ImageStore.COL_DESCRIPTION,
416
 
                                                      ImageStore.COL_TAGS,
417
 
                                                      ImageStore.COL_SET)
418
 
 
 
535
            (title, desc, tags, set_it, groups, privacy_it, safety_it, visible) = self.model.get(self.current_it,
 
536
                                                                                                 ImageStore.COL_TITLE,
 
537
                                                                                                 ImageStore.COL_DESCRIPTION,
 
538
                                                                                                 ImageStore.COL_TAGS,
 
539
                                                                                                 ImageStore.COL_SET,
 
540
                                                                                                 ImageStore.COL_GROUPS,
 
541
                                                                                                 ImageStore.COL_PRIVACY,
 
542
                                                                                                 ImageStore.COL_SAFETY,
 
543
                                                                                                 ImageStore.COL_VISIBLE)
 
544
            
419
545
            enable_field(self.title_entry, title)
420
 
            enable_field(self.desc_entry, desc)
 
546
            enable_field(self.desc_view, desc)
421
547
            enable_field(self.tags_entry, tags)
422
 
            self.set_combo.set_sensitive(True)
423
 
            if (set_it):
424
 
                self.set_combo.set_active_iter(set_it)
425
 
            else:
426
 
                self.set_combo.set_active(0)
 
548
            enable_field(self.set_combo, set_it)
 
549
            enable_field(self.group_selector, groups)
 
550
            enable_field(self.privacy_combo, privacy_it)
 
551
            enable_field(self.safety_combo, safety_it)
 
552
            enable_field(self.visible_check, visible)
 
553
            
427
554
            self.update_thumbnail(self.thumbnail_image)
428
555
        else:
429
556
            self.current_it = None
430
557
            disable_field(self.title_entry)
431
 
            disable_field(self.desc_entry)
 
558
            disable_field(self.desc_view)
432
559
            disable_field(self.tags_entry)
433
 
            self.set_combo.set_sensitive(False)
434
 
            self.set_combo.set_active(-1)
 
560
            disable_field(self.set_combo)
 
561
            disable_field(self.group_selector)
 
562
            disable_field(self.privacy_combo)
 
563
            disable_field(self.safety_combo)
 
564
            disable_field(self.visible_check)
435
565
 
436
566
            self.thumbnail_image.set_from_pixbuf(None)
437
567
 
438
568
        [obj.handler_unblock(i) for obj,i in self.change_signals]
439
569
 
440
 
    def get_image_info(self, title, description, tags):
441
 
        from xml.sax.saxutils import escape
442
 
        if title:
443
 
            info_title = title
444
 
        else:
445
 
            info_title = _("No title")
446
 
 
447
 
        if description:
448
 
            info_desc = description
449
 
        else:
450
 
            info_desc = _("No description")
451
 
 
452
 
        s = "<b><big>%s</big></b>\n%s\n" % (escape (info_title), escape (info_desc))
453
 
        if tags:
454
 
            colour = self.window.style.text[gtk.STATE_INSENSITIVE].pixel
455
 
            s = s + "<span color='#%X'>%s</span>" % (colour, escape (tags))
456
 
        return s
457
 
    
458
570
    def add_image_filename(self, filename):
459
571
        """Add a file to the image list.  Called by the File->Add Photo and drag
460
572
        and drop callbacks."""
461
573
        # TODO: MIME type check
462
574
 
 
575
        # Check the file size
 
576
        filesize = os.path.getsize(filename)
 
577
        if filesize > 20 * 1024 * 1024:
 
578
            d = ErrorDialog(self.window)
 
579
            d.set_from_string("Image %s is too large, images must be no larger than 20MB in size." % filename)
 
580
            d.show_all()
 
581
            return
 
582
        
463
583
        # TODO: we open the file three times now, which is madness, especially
464
584
        # if gnome-vfs is used to read remote files.  Need to find/write EXIF
465
585
        # and IPTC parsers that are incremental.
529
649
        
530
650
        self.model.set(self.model.append(),
531
651
                       ImageStore.COL_FILENAME, filename,
532
 
                       ImageStore.COL_SIZE, os.path.getsize(filename),
 
652
                       ImageStore.COL_SIZE, filesize,
533
653
                       ImageStore.COL_IMAGE, None,
534
654
                       ImageStore.COL_PREVIEW, preview,
535
655
                       ImageStore.COL_THUMBNAIL, thumb,
536
656
                       ImageStore.COL_TITLE, title,
537
657
                       ImageStore.COL_DESCRIPTION, desc,
538
658
                       ImageStore.COL_TAGS, tags,
539
 
                       ImageStore.COL_INFO, self.get_image_info(title, desc, tags))
 
659
                       ImageStore.COL_VISIBLE, True)
540
660
 
541
661
        self.update_statusbar()
 
662
        self.update_upload()
542
663
    
543
664
    def on_drag_data_received(self, widget, context, x, y, selection, targetType, timestamp):
544
665
        """Drag and drop callback when data is received."""
554
675
            sizes = get_thumb_size (pixbuf.get_width(), pixbuf.get_height(), 64, 64)
555
676
            thumb = pixbuf.scale_simple(sizes[0], sizes[1], gtk.gdk.INTERP_BILINEAR)
556
677
 
557
 
            # TODO: Either this or the matching code in add_image_filename() is
558
 
            # wrong. Does the Flickr quota work on compressed image size, or raw
559
 
            # image data size?
 
678
            # TODO: This is wrong, and should generate a PNG here and use the
 
679
            # size of the PNG
560
680
            size = pixbuf.get_width() * pixbuf.get_height() * pixbuf.get_n_channels()
561
681
            
562
682
            self.model.set(self.model.append(),
568
688
                           ImageStore.COL_TITLE, "",
569
689
                           ImageStore.COL_DESCRIPTION, "",
570
690
                           ImageStore.COL_TAGS, "",
571
 
                           ImageStore.COL_INFO, self.get_image_info(None, None, None))
 
691
                           ImageStore.COL_VISIBLE, True)
 
692
 
572
693
        
573
694
        elif targetType == ImageList.DRAG_URI:
574
695
            for uri in selection.get_uris():
617
738
 
618
739
    def add_to_set(self, rsp, set):
619
740
        """Callback from the upload method to add the picture to a set."""
620
 
        self.flickr.photosets_addPhoto(photoset_id=set,
621
 
                                       photo_id=rsp.find("photoid").text)
622
 
        return rsp
623
 
 
624
 
    def upload_error(self, failure):
625
 
        self.twisted_error(failure)
626
 
        # TODO: nasty duplicate of the code in upload()
 
741
        photo_id=rsp.find("photoid").text
 
742
        self.flickr.photosets_addPhoto(photo_id=photo_id, photoset_id=set).addErrback(self.twisted_error)
 
743
        return rsp
 
744
 
 
745
    def add_to_groups(self, rsp, groups):
 
746
        """Callback from the upload method to add the picture to a groups."""
 
747
        photo_id=rsp.find("photoid").text
 
748
        for group in groups:
 
749
            def error(failure):
 
750
                # Code 6 means "moderated", which isn't an error
 
751
                if failure.value.code != 6:
 
752
                    twisted_error(self, failure)
 
753
            self.flickr.groups_pools_add(photo_id=photo_id, group_id=group).addErrback(error)
 
754
        return rsp
 
755
 
 
756
    def upload_done(self):
627
757
        self.cancel_upload = False
628
758
        self.window.set_title(_("Flickr Uploader"))
629
759
        self.upload_menu.set_sensitive(True)
 
760
        self.upload_button.set_sensitive(True)
630
761
        self.uploading = False
631
762
        self.progress_dialog.hide()
632
763
        self.thumbview.set_sensitive(True)
 
764
        self.update_statusbar()
633
765
        self.statusbar.update_quota()
634
766
 
 
767
    def upload_error(self, failure):
 
768
        self.twisted_error(failure)
 
769
        self.upload_done()
 
770
        
635
771
    def upload(self, response=None):
636
772
        """Upload worker function, called by the File->Upload callback.  As this
637
773
        calls itself in the deferred callback, it takes a response argument."""
643
779
        
644
780
        it = self.model.get_iter_first()
645
781
        if self.cancel_upload or it is None:
646
 
            self.cancel_upload = False
647
 
            self.window.set_title(_("Flickr Uploader"))
648
 
            self.upload_menu.set_sensitive(True)
649
 
            self.uploading = False
650
 
            self.progress_dialog.hide()
651
 
            self.thumbview.set_sensitive(True)
652
 
            self.statusbar.update_quota()
 
782
            self.upload_done()
653
783
            return
654
784
 
655
 
        (filename, thumb, pixbuf, title, desc, tags, set_it) = self.model.get(it,
656
 
                                                                              ImageStore.COL_FILENAME,
657
 
                                                                              ImageStore.COL_THUMBNAIL,
658
 
                                                                              ImageStore.COL_IMAGE,
659
 
                                                                              ImageStore.COL_TITLE,
660
 
                                                                              ImageStore.COL_DESCRIPTION,
661
 
                                                                              ImageStore.COL_TAGS,
662
 
                                                                              ImageStore.COL_SET)
 
785
        (filename, thumb, pixbuf, title, desc, tags, set_it, groups, privacy_it, safety_it, visible) = self.model.get(it,
 
786
                                                                                                                      ImageStore.COL_FILENAME,
 
787
                                                                                                                      ImageStore.COL_THUMBNAIL,
 
788
                                                                                                                      ImageStore.COL_IMAGE,
 
789
                                                                                                                      ImageStore.COL_TITLE,
 
790
                                                                                                                      ImageStore.COL_DESCRIPTION,
 
791
                                                                                                                      ImageStore.COL_TAGS,
 
792
                                                                                                                      ImageStore.COL_SET,
 
793
                                                                                                                      ImageStore.COL_GROUPS,
 
794
                                                                                                                      ImageStore.COL_PRIVACY,
 
795
                                                                                                                      ImageStore.COL_SAFETY,
 
796
                                                                                                                      ImageStore.COL_VISIBLE)
663
797
        # Lookup the set ID from the iterator
664
798
        if set_it:
665
799
            (set_id,) = self.sets.get (set_it, 0)
666
800
        else:
667
801
            set_id = 0
668
 
        
 
802
 
 
803
        if privacy_it:
 
804
            (is_public, is_family, is_friend) = self.privacy_combo.get_acls_for_iter(privacy_it)
 
805
        else:
 
806
            is_public = is_family = is_friend = None
 
807
 
 
808
        if safety_it:
 
809
            safety = self.safety_combo.get_safety_for_iter(safety_it)
 
810
        else:
 
811
            safety = None
 
812
 
669
813
        self.update_progress(filename, title, thumb)
670
814
        self.upload_index += 1
671
815
        self.current_upload_it = it
672
816
        
673
817
        if filename:
674
818
            d = self.flickr.upload(filename=filename,
675
 
                               title=title, desc=desc,
676
 
                               tags=tags)
677
 
            if set_id:
678
 
                d.addCallback(self.add_to_set, set_id)
679
 
            d.addCallbacks(self.upload, self.upload_error)
 
819
                                   title=title, desc=desc,
 
820
                                   tags=tags, search_hidden=not visible, safety=safety,
 
821
                                   is_public=is_public, is_family=is_family, is_friend=is_friend)
680
822
        elif pixbuf:
681
823
            # This isn't very nice, but might be the best way
682
824
            data = []
683
825
            pixbuf.save_to_callback(lambda d: data.append(d), "png", {})
684
826
            d = self.flickr.upload(imageData=''.join(data),
685
 
                                title=title, desc=desc,
686
 
                                tags=tags)
687
 
            if set_id:
688
 
                d.addCallback(self.add_to_set, set_id)
689
 
            d.addCallbacks(self.upload, self.upload_error)
 
827
                                   title=title, desc=desc, tags=tags,
 
828
                                   search_hidden=not visible, safety=safety,
 
829
                                   is_public=is_public, is_family=is_family, is_friend=is_friend)
690
830
        else:
691
831
            print "No filename or pixbuf stored"
 
832
 
 
833
        if set_id:
 
834
            d.addCallback(self.add_to_set, set_id)
 
835
        if groups:
 
836
            d.addCallback(self.add_to_groups, groups)
 
837
        d.addCallbacks(self.upload, self.upload_error)