1 /********************************************************************\
2  * dialog-progress.c -- GnuCash progress dialog                     *
3  * Copyright (C) 2000 Dave Peticolas                                *
4  *                                                                  *
5  * This program is free software; you can redistribute it and/or    *
6  * modify it under the terms of the GNU General Public License as   *
7  * published by the Free Software Foundation; either version 2 of   *
8  * the License, or (at your option) any later version.              *
9  *                                                                  *
10  * This program is distributed in the hope that it will be useful,  *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
13  * GNU General Public License for more details.                     *
14  *                                                                  *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, contact:                        *
17  *                                                                  *
18  * Free Software Foundation           Voice:  +1-617-542-5942       *
19  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
20  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
21  *                                                                  *
22 \********************************************************************/
23 
24 #include <config.h>
25 
26 #include <gtk/gtk.h>
27 #include <glib/gi18n.h>
28 #include <libguile.h>
29 #include "guile-mappings.h"
30 
31 #include "dialog-progress.h"
32 #include "dialog-utils.h"
33 
34 
35 struct _GNCProgressDialog
36 {
37     GtkWidget *dialog;
38 
39     GtkWidget *primary_label;
40     GtkWidget *secondary_label;
41     GtkWidget *progress_bar;
42     GtkWidget *sub_label;
43     GtkWidget *log;
44 
45     GtkWidget *ok_button;
46     GtkWidget *cancel_button;
47 
48     /* The stack of virtual progress bars. */
49     GList     *bars;
50     /* The fraction of the current bar that is filled. */
51     gdouble    bar_value;
52     /* The value of the real (top-level) bar before the last push. */
53     gdouble    total_offset;
54     /* The product of all weights in the stack. */
55     gdouble    total_weight;
56 
57     GNCProgressCancelFunc cancel_func;
58     gpointer user_data;
59 
60     SCM cancel_scm_func;
61 
62     gboolean use_ok_button;
63     gboolean closed;
64     gboolean finished;
65     gboolean destroyed;
66     gboolean title_set;
67 };
68 
69 typedef struct
70 {
71     gdouble offset;
72     gdouble weight;
73 } VirtualBar;
74 
75 static void
gnc_progress_maybe_destroy(GNCProgressDialog * progress)76 gnc_progress_maybe_destroy(GNCProgressDialog *progress)
77 {
78     g_return_if_fail(progress);
79 
80     if (!(progress->closed && progress->destroyed))
81         return;
82 
83     if (progress->dialog != NULL)
84         gtk_widget_destroy(progress->dialog);
85 }
86 
87 
88 static void
ok_cb(GtkWidget * widget,gpointer data)89 ok_cb(GtkWidget * widget, gpointer data)
90 {
91     GNCProgressDialog *progress = data;
92 
93     g_return_if_fail(progress);
94 
95     if (progress->dialog != NULL)
96         gtk_widget_hide(progress->dialog);
97     progress->closed = TRUE;
98     gnc_progress_maybe_destroy(progress);
99 }
100 
101 
102 static void
cancel_cb(GtkWidget * widget,gpointer data)103 cancel_cb(GtkWidget * widget, gpointer data)
104 {
105     GNCProgressDialog *progress = data;
106 
107     g_return_if_fail(progress);
108 
109     if (progress->cancel_func && !progress->cancel_func(progress->user_data))
110         return;
111 
112     if (progress->cancel_scm_func != SCM_UNDEFINED)
113     {
114         SCM result;
115 
116         result = scm_call_0(progress->cancel_scm_func);
117 
118         if (!scm_is_true(result))
119             return;
120     }
121 
122     if (progress->dialog != NULL)
123         gtk_widget_hide(progress->dialog);
124     progress->closed = TRUE;
125     gnc_progress_maybe_destroy(progress);
126 }
127 
128 
129 static gboolean
delete_cb(GtkWidget * widget,GdkEvent * event,gpointer data)130 delete_cb(GtkWidget *widget, GdkEvent  *event, gpointer data)
131 {
132     GNCProgressDialog *progress = data;
133 
134     g_return_val_if_fail(progress, TRUE);
135 
136     if (progress->finished)
137     {
138         if (progress->dialog != NULL)
139             gtk_widget_hide(progress->dialog);
140         progress->closed = TRUE;
141         gnc_progress_maybe_destroy(progress);
142         return TRUE;
143     }
144 
145     if (progress->cancel_func)
146     {
147         if (progress->cancel_func(progress->user_data))
148         {
149             if (progress->dialog != NULL)
150                 gtk_widget_hide(progress->dialog);
151             progress->closed = TRUE;
152             gnc_progress_maybe_destroy(progress);
153             return TRUE;
154         }
155     }
156 
157     if (progress->cancel_scm_func != SCM_UNDEFINED)
158     {
159         SCM result;
160 
161         result = scm_call_0(progress->cancel_scm_func);
162 
163         if (scm_is_true(result))
164         {
165             if (progress->dialog != NULL)
166                 gtk_widget_hide(progress->dialog);
167             progress->closed = TRUE;
168             gnc_progress_maybe_destroy(progress);
169             return TRUE;
170         }
171     }
172 
173     /* Don't delete the window, wait for gnc_progress_dialog_destroy. */
174     return TRUE;
175 }
176 
177 
178 static void
destroy_cb(GtkWidget * object,gpointer data)179 destroy_cb(GtkWidget *object, gpointer data)
180 {
181     GNCProgressDialog *progress = data;
182 
183     g_return_if_fail(progress);
184 
185     /* Make sure the callbacks aren't invoked */
186     progress->cancel_func = NULL;
187     if (progress->cancel_scm_func != SCM_UNDEFINED)
188         scm_gc_unprotect_object(progress->cancel_scm_func);
189     progress->cancel_scm_func = SCM_UNDEFINED;
190 
191     g_free(progress);
192 }
193 
194 
195 static void
gnc_progress_dialog_create(GtkWidget * parent,GNCProgressDialog * progress)196 gnc_progress_dialog_create(GtkWidget * parent, GNCProgressDialog *progress)
197 {
198     GtkWidget *dialog;
199     GtkBuilder *builder;
200 
201     g_return_if_fail(progress);
202 
203     builder = gtk_builder_new();
204     gnc_builder_add_from_file (builder, "dialog-progress.glade", "progress_dialog");
205 
206 
207     dialog = GTK_WIDGET(gtk_builder_get_object (builder, "progress_dialog"));
208     progress->dialog = dialog;
209 
210     // Set the name for this dialog so it can be easily manipulated with css
211     gtk_widget_set_name (GTK_WIDGET(dialog), "gnc-id-progress");
212 
213     /* parent */
214     if (parent != NULL)
215         gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent));
216 
217     g_signal_connect(G_OBJECT(dialog), "delete_event", G_CALLBACK(delete_cb), progress);
218 
219     g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(destroy_cb), progress);
220 
221     progress->primary_label = GTK_WIDGET(gtk_builder_get_object (builder, "primary_label"));
222     gtk_widget_hide(progress->primary_label);
223 
224     progress->secondary_label = GTK_WIDGET(gtk_builder_get_object (builder, "secondary_label"));
225     gtk_widget_hide(progress->secondary_label);
226 
227     progress->progress_bar = GTK_WIDGET(gtk_builder_get_object (builder, "progress_bar"));
228     progress->total_offset = 0;
229     progress->total_weight = 1;
230     progress->bar_value = 0;
231 
232     progress->sub_label = GTK_WIDGET(gtk_builder_get_object (builder, "sub_label"));
233     gtk_widget_hide(progress->sub_label);
234 
235     progress->log = GTK_WIDGET(gtk_builder_get_object (builder, "progress_log"));
236     gtk_widget_hide(GTK_WIDGET(gtk_builder_get_object (builder, "progress_log_window")));
237 
238     progress->ok_button = GTK_WIDGET(gtk_builder_get_object (builder, "ok_button"));
239 
240     g_signal_connect(progress->ok_button, "clicked",
241                      G_CALLBACK(ok_cb), progress);
242 
243     if (!progress->use_ok_button)
244         gtk_widget_hide(progress->ok_button);
245 
246     progress->cancel_button = GTK_WIDGET(gtk_builder_get_object (builder, "cancel_button"));
247 
248     g_signal_connect(progress->cancel_button, "clicked",
249                      G_CALLBACK(cancel_cb), progress);
250 
251     progress->cancel_func = NULL;
252     progress->user_data = NULL;
253 
254     progress->cancel_scm_func = SCM_UNDEFINED;
255 
256     progress->closed = FALSE;
257     progress->finished = FALSE;
258     progress->destroyed = FALSE;
259     progress->title_set = FALSE;
260 
261     gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, progress);
262     g_object_unref(G_OBJECT(builder));
263 }
264 
265 
266 GNCProgressDialog *
gnc_progress_dialog_new(GtkWidget * parent,gboolean use_ok_button)267 gnc_progress_dialog_new(GtkWidget * parent, gboolean use_ok_button)
268 {
269     GNCProgressDialog *progress;
270 
271     progress = g_new0(GNCProgressDialog, 1);
272 
273     progress->use_ok_button = use_ok_button;
274 
275     gnc_progress_dialog_create(parent, progress);
276 
277     gtk_widget_show(progress->dialog);
278 
279     gnc_progress_dialog_update(progress);
280 
281     return progress;
282 }
283 
284 
285 GNCProgressDialog *
gnc_progress_dialog_custom(GtkLabel * primary,GtkLabel * secondary,GtkProgressBar * bar,GtkLabel * suboperation,GtkTextView * log)286 gnc_progress_dialog_custom(GtkLabel       *primary,
287                            GtkLabel       *secondary,
288                            GtkProgressBar *bar,
289                            GtkLabel       *suboperation,
290                            GtkTextView    *log)
291 {
292     GNCProgressDialog *progress;
293 
294     progress = g_new0(GNCProgressDialog, 1);
295 
296     /* Set up widgets. */
297     progress->dialog = NULL;
298     progress->primary_label = GTK_WIDGET(primary);
299     progress->secondary_label = GTK_WIDGET(secondary);
300     progress->progress_bar = GTK_WIDGET(bar);
301     progress->sub_label = GTK_WIDGET(suboperation);
302     progress->log = GTK_WIDGET(log);
303     progress->ok_button = NULL;
304     progress->cancel_button = NULL;
305 
306     /* Initialize all other items. */
307     progress->total_offset = 0;
308     progress->total_weight = 1;
309     progress->bar_value = 0;
310     progress->cancel_func = NULL;
311     progress->user_data = NULL;
312     progress->cancel_scm_func = SCM_UNDEFINED;
313     progress->use_ok_button = FALSE;
314     progress->closed = FALSE;
315     progress->finished = FALSE;
316     progress->destroyed = FALSE;
317     progress->title_set = FALSE;
318 
319     return progress;
320 }
321 
322 
323 void
gnc_progress_dialog_set_title(GNCProgressDialog * progress,const char * title)324 gnc_progress_dialog_set_title(GNCProgressDialog *progress, const char *title)
325 {
326     g_return_if_fail(progress);
327 
328     if (!progress->dialog)
329         return;
330 
331     if (title == NULL)
332         title = "";
333 
334     gtk_window_set_title(GTK_WINDOW(progress->dialog), title);
335 
336     progress->title_set = TRUE;
337 
338     gnc_progress_dialog_update(progress);
339 }
340 
341 
342 void
gnc_progress_dialog_set_primary(GNCProgressDialog * progress,const gchar * str)343 gnc_progress_dialog_set_primary(GNCProgressDialog *progress,
344                                 const gchar *str)
345 {
346     g_return_if_fail(progress);
347 
348     if (progress->primary_label == NULL)
349         return;
350 
351     if (str == NULL || *str == '\0')
352         gtk_widget_hide(progress->primary_label);
353     else
354     {
355         /* Display the primary text with the HIG-recommended style. */
356         char *markup = g_markup_printf_escaped("<span weight=\"bold\" size=\"larger\">%s</span>", str);
357 
358         gtk_label_set_markup(GTK_LABEL(progress->primary_label), markup);
359         g_free(markup);
360         gtk_widget_show(progress->primary_label);
361     }
362 
363     gnc_progress_dialog_update(progress);
364 }
365 
366 
367 void
gnc_progress_dialog_set_heading(GNCProgressDialog * progress,const char * heading)368 gnc_progress_dialog_set_heading(GNCProgressDialog *progress,
369                                 const char *heading)
370 {
371     g_return_if_fail(progress);
372 
373     if (progress->primary_label == NULL)
374         return;
375 
376     if (heading == NULL || *heading == '\0')
377         gtk_widget_hide(progress->primary_label);
378     else
379     {
380         gtk_label_set_text(GTK_LABEL(progress->primary_label), heading);
381         gtk_widget_show(progress->primary_label);
382     }
383 
384     gnc_progress_dialog_update(progress);
385 }
386 
387 
388 void
gnc_progress_dialog_set_secondary(GNCProgressDialog * progress,const gchar * str)389 gnc_progress_dialog_set_secondary(GNCProgressDialog *progress,
390                                   const gchar *str)
391 {
392     g_return_if_fail(progress);
393 
394     if (progress->secondary_label == NULL)
395         return;
396 
397     if (str == NULL || *str == '\0')
398         gtk_widget_hide(progress->secondary_label);
399     else
400     {
401         gtk_label_set_text(GTK_LABEL(progress->secondary_label), str);
402         gtk_widget_show(progress->secondary_label);
403     }
404 
405     gnc_progress_dialog_update(progress);
406 }
407 
408 
409 void
gnc_progress_dialog_set_sub(GNCProgressDialog * progress,const gchar * str)410 gnc_progress_dialog_set_sub(GNCProgressDialog *progress,
411                             const gchar *str)
412 {
413     g_return_if_fail(progress);
414 
415     if (progress->sub_label == NULL)
416         return;
417 
418     if (str == NULL || *str == '\0')
419         gtk_widget_hide(progress->sub_label);
420     else
421     {
422         /* Display the suboperation text with the HIG-recommended style. */
423         char *markup = g_markup_printf_escaped("<span style=\"italic\">%s</span>", str);
424 
425         gtk_label_set_markup(GTK_LABEL(progress->sub_label), markup);
426         g_free(markup);
427         gtk_widget_show(progress->sub_label);
428     }
429 
430     gnc_progress_dialog_update(progress);
431 }
432 
433 
434 void
gnc_progress_dialog_reset_log(GNCProgressDialog * progress)435 gnc_progress_dialog_reset_log(GNCProgressDialog *progress)
436 {
437     GtkTextBuffer *buf;
438 
439     g_return_if_fail(progress);
440 
441     if (progress->log == NULL)
442         return;
443 
444     /* Reset the text buffer. */
445     buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(progress->log));
446     gtk_text_buffer_set_text(buf, "", -1);
447     gtk_text_buffer_set_modified(buf, FALSE);
448 
449     /* Show the log and its parent (in case it is in a scrolled window). */
450     gtk_widget_show(progress->log);
451     gtk_widget_show(gtk_widget_get_parent(progress->log));
452 
453     gnc_progress_dialog_update(progress);
454 }
455 
456 
457 void
gnc_progress_dialog_append_log(GNCProgressDialog * progress,const gchar * str)458 gnc_progress_dialog_append_log(GNCProgressDialog *progress, const gchar *str)
459 {
460     GtkTextBuffer *buf;
461     GtkTextIter    iter;
462 
463     g_return_if_fail(progress);
464 
465     if (progress->log == NULL || !str || !*str)
466         return;
467 
468     /* Append to the text buffer. */
469     buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(progress->log));
470     gtk_text_buffer_get_end_iter(buf, &iter);
471     gtk_text_buffer_insert(buf, &iter, str, -1);
472 
473     gnc_progress_dialog_update(progress);
474 }
475 
476 
477 void
gnc_progress_dialog_pause(GNCProgressDialog * progress)478 gnc_progress_dialog_pause(GNCProgressDialog *progress)
479 {
480     gchar *suffix;
481 
482     g_return_if_fail(progress);
483 
484     suffix = g_strconcat(" ", _("(paused)"), NULL);
485 
486     if (progress->sub_label && gtk_widget_get_visible(progress->sub_label))
487     {
488         const gchar *txt = gtk_label_get_text(GTK_LABEL(progress->sub_label));
489 
490         if (txt && !g_str_has_suffix(txt, suffix))
491         {
492             gchar *newtxt = g_strconcat(txt, suffix, NULL);
493             gnc_progress_dialog_set_sub(progress, newtxt);
494             g_free(newtxt);
495         }
496     }
497     else if (progress->dialog)
498     {
499         const gchar *txt = gtk_window_get_title(GTK_WINDOW(progress->dialog));
500 
501         if (txt && !g_str_has_suffix(txt, suffix))
502         {
503             gchar *newtxt = g_strconcat(txt, suffix, NULL);
504             gtk_window_set_title(GTK_WINDOW(progress->dialog), newtxt);
505             g_free(newtxt);
506         }
507     }
508     else if (progress->primary_label &&
509              gtk_widget_get_visible(progress->primary_label))
510     {
511         const gchar *txt = gtk_label_get_text(GTK_LABEL(progress->primary_label));
512 
513         if (txt && !g_str_has_suffix(txt, suffix))
514         {
515             gchar *newtxt = g_strconcat(txt, suffix, NULL);
516             gnc_progress_dialog_set_primary(progress, newtxt);
517             g_free(newtxt);
518         }
519     }
520 
521     g_free(suffix);
522 
523     gnc_progress_dialog_update(progress);
524 }
525 
526 void
gnc_progress_dialog_resume(GNCProgressDialog * progress)527 gnc_progress_dialog_resume(GNCProgressDialog *progress)
528 {
529     gchar *suffix;
530 
531     g_return_if_fail(progress);
532 
533     suffix = g_strconcat(" ", _("(paused)"), NULL);
534 
535     /* Remove any pause indication from the suboperation label. */
536     if (progress->sub_label)
537     {
538         const gchar *txt = gtk_label_get_text(GTK_LABEL(progress->sub_label));
539 
540         if (txt && g_str_has_suffix(txt, suffix))
541         {
542             gchar *newtxt = g_strndup(txt, strlen(txt) - strlen(suffix));
543             gnc_progress_dialog_set_sub(progress, newtxt);
544             g_free(newtxt);
545         }
546     }
547 
548     /* Remove any pause indication from the window title. */
549     if (progress->dialog)
550     {
551         const gchar *txt = gtk_window_get_title(GTK_WINDOW(progress->dialog));
552 
553         if (txt && g_str_has_suffix(txt, suffix))
554         {
555             gchar *newtxt = g_strndup(txt, strlen(txt) - strlen(suffix));
556             gtk_window_set_title(GTK_WINDOW(progress->dialog), newtxt);
557             g_free(newtxt);
558         }
559     }
560 
561     /* Remove any pause indication from the primary text. */
562     if (progress->primary_label)
563     {
564         const gchar *txt = gtk_label_get_text(GTK_LABEL(progress->primary_label));
565 
566         if (txt && g_str_has_suffix(txt, suffix))
567         {
568             gchar *newtxt = g_strndup(txt, strlen(txt) - strlen(suffix));
569             gnc_progress_dialog_set_primary(progress, newtxt);
570             g_free(newtxt);
571         }
572     }
573 
574     g_free(suffix);
575 
576     gnc_progress_dialog_update(progress);
577 }
578 
579 
580 void
gnc_progress_dialog_set_cancel_func(GNCProgressDialog * progress,GNCProgressCancelFunc cancel_func,gpointer user_data)581 gnc_progress_dialog_set_cancel_func(GNCProgressDialog *progress,
582                                     GNCProgressCancelFunc cancel_func,
583                                     gpointer user_data)
584 {
585     g_return_if_fail(progress);
586 
587     if (progress->cancel_button == NULL)
588         return;
589 
590     progress->cancel_func = cancel_func;
591     progress->user_data = user_data;
592 
593     if (cancel_func)
594         gtk_widget_show(progress->cancel_button);
595 }
596 
597 
598 void
gnc_progress_dialog_set_cancel_scm_func(GNCProgressDialog * progress,SCM cancel_scm_func)599 gnc_progress_dialog_set_cancel_scm_func(GNCProgressDialog *progress,
600                                         SCM cancel_scm_func)
601 {
602     g_return_if_fail(progress);
603 
604     if (progress->cancel_button == NULL)
605         return;
606 
607     if (progress->cancel_scm_func != SCM_UNDEFINED)
608         scm_gc_unprotect_object(progress->cancel_scm_func);
609 
610     if (scm_is_procedure(cancel_scm_func))
611     {
612         progress->cancel_scm_func = cancel_scm_func;
613         scm_gc_protect_object(cancel_scm_func);
614         gtk_widget_show(progress->cancel_button);
615     }
616     else
617         progress->cancel_scm_func = SCM_UNDEFINED;
618 }
619 
620 
621 void
gnc_progress_dialog_set_value(GNCProgressDialog * progress,gdouble value)622 gnc_progress_dialog_set_value(GNCProgressDialog *progress, gdouble value)
623 {
624     GtkProgressBar *bar;
625 
626     g_return_if_fail(progress);
627 
628     /* Get the progress bar widget. */
629     bar = GTK_PROGRESS_BAR(progress->progress_bar);
630     if (bar == NULL)
631         return;
632 
633     /* Update the progress bar. If value is over 1,
634      * the bar will pulse instead of fill. */
635     if (value > 1)
636         gtk_progress_bar_pulse(bar);
637     else
638     {
639         progress->bar_value = value > 0 ? value : 0;
640         gtk_progress_bar_set_fraction(bar,
641                                       progress->total_offset + progress->bar_value * progress->total_weight);
642     }
643 
644     gnc_progress_dialog_update(progress);
645 }
646 
647 
648 guint
gnc_progress_dialog_push(GNCProgressDialog * progress,gdouble weight)649 gnc_progress_dialog_push(GNCProgressDialog *progress, gdouble weight)
650 {
651     GtkProgressBar *bar;
652     VirtualBar     *newbar;
653 
654     g_return_val_if_fail(progress, 0);
655     g_return_val_if_fail(weight > 0, 0);
656 
657     /* Get the progress bar widget. */
658     bar = GTK_PROGRESS_BAR(progress->progress_bar);
659     if (bar == NULL)
660         return 0;
661 
662     /* Create the new virtual progress bar. */
663     newbar = g_new0(VirtualBar, 1);
664     newbar->offset = progress->bar_value;
665     if (newbar->offset + weight > 1)
666         /* The requested weight is more than the unfilled portion of the bar. */
667         newbar->weight = 1 - newbar->offset;
668     else
669         newbar->weight = weight;
670     progress->bars = g_list_prepend(progress->bars, newbar);
671 
672     /* Set the total effective offset and weight */
673     progress->total_offset = gtk_progress_bar_get_fraction(bar);
674     progress->total_weight *= newbar->weight;
675 
676     /* Set the new bar as unfilled. */
677     progress->bar_value = 0;
678 
679     return g_list_length(progress->bars);
680 }
681 
682 
683 guint
gnc_progress_dialog_pop(GNCProgressDialog * progress)684 gnc_progress_dialog_pop(GNCProgressDialog *progress)
685 {
686     VirtualBar     *bar;
687 
688     g_return_val_if_fail(progress, 0);
689 
690     /* Get the progress bar widget. */
691     if (progress->progress_bar == NULL || progress->bars == NULL)
692         return 0;
693 
694     /* Pop the bar off the bar stack. */
695     bar = progress->bars->data;
696     progress->bars = g_list_delete_link(progress->bars, progress->bars);
697 
698     /* Determine the value of the current bar. */
699     progress->bar_value = bar->offset + bar->weight * progress->bar_value;
700 
701     /* Set the total effective offset and weight. */
702     if (progress->bars == NULL)
703     {
704         progress->total_offset = 0;
705         progress->total_weight = 1;
706     }
707     else
708     {
709         progress->total_offset -= bar->offset *
710                                   ((VirtualBar *) progress->bars->data)->weight;
711         progress->total_weight /= bar->weight;
712     }
713     g_free(bar);
714 
715     if (progress->bars == NULL)
716         return 0;
717     return g_list_length(progress->bars);
718 }
719 
720 
721 guint
gnc_progress_dialog_pop_full(GNCProgressDialog * progress)722 gnc_progress_dialog_pop_full(GNCProgressDialog *progress)
723 {
724     gnc_progress_dialog_set_value(progress, 1);
725     return gnc_progress_dialog_pop(progress);
726 }
727 
728 
729 void
gnc_progress_dialog_reset_value(GNCProgressDialog * progress)730 gnc_progress_dialog_reset_value(GNCProgressDialog *progress)
731 {
732     g_return_if_fail(progress);
733 
734     /* Return to the top level. */
735     while (gnc_progress_dialog_pop(progress));
736 
737     /* Reset the bar to empty. */
738     gnc_progress_dialog_set_value(progress, 0);
739 }
740 
741 
742 void
gnc_progress_dialog_update(GNCProgressDialog * progress)743 gnc_progress_dialog_update(GNCProgressDialog *progress)
744 {
745     while (gtk_events_pending())
746         gtk_main_iteration();
747 }
748 
749 
750 void
gnc_progress_dialog_finish(GNCProgressDialog * progress)751 gnc_progress_dialog_finish(GNCProgressDialog *progress)
752 {
753     g_return_if_fail(progress);
754 
755     if (!progress->use_ok_button)
756     {
757         if (progress->dialog != NULL)
758             gtk_widget_hide(progress->dialog);
759         progress->closed = TRUE;
760     }
761 
762     gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress->progress_bar), 1.0);
763 
764     gtk_widget_set_sensitive(progress->ok_button, TRUE);
765     gtk_widget_set_sensitive(progress->cancel_button, FALSE);
766 
767     if (gtk_widget_get_visible(progress->primary_label))
768         gnc_progress_dialog_set_heading(progress, _("Complete"));
769 
770     if (!progress->title_set)
771         gtk_window_set_title(GTK_WINDOW(progress->dialog), _("Complete"));
772 
773     gtk_window_set_modal(GTK_WINDOW(progress->dialog), FALSE);
774 
775     progress->finished = TRUE;
776 
777     gnc_progress_dialog_update(progress);
778 }
779 
780 
781 void
gnc_progress_dialog_destroy(GNCProgressDialog * progress)782 gnc_progress_dialog_destroy(GNCProgressDialog *progress)
783 {
784     g_return_if_fail(progress);
785 
786     /* Make sure the callbacks aren't invoked */
787     progress->cancel_func = NULL;
788     if (progress->cancel_scm_func != SCM_UNDEFINED)
789         scm_gc_unprotect_object(progress->cancel_scm_func);
790     progress->cancel_scm_func = SCM_UNDEFINED;
791 
792     if (!progress->finished)
793     {
794         if (progress->dialog != NULL)
795             gtk_widget_hide(progress->dialog);
796         progress->closed = TRUE;
797     }
798 
799     progress->destroyed = TRUE;
800 
801     gnc_progress_maybe_destroy(progress);
802 }
803