~ubuntu-branches/ubuntu/natty/miro/natty

« back to all changes in this revision

Viewing changes to portable/frontends/widgets/itemcontextmenu.py

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2011-01-22 02:46:33 UTC
  • mfrom: (1.4.10 upstream) (1.7.5 experimental)
  • Revision ID: james.westby@ubuntu.com-20110122024633-kjme8u93y2il5nmf
Tags: 3.5.1-1ubuntu1
* Merge from debian.  Remaining ubuntu changes:
  - Use python 2.7 instead of python 2.6
  - Relax dependency on python-dbus to >= 0.83.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Miro - an RSS based video player application
2
 
# Copyright (C) 2005-2010 Participatory Culture Foundation
3
 
#
4
 
# This program is free software; you can redistribute it and/or modify
5
 
# it under the terms of the GNU General Public License as published by
6
 
# the Free Software Foundation; either version 2 of the License, or
7
 
# (at your option) any later version.
8
 
#
9
 
# This program is distributed in the hope that it will be useful,
10
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
# GNU General Public License for more details.
13
 
#
14
 
# You should have received a copy of the GNU General Public License
15
 
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17
 
#
18
 
# In addition, as a special exception, the copyright holders give
19
 
# permission to link the code of portions of this program with the OpenSSL
20
 
# library.
21
 
#
22
 
# You must obey the GNU General Public License in all respects for all of
23
 
# the code used other than OpenSSL. If you modify file(s) with this
24
 
# exception, you may extend this exception to your version of the file(s),
25
 
# but you are not obligated to do so. If you do not wish to do so, delete
26
 
# this exception statement from your version. If you delete this exception
27
 
# statement from all source files in the program, then also delete it here.
28
 
 
29
 
"""itemcontextmenu.py -- Handle popping up an context menu for an item
30
 
"""
31
 
 
32
 
from miro import app
33
 
from miro import messages
34
 
from miro import prefs
35
 
from miro import config
36
 
from miro.gtcache import gettext as _
37
 
from miro.gtcache import ngettext
38
 
from miro.plat import resources
39
 
from miro.plat.frontends.widgets import file_navigator_name
40
 
 
41
 
 
42
 
class ItemContextMenuHandler(object):
43
 
    """Handles the context menus for rows in an item list."""
44
 
 
45
 
    def callback(self, tableview):
46
 
        """Callback to handle the context menu.
47
 
 
48
 
        This method can be passed into TableView.set_context_menu_callback
49
 
        """
50
 
        selected = [tableview.model[iter][0] for iter in \
51
 
                tableview.get_selection()]
52
 
        if len(selected) == 1:
53
 
            return self._make_context_menu_single(selected[0])
54
 
        else:
55
 
            return self._make_context_menu_multiple(selected)
56
 
 
57
 
    def _remove_context_menu_item(self, selection):
58
 
        """The menu item to remove the item (or None to exclude it)."""
59
 
        remove = False
60
 
        for info in selection:
61
 
            if info.is_external:
62
 
                remove = True
63
 
                break
64
 
        if remove:
65
 
            return (_('Remove From the Library'), app.widgetapp.remove_items)
66
 
        else:
67
 
            return (_('Delete'), app.widgetapp.remove_items)
68
 
 
69
 
    def _add_remove_context_menu_item(self, menu, selection):
70
 
        remove = self._remove_context_menu_item(selection)
71
 
        if remove is not None:
72
 
            menu.append(remove)
73
 
 
74
 
    def _make_context_menu_single(self, item):
75
 
        """Make the context menu for a single item."""
76
 
        # Format for the menu list:
77
 
        #
78
 
        # Each item is either None or separated into (label, callback),
79
 
        # more or less, kinda.  If it's None, it's actually a
80
 
        # separator. Otherwise..
81
 
        #
82
 
        # The label is one of two things:
83
 
        #  - A string, which is used as the label for the menu item
84
 
        #  - A tuple of (label_text, icon_path), in case you need icons
85
 
        #
86
 
        # The callback is one of three things:
87
 
        #  - None, in which case the menu item is made insensitive
88
 
        #  - A list, which means a submenu... should be in the same format
89
 
        #    as this normal menu
90
 
        #  - A method of some form.  In other words, a *real* callback :)
91
 
        if item.downloaded:
92
 
            def play_and_stop():
93
 
                app.playback_manager.start_with_items([item])
94
 
 
95
 
            def play_externally():
96
 
                app.widgetapp.open_file(item.video_path)
97
 
                messages.MarkItemWatched(item.id).send_to_backend()
98
 
 
99
 
            menu = [
100
 
                (_('Play'), app.widgetapp.play_selection),
101
 
            ]
102
 
            if config.get(prefs.PLAY_IN_MIRO):
103
 
                menu.append((_('Play Just This Item'), play_and_stop))
104
 
                menu.append((_('Play Externally'), play_externally))
105
 
            menu.append((_('Add to Playlist'), app.widgetapp.add_to_playlist))
106
 
            self._add_remove_context_menu_item(menu, [item])
107
 
            menu.append((_("Edit Item"), app.widgetapp.edit_item))
108
 
            if item.video_watched:
109
 
                menu.append((_('Mark as Unplayed'),
110
 
                    messages.MarkItemUnwatched(item.id).send_to_backend))
111
 
            else:
112
 
                menu.append((_('Mark as Played'),
113
 
                    messages.MarkItemWatched(item.id).send_to_backend))
114
 
            if item.expiration_date:
115
 
                menu.append((_('Keep'),
116
 
                    messages.KeepVideo(item.id).send_to_backend))
117
 
            if item.seeding_status == 'seeding':
118
 
                menu.append((_('Stop Seeding'), messages.StopUpload(item.id).send_to_backend))
119
 
            elif item.seeding_status == 'stopped':
120
 
                menu.append((_('Resume Seeding'), messages.StartUpload(item.id).send_to_backend))
121
 
        elif item.download_info is not None and item.download_info.state != 'failed':
122
 
            menu = [
123
 
                    (_('Cancel Download'),
124
 
                        messages.CancelDownload(item.id).send_to_backend)
125
 
            ]
126
 
            if item.download_info.state != 'paused':
127
 
                menu.append((_('Pause Download'),
128
 
                        messages.PauseDownload(item.id).send_to_backend))
129
 
            else:
130
 
                menu.append((_('Resume Download'),
131
 
                        messages.ResumeDownload(item.id).send_to_backend))
132
 
        else:
133
 
            menu = [
134
 
                (_('Download'),
135
 
                    messages.StartDownload(item.id).send_to_backend)
136
 
            ]
137
 
 
138
 
        view_menu = []
139
 
        if not item.is_external:
140
 
            view_menu.append((_('Web Page'), lambda: app.widgetapp.open_url(item.permalink)))
141
 
        if item.commentslink and item.commentslink != item.permalink:
142
 
            view_menu.append((_('Comments'), lambda: app.widgetapp.open_url(item.commentslink)))
143
 
        if item.license and item.license != item.permalink:
144
 
            view_menu.append((_('License'), lambda: app.widgetapp.open_url(item.license)))
145
 
        if item.downloaded:
146
 
            if item.file_url != item.permalink and not item.file_url.startswith('file://'):
147
 
                view_menu.append((_('File in Browser'), lambda: app.widgetapp.open_url(item.file_url)))
148
 
            if file_navigator_name:
149
 
                reveal_text = _('File in %(progname)s', {"progname": file_navigator_name})
150
 
            else:
151
 
                reveal_text = _('File on Disk')
152
 
            view_menu.append((reveal_text, lambda: app.widgetapp.check_then_reveal_file(item.video_path)))
153
 
 
154
 
        menu.append((_('View'), view_menu))
155
 
 
156
 
        if item.has_sharable_url:
157
 
            menu.append((_('Share'), lambda: app.widgetapp.share_item(item)))
158
 
 
159
 
        return menu
160
 
 
161
 
    def _make_context_menu_multiple(self, selection):
162
 
        """Make the context menu for multiple items."""
163
 
        watched = []
164
 
        unwatched = []
165
 
        downloaded = []
166
 
        downloading = []
167
 
        available = []
168
 
        paused = []
169
 
        uploadable = []
170
 
        expiring = []
171
 
        for info in selection:
172
 
            if info.downloaded:
173
 
                downloaded.append(info)
174
 
                if info.video_watched:
175
 
                    watched.append(info)
176
 
                    if info.expiration_date:
177
 
                        expiring.append(info)
178
 
                else:
179
 
                    unwatched.append(info)
180
 
            elif info.state == 'paused':
181
 
                paused.append(info)
182
 
            elif info.state == 'downloading':
183
 
                downloading.append(info)
184
 
                if (info.download_info.torrent and
185
 
                        info.download_info.state != 'uploading'):
186
 
                    uploadable.append(info)
187
 
            else:
188
 
                available.append(info)
189
 
 
190
 
        menu = []
191
 
        if downloaded:
192
 
            menu.append((ngettext('%(count)d Downloaded Item',
193
 
                                  '%(count)d Downloaded Items',
194
 
                                  len(downloaded),
195
 
                                  {"count": len(downloaded)}),
196
 
                         None))
197
 
            menu.append((_('Play'), app.widgetapp.play_selection)),
198
 
            menu.append((_('Add to Playlist'),
199
 
                app.widgetapp.add_to_playlist))
200
 
            self._add_remove_context_menu_item(menu, selection)
201
 
            if watched:
202
 
                def mark_unwatched():
203
 
                    for item in watched:
204
 
                        messages.MarkItemUnwatched(item.id).send_to_backend()
205
 
                menu.append((_('Mark as Unplayed'), mark_unwatched))
206
 
            if unwatched:
207
 
                def mark_watched():
208
 
                    for item in unwatched:
209
 
                        messages.MarkItemWatched(item.id).send_to_backend()
210
 
                menu.append((_('Mark as Played'), mark_watched))
211
 
            if expiring:
212
 
                def keep_videos():
213
 
                    for item in expiring:
214
 
                        if item.expiration_date:
215
 
                            messages.KeepVideo(item.id).send_to_backend()
216
 
                menu.append((_('Keep'), keep_videos))
217
 
 
218
 
        if available:
219
 
            if len(menu) > 0:
220
 
                menu.append(None)
221
 
            menu.append((ngettext('%(count)d Available Item',
222
 
                                  '%(count)d Available Items',
223
 
                                  len(available),
224
 
                                  {"count": len(available)}),
225
 
                         None))
226
 
            def download_all():
227
 
                for item in available:
228
 
                    messages.StartDownload(item.id).send_to_backend()
229
 
            menu.append((_('Download'), download_all))
230
 
 
231
 
        if downloading:
232
 
            if len(menu) > 0:
233
 
                menu.append(None)
234
 
            menu.append((ngettext('%(count)d Downloading Item',
235
 
                                  '%(count)d Downloading Items',
236
 
                                  len(downloading),
237
 
                                  {"count": len(downloading)}),
238
 
                         None))
239
 
            def cancel_all():
240
 
                for item in downloading:
241
 
                    messages.CancelDownload(item.id).send_to_backend()
242
 
            def pause_all():
243
 
                for item in downloading:
244
 
                    messages.PauseDownload(item.id).send_to_backend()
245
 
            menu.append((_('Cancel Download'), cancel_all))
246
 
            menu.append((_('Pause Download'), pause_all))
247
 
 
248
 
        if paused:
249
 
            if len(menu) > 0:
250
 
                menu.append(None)
251
 
            menu.append((ngettext('%(count)d Paused Item',
252
 
                                  '%(count)d Paused Items',
253
 
                                  len(paused),
254
 
                                  {"count": len(paused)}),
255
 
                         None))
256
 
            def resume_all():
257
 
                for item in paused:
258
 
                    messages.ResumeDownload(item.id).send_to_backend()
259
 
            menu.append((_('Resume Download'), resume_all))
260
 
            def cancel_all():
261
 
                for item in paused:
262
 
                    messages.CancelDownload(item.id).send_to_backend()
263
 
            menu.append((_('Cancel Download'), cancel_all))
264
 
 
265
 
        if uploadable:
266
 
            def restart_all():
267
 
                for item in uploadable:
268
 
                    messages.StartUpload(item.id).send_to_backend()
269
 
            menu.append((_('Restart Upload'), restart_all))
270
 
 
271
 
        return menu
272
 
 
273
 
class ItemContextMenuHandlerPlaylist(ItemContextMenuHandler):
274
 
    """Context menu handler for playlists."""
275
 
    def __init__(self, playlist_id):
276
 
        self.playlist_id = playlist_id
277
 
 
278
 
    def _remove_context_menu_item(self, selection):
279
 
        def do_remove():
280
 
            ids = [info.id for info in selection]
281
 
            messages.RemoveVideosFromPlaylist(self.playlist_id,
282
 
                    ids).send_to_backend()
283
 
        return (_('Remove From Playlist'), do_remove)
284
 
 
285
 
class ItemContextMenuHandlerPlaylistFolder(ItemContextMenuHandler):
286
 
    """Context menu handler for playlist folders."""
287
 
    def _remove_context_menu_item(self, selection):
288
 
        return None