2
/* $Id: download.c,v 1.35.2.1 2004/01/17 07:57:11 miciah Exp $ */
14
#include "bfu/button.h"
15
#include "bfu/dialog.h"
16
#include "bfu/hierbox.h"
17
#include "bfu/listbox.h"
18
#include "bfu/msgbox.h"
19
#include "bfu/style.h"
21
#include "dialogs/menu.h"
22
#include "dialogs/status.h"
23
#include "intl/gettext/libintl.h"
24
#include "lowlevel/select.h"
25
#include "sched/download.h"
26
#include "sched/session.h"
27
#include "terminal/draw.h"
28
#include "terminal/terminal.h"
29
#include "util/color.h"
30
#include "util/conv.h"
31
#include "util/error.h"
32
#include "util/memlist.h"
33
#include "util/memory.h"
34
#include "util/object.h"
35
#include "util/string.h"
36
#include "util/ttime.h"
40
undisplay_download(struct file_download *file_download)
42
if (file_download->dlg_data) cancel_dialog(file_download->dlg_data, NULL);
46
do_abort_download(struct file_download *file_download)
48
abort_download(file_download, 1);
52
dlg_set_notify(struct dialog_data *dlg_data, struct widget_data *widget_data)
54
struct file_download *file_download = dlg_data->dlg->udata;
56
file_download->notify = 1;
57
undisplay_download(file_download);
62
dlg_abort_download(struct dialog_data *dlg_data, struct widget_data *widget_data)
64
struct file_download *file_download = dlg_data->dlg->udata;
66
object_unlock(file_download);
67
register_bottom_half((void (*)(void *)) do_abort_download,
73
push_delete_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
75
struct file_download *file_download = dlg_data->dlg->udata;
77
file_download->delete = 1;
78
object_unlock(file_download);
79
register_bottom_half((void (*)(void *)) do_abort_download,
85
dlg_undisplay_download(struct dialog_data *dlg_data, struct widget_data *widget_data)
87
struct file_download *file_download = dlg_data->dlg->udata;
89
object_unlock(file_download);
90
register_bottom_half((void (*)(void *)) undisplay_download,
97
download_abort_function(struct dialog_data *dlg_data)
99
struct file_download *file_download = dlg_data->dlg->udata;
101
file_download->dlg_data = NULL;
105
download_progress_bar(struct terminal *term, int x, int y, int width,
106
unsigned char *text, struct color_pair *meter_color,
107
longlong current, longlong total)
109
/* Note : values > 100% are theorically possible and were seen. */
110
int progress = (int) ((longlong) 100 * current / total);
113
/* Draw the progress meter part "[### ]" */
114
if (!text && width > 2) {
116
draw_text(term, x++, y, "[", 1, 0, NULL);
117
draw_text(term, x + width, y, "]", 1, 0, NULL);
120
if (!meter_color) meter_color = get_bfu_color(term, "dialog.meter");
121
barprogress = int_min(width * progress / 100, width);
122
draw_area(term, x, y, barprogress, 1, ' ', 0, meter_color);
124
/* On error, will print '?' only, should not occur. */
126
width = int_min(width, strlen(text));
128
} else if (width > 1) {
129
static unsigned char percent[] = "????"; /* Reduce or enlarge at will. */
130
unsigned int percent_len = 0;
131
int max = int_min(sizeof(percent), width) - 1;
133
if (ulongcat(percent, &percent_len, progress, max, 0)) {
138
percent[percent_len++] = '%';
140
/* Draw the percentage centered in the progress meter */
141
x += (1 + width - percent_len) / 2;
143
assert(percent_len <= width);
148
draw_text(term, x, y, text, width, 0, NULL);
152
download_dialog_layouter(struct dialog_data *dlg_data)
154
struct file_download *file_download = dlg_data->dlg->udata;
155
struct terminal *term = dlg_data->win->term;
156
int w = dialog_max_width(term);
161
struct download *download = &file_download->download;
162
struct color_pair *dialog_text_color = get_bfu_color(term, "dialog.text");
163
unsigned char *msg = get_stat_msg(download, term, 1, 1, "\n");
164
int show_meter = (download_is_progressing(download)
165
&& download->prg->size >= 0);
167
redraw_below_window(dlg_data->win);
168
file_download->dlg_data = dlg_data;
172
url = get_no_post_url(file_download->url, &url_len);
179
int_lower_bound(&w, DOWN_DLG_MIN);
182
dlg_format_text_do(NULL, url, 0, &y, w, &rw,
183
dialog_text_color, AL_LEFT);
186
if (show_meter) y += 2;
187
dlg_format_text_do(NULL, msg, 0, &y, w, &rw,
188
dialog_text_color, AL_LEFT);
191
dlg_format_buttons(NULL, dlg_data->widgets_data, dlg_data->n, 0, &y, w,
194
draw_dialog(dlg_data, w, y);
198
/* Truncate too long urls */
202
url[--url_len] = '.';
203
url[--url_len] = '.';
204
url[--url_len] = '.';
207
y = dlg_data->y + DIALOG_TB + 1;
208
x = dlg_data->x + DIALOG_LB;
209
dlg_format_text_do(term, url, x, &y, w, NULL,
210
dialog_text_color, AL_LEFT);
214
download_progress_bar(term, x, y, w, NULL, NULL,
216
download->prg->size);
221
dlg_format_text_do(term, msg, x, &y, w, NULL,
222
dialog_text_color, AL_LEFT);
225
dlg_format_buttons(term, dlg_data->widgets_data, dlg_data->n, x, &y, w,
233
display_download(struct terminal *term, struct file_download *down,
238
if (!is_in_downloads_list(down))
241
#define DOWNLOAD_WIDGETS_COUNT 4
242
dlg = calloc_dialog(DOWNLOAD_WIDGETS_COUNT, 0);
245
undisplay_download(down);
247
dlg->title = _("Download", term);
248
dlg->layouter = download_dialog_layouter;
249
dlg->abort = download_abort_function;
254
add_dlg_button(dlg, B_ENTER | B_ESC, dlg_undisplay_download, _("Background", term), NULL);
255
add_dlg_button(dlg, B_ENTER | B_ESC, dlg_set_notify, _("Background with notify", term), NULL);
256
add_dlg_button(dlg, 0, dlg_abort_download, _("Abort", term), NULL);
257
add_dlg_button(dlg, 0, push_delete_button, _("Abort and delete file", term), NULL);
259
add_dlg_end(dlg, DOWNLOAD_WIDGETS_COUNT);
261
do_dialog(term, dlg, getml(dlg, NULL));
265
/* The download manager */
268
lock_file_download(struct listbox_item *item)
270
object_lock((struct file_download *)item->udata);
274
unlock_file_download(struct listbox_item *item)
276
object_unlock((struct file_download *)item->udata);
280
is_file_download_used(struct listbox_item *item)
282
return is_object_used((struct file_download *)item->udata);
285
static unsigned char *
286
get_file_download_info(struct listbox_item *item, struct terminal *term,
287
enum listbox_info listbox_info)
289
struct file_download *file_download = item->udata;
291
return (listbox_info == LISTBOX_URI)
292
? stracpy(file_download->url) : NULL;
296
can_delete_file_download(struct listbox_item *item)
302
delete_file_download(struct listbox_item *item, int last)
304
struct file_download *file_download = item->udata;
306
assert(!is_object_used(file_download));
308
abort_download(file_download, 1);
311
static enum dlg_refresh_code
312
refresh_file_download(struct dialog_data *dlg_data, void *data)
314
/* Always refresh (until we keep finished downloads) */
315
return are_there_downloads() ? REFRESH_DIALOG : REFRESH_STOP;
318
/* TODO: Make it configurable */
319
#define DOWNLOAD_METER_WIDTH 15
320
#define DOWNLOAD_URI_PERCENTAGE 50
323
draw_file_download(struct listbox_item *item, struct listbox_context *context,
324
int x, int y, int width)
326
struct file_download *file_download = item->udata;
327
struct download *download = &file_download->download;
328
unsigned char *stylename;
329
struct color_pair *color;
330
unsigned char *text = file_download->url;
331
int length = strlen(text);
333
int meter = DOWNLOAD_METER_WIDTH;
335
/* We have nothing to work with */
336
if (width < 4) return;
338
stylename = (item == context->box->sel) ? "menu.selected"
339
: ((item->marked) ? "menu.marked"
342
color = get_bfu_color(context->term, stylename);
344
/* Show atleast the required percentage of the URI */
345
if (length * DOWNLOAD_URI_PERCENTAGE / 100 < width - meter - 4) {
346
trimmedlen = int_min(length, width - meter - 4);
348
trimmedlen = int_min(length, width - 3);
351
draw_text(context->term, x, y, text, trimmedlen, 0, color);
352
if (trimmedlen < length) {
353
draw_text(context->term, x + trimmedlen, y, "...", 3, 0, color);
357
if (download->prg->size < 0
358
|| download->state != S_TRANS
359
|| !(download->prg->elapsed / 100)) {
360
/* TODO: Show trimmed error message. */
364
if (!dialog_has_refresh(context->dlg_data))
365
refresh_dialog(context->dlg_data, refresh_file_download, NULL);
367
if (trimmedlen + meter >= width) return;
371
download_progress_bar(context->term, x, y, meter, NULL, NULL,
373
download->prg->size);
376
static struct listbox_ops downloads_listbox_ops = {
378
unlock_file_download,
379
is_file_download_used,
380
get_file_download_info,
381
can_delete_file_download,
382
delete_file_download,
388
push_info_button(struct dialog_data *dlg_data, struct widget_data *button)
390
struct listbox_data *box = get_dlg_listbox_data(dlg_data);
391
struct terminal *term = dlg_data->win->term;
392
struct session *ses = dlg_data->dlg->udata;
393
struct file_download *file_download = box->sel ? box->sel->udata : NULL;
397
if (!file_download) return 0;
399
/* Don't layer on top of the download manager */
400
delete_window(dlg_data->win);
402
display_download(term, file_download, ses);
407
/* TODO: Ideas for buttons .. should be pretty trivial most of it
409
* - Resume or something that will use some goto like handler
410
* - Open button that can be used to set file_download->prog.
411
* - Toggle notify button
413
static struct hierbox_browser_button download_buttons[] = {
414
{ N_("Info"), push_info_button },
415
{ N_("Abort"), push_hierbox_delete_button },
417
/* This requires more work to make locking work and query the user */
418
{ N_("Abort and delete file"), push_delete_button },
420
{ N_("Clear"), push_hierbox_clear_button },
423
struct_hierbox_browser(
425
N_("Download manager"),
427
&downloads_listbox_ops
431
download_manager(struct session *ses)
433
hierbox_browser(&download_browser, ses);