void gui_download_window_error(struct gui_download_window *dw, const char *error_msg) { os_error *error; if (dw->ctx != NULL) download_context_destroy(dw->ctx); dw->ctx = NULL; dw->error = true; schedule_remove(ro_gui_download_update_status_wrapper, dw); /* place error message in status icon in red */ strncpy(dw->status, error_msg, sizeof dw->status); error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_STATUS, wimp_COLOUR_RED << wimp_ICON_FG_COLOUR_SHIFT, wimp_ICON_FG_COLOUR); if (error) { LOG(("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } /* grey out pathname icon */ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_PATH, wimp_ICON_SHADED, 0); if (error) { LOG(("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } /* grey out file icon */ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_ICON, wimp_ICON_SHADED, wimp_ICON_SHADED); if (error) { LOG(("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } ro_gui_download_window_hide_caret(dw); }
query_id query_user_xy(const char *query, const char *detail, const query_callback *cb, void *pw, const char *yes, const char *no, int x, int y) { struct gui_query_window *qw; char query_buffer[300]; os_error *error; wimp_icon *icn; int width; int len; int tx; char *local_text = NULL; nserror err; qw = malloc(sizeof(struct gui_query_window)); if (!qw) { warn_user("NoMemory", NULL); return QUERY_INVALID; } qw->cb = cb; qw->pw = pw; qw->id = next_id++; qw->default_confirm = false; if (next_id == QUERY_INVALID) next_id++; if (!yes) yes = messages_get("Yes"); if (!no) no = messages_get("No"); /* set the text of the 'Yes' button and size accordingly */ err = utf8_to_local_encoding(yes, 0, &local_text); if (err != NSERROR_OK) { assert(err != NSERROR_BAD_ENCODING); LOG(("utf8_to_local_encoding_failed")); local_text = NULL; } icn = &query_template->icons[ICON_QUERY_YES]; len = strlen(local_text ? local_text : yes); len = max(len, icn->data.indirected_text.size - 1); memcpy(icn->data.indirected_text.text, local_text ? local_text: yes, len); icn->data.indirected_text.text[len] = '\0'; free(local_text); local_text = NULL; error = xwimptextop_string_width(icn->data.indirected_text.text, len, &width); if (error) { LOG(("xwimptextop_string_width: 0x%x:%s", error->errnum, error->errmess)); width = len * 16; } if (!query_yes_width) query_yes_width = icn->extent.x1 - icn->extent.x0; width += 44; if (width < query_yes_width) width = query_yes_width; icn->extent.x0 = tx = icn->extent.x1 - width; /* set the text of the 'No' button and size accordingly */ err = utf8_to_local_encoding(no, 0, &local_text); if (err != NSERROR_OK) { assert(err != NSERROR_BAD_ENCODING); LOG(("utf8_to_local_encoding_failed")); local_text = NULL; } icn = &query_template->icons[ICON_QUERY_NO]; len = strlen(local_text ? local_text : no); len = max(len, icn->data.indirected_text.size - 1); memcpy(icn->data.indirected_text.text, local_text ? local_text : no, len); icn->data.indirected_text.text[len] = '\0'; free(local_text); local_text = NULL; if (!query_no_width) query_no_width = icn->extent.x1 - icn->extent.x0; icn->extent.x1 = tx - 16; error = xwimptextop_string_width(icn->data.indirected_text.text, len, &width); if (error) { LOG(("xwimptextop_string_width: 0x%x:%s", error->errnum, error->errmess)); width = len * 16; } width += 28; if (width < query_no_width) width = query_no_width; icn->extent.x0 = icn->extent.x1 - width; error = xwimp_create_window(query_template, &qw->window); if (error) { warn_user("WimpError", error->errmess); free(qw); return QUERY_INVALID; } snprintf(query_buffer, sizeof query_buffer, "%s %s", messages_get(query), detail ? detail : ""); query_buffer[sizeof query_buffer - 1] = 0; ro_gui_set_icon_string(qw->window, ICON_QUERY_MESSAGE, query_buffer, true); xwimp_set_icon_state(qw->window, ICON_QUERY_HELP, wimp_ICON_DELETED, wimp_ICON_DELETED); if (x >= 0 && y >= 0) { x -= tx - 8; y += (query_template->visible.y1 - query_template->visible.y0) / 2; ro_gui_dialog_open_xy(qw->window, x, y); } else ro_gui_dialog_open(qw->window); ro_gui_wimp_event_set_user_data(qw->window, qw); ro_gui_wimp_event_register_mouse_click(qw->window, ro_gui_query_click); ro_gui_wimp_event_register_cancel(qw->window, ICON_QUERY_NO); ro_gui_wimp_event_register_ok(qw->window, ICON_QUERY_YES, ro_gui_query_apply); ro_gui_wimp_event_register_close_window(qw->window, ro_gui_query_close); error = xwimp_set_caret_position(qw->window, (wimp_i)-1, 0, 0, 1 << 25, -1); if (error) { LOG(("xwimp_get_caret_position: 0x%x : %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } /* put this query window at the head of our list */ if (gui_query_window_list) gui_query_window_list->prev = qw; qw->prev = NULL; qw->next = gui_query_window_list; gui_query_window_list = qw; return qw->id; }
nserror gui_download_window_data(struct gui_download_window *dw, const char *data, unsigned int size) { while (true) { const char *msg; int unwritten; os_error *error; error = xosgbpb_writew(dw->file, (const byte *) data, size, &unwritten); if (error) { LOG(("xosgbpb_writew: 0x%x: %s", error->errnum, error->errmess)); msg = error->errmess; } else if (unwritten) { LOG(("xosgbpb_writew: unwritten %i", unwritten)); msg = messages_get("Unwritten"); } else { dw->received += size; return NSERROR_OK; } warn_user("SaveError", msg); if (dw->saved) { /* try to continue with the temporary file */ const char *temp_name = ro_gui_download_temp_name(dw); error = ro_gui_download_move(dw, temp_name, dw->path); if (!error) { /* re-allow saving */ dw->saved = false; error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_ICON, wimp_ICON_SHADED, 0); if (error) { LOG(("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_DESTINATION, wimp_ICON_DELETED, wimp_ICON_DELETED); if (error) { LOG(("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_PATH, wimp_ICON_DELETED, 0); if (error) { LOG(("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } continue; } } /* give up then */ assert(dw->ctx); download_context_abort(dw->ctx); gui_download_window_error(dw, msg); return NSERROR_SAVE_FAILED; } }
void ro_gui_download_update_status(struct gui_download_window *dw) { char *received; char *total_size; char *speed; char time[20] = "?"; struct timeval t; float dt; unsigned int left; float rate; os_error *error; int width; char *local_status; utf8_convert_ret err; gettimeofday(&t, 0); dt = (t.tv_sec + 0.000001 * t.tv_usec) - (dw->last_time.tv_sec + 0.000001 * dw->last_time.tv_usec); if (dt == 0) dt = 0.001; total_size = human_friendly_bytesize(max(dw->received, dw->total_size)); if (dw->ctx) { rate = (dw->received - dw->last_received) / dt; received = human_friendly_bytesize(dw->received); /* A simple 'modified moving average' download rate calculation * to smooth out rate fluctuations: chosen for simplicity. */ dw->average_points++; dw->average_rate = ((dw->average_points - 1) * dw->average_rate + rate) / dw->average_points; speed = human_friendly_bytesize(dw->average_rate); if (dw->total_size) { float f; if (dw->average_rate > 0) { left = (dw->total_size - dw->received) / dw->average_rate; sprintf(time, "%u:%.2u", left / 60, left % 60); } /* convert to local encoding */ err = utf8_to_local_encoding( messages_get("Download"), 0, &local_status); if (err != UTF8_CONVERT_OK) { /* badenc should never happen */ assert(err != UTF8_CONVERT_BADENC); /* hide nomem error */ snprintf(dw->status, sizeof dw->status, messages_get("Download"), received, total_size, speed, time); } else { snprintf(dw->status, sizeof dw->status, local_status, received, total_size, speed, time); free(local_status); } f = (float) dw->received / (float) dw->total_size; width = download_progress_width * f; } else { left = t.tv_sec - dw->start_time.tv_sec; sprintf(time, "%u:%.2u", left / 60, left % 60); err = utf8_to_local_encoding( messages_get("DownloadU"), 0, &local_status); if (err != UTF8_CONVERT_OK) { /* badenc should never happen */ assert(err != UTF8_CONVERT_BADENC); /* hide nomem error */ snprintf(dw->status, sizeof dw->status, messages_get("DownloadU"), received, speed, time); } else { snprintf(dw->status, sizeof dw->status, local_status, received, speed, time); free(local_status); } /* length unknown, stay at 0 til finished */ width = 0; } } else { left = dw->last_time.tv_sec - dw->start_time.tv_sec; if (left == 0) left = 1; rate = (float) dw->received / (float) left; sprintf(time, "%u:%.2u", left / 60, left % 60); speed = human_friendly_bytesize(rate); err = utf8_to_local_encoding(messages_get("Downloaded"), 0, &local_status); if (err != UTF8_CONVERT_OK) { /* badenc should never happen */ assert(err != UTF8_CONVERT_BADENC); /* hide nomem error */ snprintf(dw->status, sizeof dw->status, messages_get("Downloaded"), total_size, speed, time); } else { snprintf(dw->status, sizeof dw->status, local_status, total_size, speed, time); free(local_status); } /* all done */ width = download_progress_width; } dw->last_time = t; dw->last_received = dw->received; error = xwimp_resize_icon(dw->window, ICON_DOWNLOAD_PROGRESS, download_progress_x0, download_progress_y0, download_progress_x0 + width, download_progress_y1); if (error) { LOG(("xwimp_resize_icon: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_STATUS, 0, 0); if (error) { LOG(("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } if (dw->ctx) schedule(100, ro_gui_download_update_status_wrapper, dw); else schedule_remove(ro_gui_download_update_status_wrapper, dw); }
bool ro_gui_download_save(struct gui_download_window *dw, const char *file_name, bool force_overwrite) { fileswitch_object_type obj_type; const char *temp_name; os_error *error; if (dw->saved || dw->error) return true; temp_name = ro_gui_download_temp_name(dw); /* does the user want to check for collisions when saving? */ if (!force_overwrite) { /* check whether the destination file/dir already exists */ error = xosfile_read_stamped(file_name, &obj_type, NULL, NULL, NULL, NULL, NULL); if (error) { LOG(("xosfile_read_stamped: 0x%x:%s", error->errnum, error->errmess)); return false; } switch (obj_type) { case osfile_NOT_FOUND: break; case osfile_IS_FILE: dw->query = query_user("OverwriteFile", NULL, &overwrite_funcs, dw, messages_get("Replace"), messages_get("DontReplace")); dw->query_rsn = QueryRsn_Overwrite; return false; default: error = xosfile_make_error(file_name, obj_type); assert(error); warn_user("SaveError", error->errmess); return false; } } if (!ro_gui_download_check_space(dw, file_name, temp_name)) { warn_user("SaveError", messages_get("NoDiscSpace")); return false; } error = ro_gui_download_move(dw, file_name, temp_name); if (error) { warn_user("SaveError", error->errmess); /* try to reopen at old location so that the download can continue to the temporary file */ error = xosfind_openupw(osfind_NO_PATH | osfind_ERROR_IF_DIR, temp_name, 0, &dw->file); if (error) { LOG(("xosfind_openupw: 0x%x: %s", error->errnum, error->errmess)); } else { error = xosargs_set_ptrw(dw->file, dw->received); if (error) { LOG(("xosargs_set_ptrw: 0x%x: %s", error->errnum, error->errmess)); } } if (error) { if (dw->ctx) download_context_abort(dw->ctx); gui_download_window_error(dw, error->errmess); } return false; } dw->saved = true; strncpy(dw->path, file_name, sizeof dw->path); if (!dw->send_dataload || dw->save_message.data.data_xfer.est_size != -1) ro_gui_download_remember_dir(file_name); /* grey out file icon */ error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_ICON, wimp_ICON_SHADED, wimp_ICON_SHADED); if (error) { LOG(("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } /* hide writeable path icon and show destination icon Note: must redraw icon bounding box because the destination icon has rounded edges on RISC OS Select/Adjust and doesn't completely cover the writeable icon */ ro_gui_force_redraw_icon(dw->window, ICON_DOWNLOAD_PATH); error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_PATH, wimp_ICON_DELETED, wimp_ICON_DELETED); if (error) { LOG(("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } error = xwimp_set_icon_state(dw->window, ICON_DOWNLOAD_DESTINATION, wimp_ICON_DELETED, 0); if (error) { LOG(("xwimp_set_icon_state: 0x%x: %s", error->errnum, error->errmess)); warn_user("WimpError", error->errmess); } ro_gui_download_window_hide_caret(dw); return true; }