/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * io-context.c : Place holder for an io error context. * It is intended to become a place to handle errors * as well as storing non-fatal warnings. * * Authors: * Jody Goldberg * Zbigniew Chyla * * (C) 2000-2002 Jody Goldberg */ #include #include "gnumeric.h" #include "io-context-priv.h" //#include "sheet.h" //#include "workbook.h" #include "command-context.h" #include "gui-util.h" #include #include #define PROGRESS_UPDATE_STEP 0.01 #define PROGRESS_UPDATE_STEP_END (1.0 / 400) #define PROGRESS_UPDATE_PERIOD_SEC 0.20 #define IOC_CLASS(ioc) IO_CONTEXT_CLASS(G_OBJECT_GET_CLASS(ioc)) static void io_context_init (IOContext *ioc) { ioc->impl = NULL; ioc->info = NULL; ioc->error_occurred = FALSE; ioc->warning_occurred = FALSE; ioc->progress_ranges = NULL; ioc->progress_min = 0.0; ioc->progress_max = 1.0; ioc->last_progress = -1.0; ioc->last_time = 0.0; ioc->helper.helper_type = GNM_PROGRESS_HELPER_NONE; } static void ioc_finalize (GObject *obj) { IOContext *ioc; g_return_if_fail (IS_IO_CONTEXT (obj)); ioc = IO_CONTEXT (obj); error_info_free (ioc->info); if (ioc->impl) { cmd_context_progress_set (ioc->impl, 0.0); cmd_context_progress_message_set (ioc->impl, NULL); g_object_unref (G_OBJECT (ioc->impl)); } G_OBJECT_CLASS (g_type_class_peek (G_TYPE_OBJECT))->finalize (obj); } static char * ioc_get_password (GnmCmdContext *cc, char const *filename) { IOContext *ioc = (IOContext *)cc; return gnm_cmd_context_get_password (ioc->impl, filename); } static void ioc_set_sensitive (GnmCmdContext *cc, gboolean sensitive) { (void)cc; (void)sensitive; } static void ioc_error_error (GnmCmdContext *cc, GError *err) { gnumeric_io_error_string (IO_CONTEXT (cc), err->message); } static void ioc_error_error_info (G_GNUC_UNUSED GnmCmdContext *ctxt, ErrorInfo *error) { /* TODO what goes here */ error_info_print (error); } void gnumeric_io_error_string (IOContext *context, const gchar *str) { ErrorInfo *error; g_return_if_fail (context != NULL); g_return_if_fail (str != NULL); error = error_info_new_str (str); gnumeric_io_error_info_set (context, error); } static void io_context_gnm_cmd_context_init (GnmCmdContextClass *cc_class) { cc_class->get_password = ioc_get_password; cc_class->set_sensitive = ioc_set_sensitive; cc_class->error.error = ioc_error_error; cc_class->error.error_info = ioc_error_error_info; } static void io_context_class_init (GObjectClass *klass) { klass->finalize = ioc_finalize; } GSF_CLASS_FULL (IOContext, io_context, io_context_class_init, io_context_init, G_TYPE_OBJECT, 0, GSF_INTERFACE (io_context_gnm_cmd_context_init, GNM_CMD_CONTEXT_TYPE)) IOContext * gnumeric_io_context_new (GnmCmdContext *cc) { IOContext *ioc; g_return_val_if_fail (IS_GNM_CMD_CONTEXT (cc), NULL); ioc = g_object_new (TYPE_IO_CONTEXT, NULL); /* The cc is optional for subclasses, but mandatory in this class. */ ioc->impl = cc; g_object_ref (G_OBJECT (ioc->impl)); return ioc; } void gnumeric_io_error_unknown (IOContext *context) { g_return_if_fail (context != NULL); context->error_occurred = TRUE; } void gnumeric_io_error_info_set (IOContext *context, ErrorInfo *error) { g_return_if_fail (context != NULL); g_return_if_fail (error != NULL); g_return_if_fail (context->info == NULL); context->info = error; context->error_occurred = TRUE; } void gnumeric_io_error_push (IOContext *context, ErrorInfo *error) { g_return_if_fail (context != NULL); g_return_if_fail (error != NULL); error_info_add_details (error, context->info); context->info = error; } void gnumeric_io_error_display (IOContext *context) { GnmCmdContext *cc; g_return_if_fail (context != NULL); if (context->info != NULL) { if (context->impl) cc = context->impl; else cc = GNM_CMD_CONTEXT (context); gnm_cmd_context_error_info (cc, context->info); } } /* TODO: Rename to gnumeric_io_info_clear */ void gnumeric_io_error_clear (IOContext *context) { g_return_if_fail (context != NULL); context->error_occurred = FALSE; context->warning_occurred = FALSE; error_info_free (context->info); context->info = NULL; } gboolean gnumeric_io_error_occurred (IOContext *context) { return context->error_occurred; } gboolean gnumeric_io_warning_occurred (IOContext *context) { return context->warning_occurred; } void io_progress_update (IOContext *ioc, gdouble f) { gboolean at_end; g_return_if_fail (IS_IO_CONTEXT (ioc)); if (ioc->progress_ranges != NULL) { f = f * (ioc->progress_max - ioc->progress_min) + ioc->progress_min; } at_end = (f - ioc->last_progress > PROGRESS_UPDATE_STEP_END && f + PROGRESS_UPDATE_STEP > 1); if (at_end || f - ioc->last_progress >= PROGRESS_UPDATE_STEP) { GTimeVal tv; double t; (void) g_get_current_time (&tv); t = tv.tv_sec + tv.tv_usec / 1000000.0; if (at_end || t - ioc->last_time >= PROGRESS_UPDATE_PERIOD_SEC) { GnmCmdContext *cc; if (ioc->impl) cc = ioc->impl; else cc = GNM_CMD_CONTEXT (ioc); cmd_context_progress_set (cc, f); ioc->last_time = t; ioc->last_progress = f; } } /* FIXME : abstract this into the workbook control */ while (gtk_events_pending ()) gtk_main_iteration_do (FALSE); } void io_progress_message (IOContext *ioc, const gchar *msg) { GnmCmdContext *cc; g_return_if_fail (IS_IO_CONTEXT (ioc)); if (ioc->impl) cc = ioc->impl; else cc = GNM_CMD_CONTEXT (ioc); cmd_context_progress_message_set (cc, msg); } void io_progress_range_push (IOContext *ioc, gdouble min, gdouble max) { ProgressRange *r; gdouble new_min, new_max; g_return_if_fail (IS_IO_CONTEXT (ioc)); r = g_new (ProgressRange, 1); r->min = min; r->max = max; ioc->progress_ranges = g_list_append (ioc->progress_ranges, r); new_min = min / (ioc->progress_max - ioc->progress_min) + ioc->progress_min; new_max = max / (ioc->progress_max - ioc->progress_min) + ioc->progress_min; ioc->progress_min = new_min; ioc->progress_max = new_max; } void io_progress_range_pop (IOContext *ioc) { GList *l; g_return_if_fail (IS_IO_CONTEXT (ioc)); g_return_if_fail (ioc->progress_ranges != NULL); l = g_list_last (ioc->progress_ranges); ioc->progress_ranges= g_list_remove_link (ioc->progress_ranges, l); g_free (l->data); g_list_free_1 (l); ioc->progress_min = 0.0; ioc->progress_max = 1.0; for (l = ioc->progress_ranges; l != NULL; l = l->next) { ProgressRange *r = l->data; gdouble new_min, new_max; new_min = r->min / (ioc->progress_max - ioc->progress_min) + ioc->progress_min; new_max = r->max / (ioc->progress_max - ioc->progress_min) + ioc->progress_min; ioc->progress_min = new_min; ioc->progress_max = new_max; } } void value_io_progress_set (IOContext *ioc, gint total, gint step) { g_return_if_fail (IS_IO_CONTEXT (ioc)); g_return_if_fail (total >= 0); ioc->helper.helper_type = GNM_PROGRESS_HELPER_VALUE; ioc->helper.v.value.total = MAX (total, 1); ioc->helper.v.value.last = -step; ioc->helper.v.value.step = step; } void value_io_progress_update (IOContext *ioc, gint value) { gdouble complete; gint step, total; g_return_if_fail (IS_IO_CONTEXT (ioc)); g_return_if_fail (ioc->helper.helper_type == GNM_PROGRESS_HELPER_VALUE); total = ioc->helper.v.value.total; step = ioc->helper.v.value.step; if (value - ioc->helper.v.value.last < step && value + step < total) { return; } ioc->helper.v.value.last = value; complete = (gdouble)value / total; io_progress_update (ioc, complete); } void count_io_progress_set (IOContext *ioc, gint total, gint step) { g_return_if_fail (IS_IO_CONTEXT (ioc)); g_return_if_fail (total >= 0); ioc->helper.helper_type = GNM_PROGRESS_HELPER_COUNT; ioc->helper.v.count.total = MAX (total, 1); ioc->helper.v.count.last = -step; ioc->helper.v.count.current = 0; ioc->helper.v.count.step = step; } void count_io_progress_update (IOContext *ioc, gint inc) { gdouble complete; gint current, step, total; g_return_if_fail (IS_IO_CONTEXT (ioc)); g_return_if_fail (ioc->helper.helper_type == GNM_PROGRESS_HELPER_COUNT); current = (ioc->helper.v.count.current += inc); step = ioc->helper.v.count.step; total = ioc->helper.v.count.total; if (current - ioc->helper.v.count.last < step && current + step < total) { return; } ioc->helper.v.count.last = current; complete = (gdouble)current / total; io_progress_update (ioc, complete); } #if 0 void workbook_io_progress_set (IOContext *ioc, Workbook const *wb, gint step) { gint n = 0; GList *sheets, *l; g_return_if_fail (IS_IO_CONTEXT (ioc)); g_return_if_fail (IS_WORKBOOK (wb)); sheets = workbook_sheets (wb); for (l = sheets; l != NULL; l = l->next) { Sheet *sheet = l->data; n += g_hash_table_size (sheet->cell_hash); } g_list_free (sheets); ioc->helper.helper_type = GNM_PROGRESS_HELPER_WORKBOOK; ioc->helper.v.workbook.n_elements = MAX (n, 1); ioc->helper.v.workbook.last = -step; ioc->helper.v.workbook.current = 0; ioc->helper.v.workbook.step = step; } void workbook_io_progress_update (IOContext *ioc, gint inc) { gdouble complete; g_return_if_fail (IS_IO_CONTEXT (ioc)); g_return_if_fail (ioc->helper.helper_type == GNM_PROGRESS_HELPER_WORKBOOK); ioc->helper.v.workbook.current += inc; if (ioc->helper.v.workbook.current - ioc->helper.v.workbook.last < ioc->helper.v.workbook.step) { return; } ioc->helper.v.workbook.last = ioc->helper.v.workbook.current; complete = 1.0 * ioc->helper.v.workbook.current / ioc->helper.v.workbook.n_elements; io_progress_update (ioc, complete); } #endif // 0 void io_progress_unset (IOContext *ioc) { g_return_if_fail (IS_IO_CONTEXT (ioc)); ioc->helper.helper_type = GNM_PROGRESS_HELPER_NONE; } void gnm_io_context_set_num_files (IOContext *ioc, guint count) { IOContextClass *klass = IOC_CLASS(ioc); g_return_if_fail (klass != NULL); if (klass->set_num_files != NULL) klass->set_num_files (ioc, count); } void gnm_io_context_processing_file (IOContext *ioc, char const *name) { IOContextClass *klass = IOC_CLASS(ioc); g_return_if_fail (klass != NULL); if (klass->processing_file != NULL) klass->processing_file (ioc, name); } void gnm_io_warning (G_GNUC_UNUSED IOContext *context, char const *fmt, ...) { va_list args; va_start (args, fmt); gnm_io_warning_varargs (context, fmt, args); va_end (args); } void gnm_io_warning_varargs (IOContext *context, char const *fmt, va_list args) { context->info = error_info_new_vprintf (GNM_WARNING, fmt, args); context->warning_occurred = TRUE; } void gnm_io_warning_unknown_font (IOContext *context, G_GNUC_UNUSED char const *font_name) { g_return_if_fail (IS_IO_CONTEXT (context)); } void gnm_io_warning_unknown_function (IOContext *context, G_GNUC_UNUSED char const *funct_name) { g_return_if_fail (IS_IO_CONTEXT (context)); } void gnm_io_warning_unsupported_feature (IOContext *context, char const *feature) { g_return_if_fail (IS_IO_CONTEXT (context)); g_warning ("%s : are not supported yet", feature); }