1 # -*- coding: utf-8 -*-
3 # gPodder - A media aggregator and podcast client
4 # Copyright (c) 2005-2010 Thomas Perl and the gPodder Team
6 # gPodder is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # gPodder is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 # gpodder.gtkui.download -- Download management in GUIs (2009-08-24)
23 # Based on code from gpodder.services (thp, 2007-08-24)
28 from gpodder
import util
29 from gpodder
import download
38 class DownloadStatusModel(gtk
.ListStore
):
39 # Symbolic names for our columns, so we know what we're up to
40 C_TASK
, C_NAME
, C_URL
, C_PROGRESS
, C_PROGRESS_TEXT
, C_ICON_NAME
= range(6)
42 SEARCH_COLUMNS
= (C_NAME
, C_URL
)
45 gtk
.ListStore
.__init
__(self
, object, str, str, int, str, str)
47 # Set up stock icon IDs for tasks
48 self
._status
_ids
= collections
.defaultdict(lambda: None)
49 self
._status
_ids
[download
.DownloadTask
.DOWNLOADING
] = gtk
.STOCK_GO_DOWN
50 self
._status
_ids
[download
.DownloadTask
.DONE
] = gtk
.STOCK_APPLY
51 self
._status
_ids
[download
.DownloadTask
.FAILED
] = gtk
.STOCK_STOP
52 self
._status
_ids
[download
.DownloadTask
.CANCELLED
] = gtk
.STOCK_CANCEL
53 self
._status
_ids
[download
.DownloadTask
.PAUSED
] = gtk
.STOCK_MEDIA_PAUSE
57 if gpodder
.ui
.fremantle
:
58 self
._status
_ids
[download
.DownloadTask
.DOWNLOADING
] = ICON('email_inbox')
59 self
._status
_ids
[download
.DownloadTask
.FAILED
] = ICON('general_stop')
60 self
._status
_ids
[download
.DownloadTask
.PAUSED
] = ICON('camera_video_pause')
61 self
._status
_ids
[download
.DownloadTask
.DONE
] = ICON('general_tickmark_checked')
63 def _format_message(self
, episode
, message
, podcast
):
64 return '%s\n<small>%s - %s</small>' % (episode
, message
, podcast
)
66 def request_update(self
, iter, task
=None):
68 # Ongoing update request from UI - get task from model
69 task
= self
.get_value(iter, self
.C_TASK
)
71 # Initial update request - update non-changing fields
76 if task
.status
== task
.FAILED
:
77 status_message
= '%s: %s' % (\
78 task
.STATUS_MESSAGE
[task
.status
], \
80 elif task
.status
== task
.DOWNLOADING
:
81 status_message
= '%s (%.0f%%, %s/s)' % (\
82 task
.STATUS_MESSAGE
[task
.status
], \
84 util
.format_filesize(task
.speed
))
86 status_message
= task
.STATUS_MESSAGE
[task
.status
]
88 if task
.progress
> 0 and task
.progress
< 1:
89 current
= util
.format_filesize(task
.progress
*task
.total_size
, digits
=1)
90 total
= util
.format_filesize(task
.total_size
, digits
=1)
92 # Remove unit from current if same as in total
93 # (does: "12 MiB / 24 MiB" => "12 / 24 MiB")
94 current
= current
.split()
95 if current
[-1] == total
.split()[-1]:
97 current
= ' '.join(current
)
99 progress_message
= ' / '.join((current
, total
))
100 elif task
.total_size
> 0:
101 progress_message
= util
.format_filesize(task
.total_size
, \
104 progress_message
= ('unknown size')
107 self
.C_NAME
, self
._format
_message
(task
.markup_name
, \
108 status_message
, task
.markup_podcast_name
),
109 self
.C_PROGRESS
, 100.*task
.progress
, \
110 self
.C_PROGRESS_TEXT
, progress_message
, \
111 self
.C_ICON_NAME
, self
._status
_ids
[task
.status
])
113 def __add_new_task(self
, task
):
115 self
.request_update(iter, task
)
117 def register_task(self
, task
):
118 util
.idle_add(self
.__add
_new
_task
, task
)
120 def tell_all_tasks_to_quit(self
):
122 task
= row
[DownloadStatusModel
.C_TASK
]
124 # Pause currently-running (and queued) downloads
125 if task
.status
in (task
.QUEUED
, task
.DOWNLOADING
):
126 task
.status
= task
.PAUSED
128 # Delete cancelled and failed downloads
129 if task
.status
in (task
.CANCELLED
, task
.FAILED
):
130 task
.removed_from_list()
132 def are_downloads_in_progress(self
):
134 Returns True if there are any downloads in the
135 QUEUED or DOWNLOADING status, False otherwise.
138 task
= row
[DownloadStatusModel
.C_TASK
]
139 if task
is not None and \
140 task
.status
in (task
.DOWNLOADING
, \
146 def cancel_by_url(self
, url
):
148 task
= row
[DownloadStatusModel
.C_TASK
]
149 if task
is not None and task
.url
== url
and \
150 task
.status
in (task
.DOWNLOADING
, \
152 task
.status
= task
.CANCELLED
158 class DownloadTaskMonitor(object):
159 """A helper class that abstracts download events"""
160 def __init__(self
, episode
, on_can_resume
, on_can_pause
, on_finished
):
161 self
.episode
= episode
163 self
._on
_can
_resume
= on_can_resume
164 self
._on
_can
_pause
= on_can_pause
165 self
._on
_finished
= on_finished
167 def task_updated(self
, task
):
168 if self
.episode
.url
== task
.episode
.url
and self
._status
!= task
.status
:
169 if task
.status
in (task
.DONE
, task
.FAILED
, task
.CANCELLED
):
171 elif task
.status
== task
.PAUSED
:
172 self
._on
_can
_resume
()
173 elif task
.status
in (task
.QUEUED
, task
.DOWNLOADING
):
175 self
._status
= task
.status