~ubuntu-branches/ubuntu/feisty/elinks/feisty-updates

« back to all changes in this revision

Viewing changes to src/dialogs/download.c

  • Committer: Bazaar Package Importer
  • Author(s): Peter Gervai
  • Date: 2004-01-21 22:13:45 UTC
  • Revision ID: james.westby@ubuntu.com-20040121221345-ju33hai1yhhqt6kn
Tags: upstream-0.9.1
ImportĀ upstreamĀ versionĀ 0.9.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Download dialogs */
 
2
/* $Id: download.c,v 1.35.2.1 2004/01/17 07:57:11 miciah Exp $ */
 
3
 
 
4
#ifdef HAVE_CONFIG_H
 
5
#include "config.h"
 
6
#endif
 
7
 
 
8
#include <stdio.h>
 
9
#include <stdlib.h>
 
10
#include <string.h>
 
11
 
 
12
#include "elinks.h"
 
13
 
 
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"
 
20
#include "bfu/text.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"
 
37
 
 
38
 
 
39
static void
 
40
undisplay_download(struct file_download *file_download)
 
41
{
 
42
        if (file_download->dlg_data) cancel_dialog(file_download->dlg_data, NULL);
 
43
}
 
44
 
 
45
static void
 
46
do_abort_download(struct file_download *file_download)
 
47
{
 
48
        abort_download(file_download, 1);
 
49
}
 
50
 
 
51
static int
 
52
dlg_set_notify(struct dialog_data *dlg_data, struct widget_data *widget_data)
 
53
{
 
54
        struct file_download *file_download = dlg_data->dlg->udata;
 
55
 
 
56
        file_download->notify = 1;
 
57
        undisplay_download(file_download);
 
58
        return 0;
 
59
}
 
60
 
 
61
static int
 
62
dlg_abort_download(struct dialog_data *dlg_data, struct widget_data *widget_data)
 
63
{
 
64
        struct file_download *file_download = dlg_data->dlg->udata;
 
65
 
 
66
        object_unlock(file_download);
 
67
        register_bottom_half((void (*)(void *)) do_abort_download,
 
68
                             file_download);
 
69
        return 0;
 
70
}
 
71
 
 
72
static int
 
73
push_delete_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
 
74
{
 
75
        struct file_download *file_download = dlg_data->dlg->udata;
 
76
 
 
77
        file_download->delete = 1;
 
78
        object_unlock(file_download);
 
79
        register_bottom_half((void (*)(void *)) do_abort_download,
 
80
                             file_download);
 
81
        return 0;
 
82
}
 
83
 
 
84
static int
 
85
dlg_undisplay_download(struct dialog_data *dlg_data, struct widget_data *widget_data)
 
86
{
 
87
        struct file_download *file_download = dlg_data->dlg->udata;
 
88
 
 
89
        object_unlock(file_download);
 
90
        register_bottom_half((void (*)(void *)) undisplay_download,
 
91
                             file_download);
 
92
        return 0;
 
93
}
 
94
 
 
95
 
 
96
static void
 
97
download_abort_function(struct dialog_data *dlg_data)
 
98
{
 
99
        struct file_download *file_download = dlg_data->dlg->udata;
 
100
 
 
101
        file_download->dlg_data = NULL;
 
102
}
 
103
 
 
104
void
 
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)
 
108
{
 
109
        /* Note : values > 100% are theorically possible and were seen. */
 
110
        int progress = (int) ((longlong) 100 * current / total);
 
111
        int barprogress;
 
112
 
 
113
        /* Draw the progress meter part "[###    ]" */
 
114
        if (!text && width > 2) {
 
115
                width -= 2;
 
116
                draw_text(term, x++, y, "[", 1, 0, NULL);
 
117
                draw_text(term, x + width, y, "]", 1, 0, NULL);
 
118
        }
 
119
 
 
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);
 
123
 
 
124
        /* On error, will print '?' only, should not occur. */
 
125
        if (text) {
 
126
                width = int_min(width, strlen(text));
 
127
 
 
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;
 
132
 
 
133
                if (ulongcat(percent, &percent_len, progress, max, 0)) {
 
134
                        percent[0] = '?';
 
135
                        percent_len = 1;
 
136
                }
 
137
 
 
138
                percent[percent_len++] = '%';
 
139
 
 
140
                /* Draw the percentage centered in the progress meter */
 
141
                x += (1 + width - percent_len) / 2;
 
142
 
 
143
                assert(percent_len <= width);
 
144
                width = percent_len;
 
145
                text = percent;
 
146
        }
 
147
 
 
148
        draw_text(term, x, y, text, width, 0, NULL);
 
149
}
 
150
 
 
151
static void
 
152
download_dialog_layouter(struct dialog_data *dlg_data)
 
153
{
 
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);
 
157
        int rw = w;
 
158
        int x, y = 0;
 
159
        int url_len;
 
160
        unsigned char *url;
 
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);
 
166
 
 
167
        redraw_below_window(dlg_data->win);
 
168
        file_download->dlg_data = dlg_data;
 
169
 
 
170
        if (!msg) return;
 
171
 
 
172
        url = get_no_post_url(file_download->url, &url_len);
 
173
        if (!url) {
 
174
                mem_free(msg);
 
175
                return;
 
176
        }
 
177
 
 
178
        if (show_meter) {
 
179
                int_lower_bound(&w, DOWN_DLG_MIN);
 
180
        }
 
181
 
 
182
        dlg_format_text_do(NULL, url, 0, &y, w, &rw,
 
183
                        dialog_text_color, AL_LEFT);
 
184
 
 
185
        y++;
 
186
        if (show_meter) y += 2;
 
187
        dlg_format_text_do(NULL, msg, 0, &y, w, &rw,
 
188
                        dialog_text_color, AL_LEFT);
 
189
 
 
190
        y++;
 
191
        dlg_format_buttons(NULL, dlg_data->widgets_data, dlg_data->n, 0, &y, w,
 
192
                           &rw, AL_CENTER);
 
193
 
 
194
        draw_dialog(dlg_data, w, y);
 
195
 
 
196
        w = rw;
 
197
        if (url_len > w) {
 
198
                /* Truncate too long urls */
 
199
                url_len = w;
 
200
                url[url_len] = '\0';
 
201
                if (url_len > 4) {
 
202
                        url[--url_len] = '.';
 
203
                        url[--url_len] = '.';
 
204
                        url[--url_len] = '.';
 
205
                }
 
206
        }
 
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);
 
211
 
 
212
        if (show_meter) {
 
213
                y++;
 
214
                download_progress_bar(term, x, y, w, NULL, NULL,
 
215
                                      download->prg->pos,
 
216
                                      download->prg->size);
 
217
                y++;
 
218
        }
 
219
 
 
220
        y++;
 
221
        dlg_format_text_do(term, msg, x, &y, w, NULL,
 
222
                        dialog_text_color, AL_LEFT);
 
223
 
 
224
        y++;
 
225
        dlg_format_buttons(term, dlg_data->widgets_data, dlg_data->n, x, &y, w,
 
226
                           NULL, AL_CENTER);
 
227
 
 
228
        mem_free(url);
 
229
        mem_free(msg);
 
230
}
 
231
 
 
232
void
 
233
display_download(struct terminal *term, struct file_download *down,
 
234
                 struct session *ses)
 
235
{
 
236
        struct dialog *dlg;
 
237
 
 
238
        if (!is_in_downloads_list(down))
 
239
                return;
 
240
 
 
241
#define DOWNLOAD_WIDGETS_COUNT 4
 
242
        dlg = calloc_dialog(DOWNLOAD_WIDGETS_COUNT, 0);
 
243
        if (!dlg) return;
 
244
 
 
245
        undisplay_download(down);
 
246
        down->ses = ses;
 
247
        dlg->title = _("Download", term);
 
248
        dlg->layouter = download_dialog_layouter;
 
249
        dlg->abort = download_abort_function;
 
250
        dlg->udata = down;
 
251
 
 
252
        object_lock(down);
 
253
 
 
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);
 
258
 
 
259
        add_dlg_end(dlg, DOWNLOAD_WIDGETS_COUNT);
 
260
 
 
261
        do_dialog(term, dlg, getml(dlg, NULL));
 
262
}
 
263
 
 
264
 
 
265
/* The download manager */
 
266
 
 
267
static void
 
268
lock_file_download(struct listbox_item *item)
 
269
{
 
270
        object_lock((struct file_download *)item->udata);
 
271
}
 
272
 
 
273
static void
 
274
unlock_file_download(struct listbox_item *item)
 
275
{
 
276
        object_unlock((struct file_download *)item->udata);
 
277
}
 
278
 
 
279
static int
 
280
is_file_download_used(struct listbox_item *item)
 
281
{
 
282
        return is_object_used((struct file_download *)item->udata);
 
283
}
 
284
 
 
285
static unsigned char *
 
286
get_file_download_info(struct listbox_item *item, struct terminal *term,
 
287
                enum listbox_info listbox_info)
 
288
{
 
289
        struct file_download *file_download = item->udata;
 
290
 
 
291
        return (listbox_info == LISTBOX_URI)
 
292
                ? stracpy(file_download->url) : NULL;
 
293
}
 
294
 
 
295
static int
 
296
can_delete_file_download(struct listbox_item *item)
 
297
{
 
298
        return 1;
 
299
}
 
300
 
 
301
static void
 
302
delete_file_download(struct listbox_item *item, int last)
 
303
{
 
304
        struct file_download *file_download = item->udata;
 
305
 
 
306
        assert(!is_object_used(file_download));
 
307
 
 
308
        abort_download(file_download, 1);
 
309
}
 
310
 
 
311
static enum dlg_refresh_code
 
312
refresh_file_download(struct dialog_data *dlg_data, void *data)
 
313
{
 
314
        /* Always refresh (until we keep finished downloads) */
 
315
        return are_there_downloads() ? REFRESH_DIALOG : REFRESH_STOP;
 
316
}
 
317
 
 
318
/* TODO: Make it configurable */
 
319
#define DOWNLOAD_METER_WIDTH 15
 
320
#define DOWNLOAD_URI_PERCENTAGE 50
 
321
 
 
322
static void
 
323
draw_file_download(struct listbox_item *item, struct listbox_context *context,
 
324
                   int x, int y, int width)
 
325
{
 
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);
 
332
        int trimmedlen;
 
333
        int meter = DOWNLOAD_METER_WIDTH;
 
334
 
 
335
        /* We have nothing to work with */
 
336
        if (width < 4) return;
 
337
 
 
338
        stylename = (item == context->box->sel) ? "menu.selected"
 
339
                  : ((item->marked)             ? "menu.marked"
 
340
                                                : "menu.normal");
 
341
 
 
342
        color = get_bfu_color(context->term, stylename);
 
343
 
 
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);
 
347
        } else {
 
348
                trimmedlen = int_min(length, width - 3);
 
349
        }
 
350
 
 
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);
 
354
                trimmedlen += 3;
 
355
        }
 
356
 
 
357
        if (download->prg->size < 0
 
358
            || download->state != S_TRANS
 
359
            || !(download->prg->elapsed / 100)) {
 
360
                /* TODO: Show trimmed error message. */
 
361
                return;
 
362
        }
 
363
 
 
364
        if (!dialog_has_refresh(context->dlg_data))
 
365
                refresh_dialog(context->dlg_data, refresh_file_download, NULL);
 
366
 
 
367
        if (trimmedlen + meter >= width) return;
 
368
 
 
369
        x += width - meter;
 
370
 
 
371
        download_progress_bar(context->term, x, y, meter, NULL, NULL,
 
372
                              download->prg->pos,
 
373
                              download->prg->size);
 
374
}
 
375
 
 
376
static struct listbox_ops downloads_listbox_ops = {
 
377
        lock_file_download,
 
378
        unlock_file_download,
 
379
        is_file_download_used,
 
380
        get_file_download_info,
 
381
        can_delete_file_download,
 
382
        delete_file_download,
 
383
        draw_file_download,
 
384
};
 
385
 
 
386
 
 
387
static int
 
388
push_info_button(struct dialog_data *dlg_data, struct widget_data *button)
 
389
{
 
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;
 
394
 
 
395
        assert(ses);
 
396
 
 
397
        if (!file_download) return 0;
 
398
 
 
399
        /* Don't layer on top of the download manager */
 
400
        delete_window(dlg_data->win);
 
401
 
 
402
        display_download(term, file_download, ses);
 
403
        return 0;
 
404
}
 
405
 
 
406
 
 
407
/* TODO: Ideas for buttons .. should be pretty trivial most of it
 
408
 *
 
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
 
412
 */
 
413
static struct hierbox_browser_button download_buttons[] = {
 
414
        { N_("Info"),                   push_info_button                },
 
415
        { N_("Abort"),                  push_hierbox_delete_button      },
 
416
#if 0
 
417
        /* This requires more work to make locking work and query the user */
 
418
        { N_("Abort and delete file"),  push_delete_button              },
 
419
#endif
 
420
        { N_("Clear"),                  push_hierbox_clear_button       },
 
421
};
 
422
 
 
423
struct_hierbox_browser(
 
424
        download_browser,
 
425
        N_("Download manager"),
 
426
        download_buttons,
 
427
        &downloads_listbox_ops
 
428
);
 
429
 
 
430
void
 
431
download_manager(struct session *ses)
 
432
{
 
433
        hierbox_browser(&download_browser, ses);
 
434
}