13 #include "bfu/dialog.h"
14 #include "bfu/hierbox.h"
15 #include "dialogs/download.h"
16 #include "dialogs/menu.h"
17 #include "dialogs/progress.h"
18 #include "dialogs/status.h"
19 #include "intl/gettext/libintl.h"
20 #include "main/object.h"
21 #include "main/select.h"
22 #include "network/connection.h"
23 #include "network/progress.h"
24 #include "protocol/bittorrent/dialogs.h"
25 #include "protocol/protocol.h"
26 #include "protocol/uri.h"
27 #include "session/download.h"
28 #include "session/session.h"
29 #include "terminal/draw.h"
30 #include "terminal/terminal.h"
31 #include "util/color.h"
32 #include "util/conv.h"
33 #include "util/error.h"
34 #include "util/memlist.h"
35 #include "util/memory.h"
36 #include "util/string.h"
37 #include "util/time.h"
41 undisplay_download(struct file_download
*file_download
)
43 /* We are maybe called from bottom halve so check consistency */
44 if (is_in_downloads_list(file_download
) && file_download
->dlg_data
)
45 cancel_dialog(file_download
->dlg_data
, NULL
);
49 do_abort_download(struct file_download
*file_download
)
51 /* We are maybe called from bottom halve so check consistency */
52 if (is_in_downloads_list(file_download
)) {
53 file_download
->stop
= 1;
54 abort_download(file_download
);
58 static widget_handler_status_T
59 dlg_set_notify(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
61 struct file_download
*file_download
= dlg_data
->dlg
->udata
;
63 file_download
->notify
= 1;
65 if (file_download
->uri
->protocol
== PROTOCOL_BITTORRENT
)
66 set_bittorrent_notify_on_completion(&file_download
->download
,
69 undisplay_download(file_download
);
70 return EVENT_PROCESSED
;
73 static widget_handler_status_T
74 dlg_abort_download(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
76 struct file_download
*file_download
= dlg_data
->dlg
->udata
;
78 object_unlock(file_download
);
79 register_bottom_half(do_abort_download
, file_download
);
80 return EVENT_PROCESSED
;
83 static widget_handler_status_T
84 push_delete_button(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
86 struct file_download
*file_download
= dlg_data
->dlg
->udata
;
88 file_download
->delete = 1;
90 if (file_download
->uri
->protocol
== PROTOCOL_BITTORRENT
)
91 set_bittorrent_files_for_deletion(&file_download
->download
);
93 object_unlock(file_download
);
94 register_bottom_half(do_abort_download
, file_download
);
95 return EVENT_PROCESSED
;
98 static widget_handler_status_T
99 dlg_undisplay_download(struct dialog_data
*dlg_data
, struct widget_data
*widget_data
)
101 struct file_download
*file_download
= dlg_data
->dlg
->udata
;
103 object_unlock(file_download
);
104 register_bottom_half(undisplay_download
, file_download
);
105 return EVENT_PROCESSED
;
110 download_abort_function(struct dialog_data
*dlg_data
)
112 struct file_download
*file_download
= dlg_data
->dlg
->udata
;
114 file_download
->dlg_data
= NULL
;
119 download_dialog_layouter(struct dialog_data
*dlg_data
)
121 struct file_download
*file_download
= dlg_data
->dlg
->udata
;
122 struct terminal
*term
= dlg_data
->win
->term
;
123 int w
= dialog_max_width(term
);
128 struct download
*download
= &file_download
->download
;
129 struct color_pair
*dialog_text_color
= get_bfu_color(term
, "dialog.text");
130 unsigned char *msg
= get_download_msg(download
, term
, 1, 1, "\n");
131 int show_meter
= (download_is_progressing(download
)
132 && download
->progress
->size
>= 0);
133 #if CONFIG_BITTORRENT
134 int bittorrent
= (file_download
->uri
->protocol
== PROTOCOL_BITTORRENT
135 && (show_meter
|| download
->state
== S_RESUME
));
138 redraw_below_window(dlg_data
->win
);
139 file_download
->dlg_data
= dlg_data
;
143 url
= get_uri_string(file_download
->uri
, URI_PUBLIC
);
152 #endif /* CONFIG_UTF8 */
153 decode_uri_for_display(url
);
154 url_len
= strlen(url
);
157 int_lower_bound(&w
, DOWN_DLG_MIN
);
160 dlg_format_text_do(term
, url
, 0, &y
, w
, &rw
,
161 dialog_text_color
, ALIGN_LEFT
, 1);
164 if (show_meter
) y
+= 2;
166 #if CONFIG_BITTORRENT
167 if (bittorrent
) y
+= 2;
169 dlg_format_text_do(term
, msg
, 0, &y
, w
, &rw
,
170 dialog_text_color
, ALIGN_LEFT
, 1);
173 dlg_format_buttons(term
, dlg_data
->widgets_data
,
174 dlg_data
->number_of_widgets
, 0, &y
, w
,
175 &rw
, ALIGN_CENTER
, 1);
177 draw_dialog(dlg_data
, w
, y
);
181 /* Truncate too long urls */
185 url
[--url_len
] = '.';
186 url
[--url_len
] = '.';
187 url
[--url_len
] = '.';
191 y
= dlg_data
->box
.y
+ DIALOG_TB
+ 1;
192 x
= dlg_data
->box
.x
+ DIALOG_LB
;
193 dlg_format_text_do(term
, url
, x
, &y
, w
, NULL
,
194 dialog_text_color
, ALIGN_LEFT
, 0);
198 draw_progress_bar(download
->progress
, term
, x
, y
, w
, NULL
, NULL
);
202 #if CONFIG_BITTORRENT
205 draw_bittorrent_piece_progress(download
, term
, x
, y
, w
, NULL
, NULL
);
210 dlg_format_text_do(term
, msg
, x
, &y
, w
, NULL
,
211 dialog_text_color
, ALIGN_LEFT
, 0);
214 dlg_format_buttons(term
, dlg_data
->widgets_data
,
215 dlg_data
->number_of_widgets
, x
, &y
, w
,
216 NULL
, ALIGN_CENTER
, 0);
223 display_download(struct terminal
*term
, struct file_download
*file_download
,
226 /* [gettext_accelerator_context(display_download)] */
229 if (!is_in_downloads_list(file_download
))
232 #if CONFIG_BITTORRENT
233 #define DOWNLOAD_WIDGETS_COUNT 5
235 #define DOWNLOAD_WIDGETS_COUNT 4
238 dlg
= calloc_dialog(DOWNLOAD_WIDGETS_COUNT
, 0);
241 undisplay_download(file_download
);
242 file_download
->ses
= ses
;
243 dlg
->title
= _("Download", term
);
244 dlg
->layouter
= download_dialog_layouter
;
245 dlg
->abort
= download_abort_function
;
246 dlg
->udata
= file_download
;
248 object_lock(file_download
);
250 add_dlg_button(dlg
, _("~Background", term
), B_ENTER
| B_ESC
, dlg_undisplay_download
, NULL
);
251 add_dlg_button(dlg
, _("Background with ~notify", term
), B_ENTER
| B_ESC
, dlg_set_notify
, NULL
);
253 #if CONFIG_BITTORRENT
254 if (file_download
->uri
->protocol
== PROTOCOL_BITTORRENT
)
255 add_dlg_button(dlg
, _("~Info", term
), B_ENTER
| B_ESC
, dlg_show_bittorrent_info
, NULL
);
258 add_dlg_button(dlg
, _("~Abort", term
), 0, dlg_abort_download
, NULL
);
260 /* Downloads scheduled to be opened by external handlers are always
262 if (!file_download
->external_handler
) {
263 add_dlg_button(dlg
, _("Abort and ~delete file", term
), 0, push_delete_button
, NULL
);
266 #if CONFIG_BITTORRENT
267 add_dlg_end(dlg
, DOWNLOAD_WIDGETS_COUNT
- !!file_download
->external_handler
268 - (file_download
->uri
->protocol
!= PROTOCOL_BITTORRENT
));
270 add_dlg_end(dlg
, DOWNLOAD_WIDGETS_COUNT
- !!file_download
->external_handler
);
273 do_dialog(term
, dlg
, getml(dlg
, NULL
));
277 /* The download manager */
280 lock_file_download(struct listbox_item
*item
)
282 object_lock((struct file_download
*) item
->udata
);
286 unlock_file_download(struct listbox_item
*item
)
288 object_unlock((struct file_download
*) item
->udata
);
292 is_file_download_used(struct listbox_item
*item
)
294 return is_object_used((struct file_download
*) item
->udata
);
297 static unsigned char *
298 get_file_download_text(struct listbox_item
*item
, struct terminal
*term
)
300 struct file_download
*file_download
= item
->udata
;
301 unsigned char *uristring
;
303 uristring
= get_uri_string(file_download
->uri
, URI_PUBLIC
);
307 decode_uri(uristring
);
309 #endif /* CONFIG_UTF8 */
310 decode_uri_for_display(uristring
);
316 static unsigned char *
317 get_file_download_info(struct listbox_item
*item
, struct terminal
*term
)
323 get_file_download_uri(struct listbox_item
*item
)
325 struct file_download
*file_download
= item
->udata
;
327 return get_uri_reference(file_download
->uri
);
330 static struct listbox_item
*
331 get_file_download_root(struct listbox_item
*item
)
337 can_delete_file_download(struct listbox_item
*item
)
343 delete_file_download(struct listbox_item
*item
, int last
)
345 struct file_download
*file_download
= item
->udata
;
347 assert(!is_object_used(file_download
));
348 register_bottom_half(do_abort_download
, file_download
);
351 static enum dlg_refresh_code
352 refresh_file_download(struct dialog_data
*dlg_data
, void *data
)
354 /* Always refresh (until we keep finished downloads) */
355 return are_there_downloads() ? REFRESH_DIALOG
: REFRESH_STOP
;
358 /* TODO: Make it configurable */
359 #define DOWNLOAD_METER_WIDTH 15
360 #define DOWNLOAD_URI_PERCENTAGE 50
363 draw_file_download(struct listbox_item
*item
, struct listbox_context
*context
,
364 int x
, int y
, int width
)
366 struct file_download
*file_download
= item
->udata
;
367 struct download
*download
= &file_download
->download
;
368 unsigned char *stylename
;
369 struct color_pair
*color
;
373 int meter
= DOWNLOAD_METER_WIDTH
;
375 /* We have nothing to work with */
376 if (width
< 4) return;
378 stylename
= (item
== context
->box
->sel
) ? "menu.selected"
379 : ((item
->marked
) ? "menu.marked"
382 color
= get_bfu_color(context
->term
, stylename
);
384 text
= get_file_download_text(item
, context
->term
);
387 length
= strlen(text
);
388 /* Show atleast the required percentage of the URI */
389 if (length
* DOWNLOAD_URI_PERCENTAGE
/ 100 < width
- meter
- 4) {
390 trimmedlen
= int_min(length
, width
- meter
- 4);
392 trimmedlen
= int_min(length
, width
- 3);
395 draw_text(context
->term
, x
, y
, text
, trimmedlen
, 0, color
);
396 if (trimmedlen
< length
) {
397 draw_text(context
->term
, x
+ trimmedlen
, y
, "...", 3, 0, color
);
403 if (!download
->progress
404 || download
->progress
->size
< 0
405 || download
->state
!= S_TRANS
406 || !has_progress(download
->progress
)) {
407 /* TODO: Show trimmed error message. */
411 if (!dialog_has_refresh(context
->dlg_data
))
412 refresh_dialog(context
->dlg_data
, refresh_file_download
, NULL
);
414 if (trimmedlen
+ meter
>= width
) return;
418 draw_progress_bar(download
->progress
, context
->term
, x
, y
, meter
, NULL
, NULL
);
421 static struct listbox_ops_messages download_messages
= {
422 /* cant_delete_item */
423 N_("Sorry, but download \"%s\" cannot be interrupted."),
424 /* cant_delete_used_item */
425 N_("Sorry, but download \"%s\" is being used by something else."),
426 /* cant_delete_folder */
428 /* cant_delete_used_folder */
430 /* delete_marked_items_title */
431 N_("Interrupt marked downloads"),
432 /* delete_marked_items */
433 N_("Interrupt marked downloads?"),
434 /* delete_folder_title */
438 /* delete_item_title */
439 N_("Interrupt download"),
440 /* delete_item; xgettext:c-format */
441 N_("Interrupt this download?"),
442 /* clear_all_items_title */
443 N_("Interrupt all downloads"),
444 /* clear_all_items_title */
445 N_("Do you really want to interrupt all downloads?"),
448 static struct listbox_ops downloads_listbox_ops
= {
450 unlock_file_download
,
451 is_file_download_used
,
452 get_file_download_text
,
453 get_file_download_info
,
454 get_file_download_uri
,
455 get_file_download_root
,
457 can_delete_file_download
,
458 delete_file_download
,
464 static widget_handler_status_T
465 push_info_button(struct dialog_data
*dlg_data
, struct widget_data
*button
)
467 struct listbox_data
*box
= get_dlg_listbox_data(dlg_data
);
468 struct terminal
*term
= dlg_data
->win
->term
;
469 struct session
*ses
= dlg_data
->dlg
->udata
;
470 struct file_download
*file_download
= box
->sel
? box
->sel
->udata
: NULL
;
474 if (!file_download
) return EVENT_PROCESSED
;
476 /* Don't layer on top of the download manager */
477 delete_window(dlg_data
->win
);
479 display_download(term
, file_download
, ses
);
480 return EVENT_PROCESSED
;
484 /* TODO: Ideas for buttons .. should be pretty trivial most of it
486 * - Resume or something that will use some goto like handler
487 * - Open button that can be used to set file_download->prog.
488 * - Toggle notify button
490 static struct hierbox_browser_button download_buttons
[] = {
491 /* [gettext_accelerator_context(.download_buttons)] */
492 { N_("~Info"), push_info_button
},
493 { N_("~Abort"), push_hierbox_delete_button
},
495 /* This requires more work to make locking work and query the user */
496 { N_("Abort and delete file"), push_delete_button
},
498 { N_("C~lear"), push_hierbox_clear_button
},
501 static struct_hierbox_browser(
503 N_("Download manager"),
505 &downloads_listbox_ops
509 download_manager(struct session
*ses
)
511 hierbox_browser(&download_browser
, ses
);
513 /* FIXME: It's workaround for bug 397. Real fix is needed. */
514 download_browser
.do_not_save_state
= 1;
518 init_download_display(struct file_download
*file_download
)
520 file_download
->box_item
= add_listbox_leaf(&download_browser
, NULL
,
525 done_download_display(struct file_download
*file_download
)
527 if (file_download
->box_item
) {
528 done_listbox_item(&download_browser
, file_download
->box_item
);
529 file_download
->box_item
= NULL
;