3 * io-context-gtk.c : gtk based io error context.
4 * It may be used e.g. for displaying progress and error messages
5 * before the first workbook is displayed.
8 * Jon K Hellan <hellan@acm.org>
10 * (C) 2002 Jon K Hellan
12 #include <gnumeric-config.h>
15 #include <io-context-gtk.h>
16 #include <goffice/goffice.h>
17 #include <application.h>
18 #include <libgnumeric.h>
19 #include <dialogs/dialogs.h>
22 #include <gsf/gsf-impl-utils.h>
26 #define ICG_POPUP_DELAY 3.0
28 #define IO_CONTEXT_GTK_CLASS(klass) \
29 (G_TYPE_CHECK_CLASS_CAST ((klass), GNM_TYPE_IO_CONTEXT_GTK, GnmIOContextGtk))
30 #define GNM_IS_IO_CONTEXT_GTK_CLASS(klass) \
31 (G_TYPE_CHECK_CLASS_TYPE ((klass), GNM_TYPE_IO_CONTEXT_GTK))
33 struct GnmIOContextGtk_
{
36 GtkWindow
*parent_window
;
37 GtkProgressBar
*file_bar
;
38 GtkProgressBar
*work_bar
;
50 gboolean show_warnings
;
53 struct GnmIOContextGtkClass_
{
54 GOIOContextClass parent_class
;
64 cb_icg_window_destroyed (GObject
*window
, GnmIOContextGtk
*icg
)
67 icg
->parent_window
= NULL
;
70 if (icg
->files_done
== 0) {
71 gnm_shutdown (); /* Pretend to be well behaved */
72 gnm_pre_parse_shutdown ();
73 exit (0); /* Stop pretending */
75 icg
->interrupted
= TRUE
;
79 cb_hide_splash (G_GNUC_UNUSED GtkWidget
*widget
,
80 G_GNUC_UNUSED GdkEventButton
*event
,
83 gtk_widget_hide (GTK_WIDGET (icg
->window
));
88 cb_realize (GtkWindow
*window
, void *dummy
)
92 GtkAllocation allocation
;
96 /* In a Xinerama setup, we want the geometry of the actual display
97 * unit, if available. See bug 59902. */
98 gdk_screen_get_monitor_geometry (gtk_window_get_screen (window
),
102 gtk_widget_get_allocation (GTK_WIDGET (window
), &allocation
);
104 geom
.base_width
= allocation
.width
;
105 geom
.base_height
= allocation
.height
;
106 geom
.min_width
= geom
.max_width
= geom
.base_width
;
107 geom
.min_height
= geom
.max_height
= geom
.base_height
;
109 gtk_window_move (window
,
110 sx
/ 2 - geom
.min_width
/ 2,
111 sy
/ 2 - geom
.min_height
/ 2);
112 hints
= GDK_HINT_POS
| GDK_HINT_USER_POS
|
113 GDK_HINT_BASE_SIZE
| GDK_HINT_MIN_SIZE
| GDK_HINT_MAX_SIZE
|
116 gtk_window_set_geometry_hints (window
, NULL
, &geom
, hints
);
117 gtk_window_set_decorated (window
, FALSE
);
121 icg_show_gui (GnmIOContextGtk
*icg
)
126 box
= GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0));
127 if (icg
->show_splash
)
128 gtk_box_pack_start (box
, gtk_image_new_from_resource ("/org/gnumeric/gnumeric/images/gnumeric_splash_1.4.png"),
131 /* Don't show this unless we need it. */
132 if (icg
->files_total
> 1) {
133 double f
= icg
->files_done
/ (double)icg
->files_total
;
134 icg
->file_bar
= GTK_PROGRESS_BAR
135 (g_object_new (GTK_TYPE_PROGRESS_BAR
,
141 gtk_box_pack_start (box
, GTK_WIDGET (icg
->file_bar
),
145 icg
->work_bar
= GTK_PROGRESS_BAR
146 (g_object_new (GTK_TYPE_PROGRESS_BAR
,
148 "text", icg
->progress_msg
,
150 "fraction", icg
->progress
,
152 gtk_box_pack_start (box
, GTK_WIDGET (icg
->work_bar
),
155 icg
->window
= GTK_WINDOW (gtk_window_new (GTK_WINDOW_TOPLEVEL
));
156 gtk_window_set_type_hint (GTK_WINDOW (icg
->window
),
157 GDK_WINDOW_TYPE_HINT_SPLASHSCREEN
);
158 g_signal_connect (G_OBJECT (icg
->window
),
159 "button_release_event",
160 G_CALLBACK (cb_hide_splash
), NULL
);
161 g_signal_connect (G_OBJECT (icg
->window
),
163 G_CALLBACK (cb_icg_window_destroyed
), icg
);
165 frame
= gtk_frame_new (NULL
);
166 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_OUT
);
167 gtk_container_add (GTK_CONTAINER (frame
), GTK_WIDGET (box
));
168 gtk_container_add (GTK_CONTAINER (icg
->window
), frame
);
170 g_signal_connect (G_OBJECT (icg
->window
), "realize",
171 G_CALLBACK (cb_realize
), NULL
);
173 if (icg
->parent_window
)
174 gnm_io_context_gtk_set_transient_for (icg
, icg
->parent_window
);
176 gtk_widget_show_all (GTK_WIDGET (icg
->window
));
180 icg_user_is_impatient (GnmIOContextGtk
*icg
)
182 gdouble t
= g_timer_elapsed (icg
->timer
, NULL
);
183 double progress
= icg
->progress
;
184 double forecast_delay
= ICG_POPUP_DELAY
/ 3.0;
185 gboolean ret
= FALSE
;
187 if (icg
->progress
== 0. && icg
->files_done
== 0)
190 if (t
>= forecast_delay
) {
191 if (icg
->files_total
> 1) {
192 progress
+= icg
->files_done
;
193 progress
/= icg
->files_total
;
195 if (progress
<= 0.0) {
196 /* We're likely to be back shortly. */
197 ret
= (t
> ICG_POPUP_DELAY
* 0.8);
199 double forecast
= icg
->latency
;
200 forecast
+= (t
- icg
->latency
) / progress
;
201 ret
= (forecast
> ICG_POPUP_DELAY
);
209 icg_get_password (GOCmdContext
*cc
, char const *filename
)
211 GnmIOContextGtk
*icg
= GNM_IO_CONTEXT_GTK (cc
);
212 return icg
->show_warnings
?
213 dialog_get_password (icg
->window
, filename
) : NULL
;
217 icg_progress_set (GOCmdContext
*cc
, double val
)
219 GnmIOContextGtk
*icg
= GNM_IO_CONTEXT_GTK (cc
);
221 if (!icg
->show_splash
)
224 if (icg
->window
== NULL
) {
226 if (!icg_user_is_impatient (icg
))
230 gtk_progress_bar_set_fraction (icg
->work_bar
, val
);
234 icg_progress_message_set (GOCmdContext
*cc
, gchar
const *msg
)
236 GnmIOContextGtk
*icg
= GNM_IO_CONTEXT_GTK (cc
);
238 if (!icg
->show_splash
)
241 if (icg
->window
== NULL
) {
242 if (!icg_user_is_impatient (icg
)) {
243 g_free (icg
->progress_msg
);
244 icg
->progress_msg
= g_strdup (msg
);
249 gtk_progress_bar_set_text (icg
->work_bar
, msg
);
253 icg_error_error_info (GOCmdContext
*cc
, GOErrorInfo
*error
)
255 GnmIOContextGtk
*icg
= GNM_IO_CONTEXT_GTK (cc
);
256 if (icg
->show_warnings
) {
257 GtkWidget
*dialog
= gnm_go_error_info_dialog_create (error
);
258 gtk_widget_show_all (GTK_WIDGET (dialog
));
259 gtk_dialog_run (GTK_DIALOG (dialog
));
260 gtk_widget_destroy (dialog
);
265 icg_error_error_info_list (GOCmdContext
*cc
, GSList
*error
)
267 GnmIOContextGtk
*icg
= GNM_IO_CONTEXT_GTK (cc
);
268 if (icg
->show_warnings
&& error
!= NULL
&& error
->data
!= NULL
) {
269 GtkWidget
*dialog
= gnm_go_error_info_dialog_create
271 gtk_widget_show_all (GTK_WIDGET (dialog
));
272 gtk_dialog_run (GTK_DIALOG (dialog
));
273 gtk_widget_destroy (dialog
);
278 icg_set_num_files (GOIOContext
*icg
, guint files_total
)
280 GNM_IO_CONTEXT_GTK (icg
)->files_total
= files_total
;
284 icg_processing_file (GOIOContext
*ioc
, char const *file
)
286 GnmIOContextGtk
*icg
= GNM_IO_CONTEXT_GTK (ioc
);
288 g_return_if_fail (icg
->files_done
< icg
->files_total
);
291 if (icg
->window
!= NULL
&& icg
->file_bar
!= NULL
) {
292 int len
= strlen (file
);
295 if (icg
->files_total
> 0)
296 gtk_progress_bar_set_fraction
298 icg
->files_done
/ (double)icg
->files_total
);
300 gtk_progress_bar_set_fraction (icg
->work_bar
, 0.0);
303 gtk_progress_bar_set_text (icg
->file_bar
, file
);
305 char *shown_text
= g_strdup (file
);
306 char *p
= shown_text
+ len
;
310 while (p
> shown_text
&& G_IS_DIR_SEPARATOR (p
[-1]))
312 if (p
> shown_text
&& shown_text
+ len
- p
< maxlen
) {
316 p
= g_strdup_printf ("...%s", last_p
);
317 gtk_progress_bar_set_text (icg
->file_bar
, p
);
328 icg_finalize (GObject
*obj
)
330 GnmIOContextGtk
*icg
= GNM_IO_CONTEXT_GTK (obj
);
332 gnm_io_context_gtk_discharge_splash (icg
);
333 g_free (icg
->progress_msg
);
334 G_OBJECT_CLASS (g_type_class_peek (GO_TYPE_IO_CONTEXT
))->finalize (obj
);
338 icg_set_property (GObject
*obj
, guint property_id
,
339 GValue
const *value
, GParamSpec
*pspec
)
341 GnmIOContextGtk
*icg
= GNM_IO_CONTEXT_GTK (obj
);
343 switch (property_id
) {
344 case PROP_SHOW_SPLASH
:
345 icg
->show_splash
= g_value_get_boolean (value
);
347 case PROP_SHOW_WARNINGS
:
348 icg
->show_warnings
= g_value_get_boolean (value
);
351 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj
, property_id
, pspec
);
356 icg_gnm_cmd_context_init (GOCmdContextClass
*cc_class
)
358 cc_class
->get_password
= icg_get_password
;
359 cc_class
->progress_set
= icg_progress_set
;
360 cc_class
->progress_message_set
= icg_progress_message_set
;
361 cc_class
->error
.error_info
= icg_error_error_info
;
362 cc_class
->error
.error_info_list
= icg_error_error_info_list
;
366 icg_class_init (GObjectClass
*gobj_klass
)
368 GOIOContextClass
*ioc_klass
= (GOIOContextClass
*)gobj_klass
;
370 gobj_klass
->finalize
= icg_finalize
;
371 gobj_klass
->set_property
= icg_set_property
;
373 g_object_class_install_property (gobj_klass
, PROP_SHOW_SPLASH
,
374 g_param_spec_boolean ("show-splash",
376 P_("Show a splash screen if loading takes more than a moment"),
378 GSF_PARAM_STATIC
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_WRITABLE
));
379 g_object_class_install_property (gobj_klass
, PROP_SHOW_WARNINGS
,
380 g_param_spec_boolean ("show-warnings",
382 P_("Show warning and password dialogs"),
384 GSF_PARAM_STATIC
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_WRITABLE
));
386 ioc_klass
->set_num_files
= icg_set_num_files
;
387 ioc_klass
->processing_file
= icg_processing_file
;
391 icg_init (GnmIOContextGtk
*icg
)
393 icg
->show_splash
= TRUE
;
394 icg
->show_warnings
= TRUE
;
397 icg
->work_bar
= NULL
;
398 icg
->file_bar
= NULL
;
399 icg
->files_total
= 0;
402 icg
->progress_msg
= NULL
;
404 icg
->interrupted
= FALSE
;
405 icg
->timer
= g_timer_new ();
406 g_timer_start (icg
->timer
);
409 GSF_CLASS_FULL (GnmIOContextGtk
, gnm_io_context_gtk
,
410 NULL
, NULL
, icg_class_init
, NULL
,
411 icg_init
, GO_TYPE_IO_CONTEXT
, 0,
412 GSF_INTERFACE (icg_gnm_cmd_context_init
, GO_TYPE_CMD_CONTEXT
))
415 gnm_io_context_gtk_set_transient_for (GnmIOContextGtk
*icg
, GtkWindow
*parent_window
)
417 icg
->parent_window
= parent_window
;
419 go_gtk_window_set_transient (parent_window
, icg
->window
);
423 gnm_io_context_gtk_get_interrupted (GnmIOContextGtk
*icg
)
425 return icg
->interrupted
;
429 gnm_io_context_gtk_discharge_splash (GnmIOContextGtk
*icg
)
432 g_signal_handlers_disconnect_by_func (
433 G_OBJECT (icg
->window
),
434 G_CALLBACK (cb_icg_window_destroyed
), icg
);
435 gtk_window_set_focus (icg
->window
, NULL
);
436 gtk_window_set_default (icg
->window
, NULL
);
437 gtk_widget_destroy (GTK_WIDGET (icg
->window
));
439 icg
->work_bar
= NULL
;
440 icg
->file_bar
= NULL
;
444 g_timer_destroy (icg
->timer
);