From 5b7f7130ba14bc516f9f90ffd61cad5d2736dc2d Mon Sep 17 00:00:00 2001 From: Dave Peticolas Date: Tue, 10 Oct 2000 09:42:43 +0000 Subject: [PATCH] Create a progress dialog with a guile-wrapped API. Add an extensions menu item for testing the progess dialog. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@3041 57a11ea4-9604-0410-9ed3-97b8803252fd --- po/POTFILES.in | 1 + src/gnome/Makefile.am | 2 + src/gnome/dialog-progress.c | 364 ++++++++++++++++++++++++++++++++++ src/gnome/dialog-progress.h | 85 ++++++++ src/gnome/glade-gnc-dialogs.c | 66 ++++++ src/gnome/glade-gnc-dialogs.h | 1 + src/gnome/gnc-dialogs.glade | 91 +++++++++ src/scm/extensions.scm | 24 +++ 8 files changed, 634 insertions(+) create mode 100644 src/gnome/dialog-progress.c create mode 100644 src/gnome/dialog-progress.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 3f262b2387..12a4066909 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -5,6 +5,7 @@ po/pseudo-source.c po/guile_strings.txt src/gnome/dialog-account-picker.c src/gnome/dialog-fincalc.c +src/gnome/dialog-progress.c src/gnome/dialog-qif-import.c src/gnome/glade-gnc-dialogs.c src/gnome/print-session.c diff --git a/src/gnome/Makefile.am b/src/gnome/Makefile.am index c8299dc6a7..080bc0ecd4 100644 --- a/src/gnome/Makefile.am +++ b/src/gnome/Makefile.am @@ -12,6 +12,7 @@ libgncgnome_a_SOURCES = \ dialog-find-transactions.c \ dialog-options.c \ dialog-print-check.c \ + dialog-progress.c \ dialog-qif-import.c \ dialog-totd.c \ dialog-transfer.c \ @@ -49,6 +50,7 @@ noinst_HEADERS = \ dialog-find-transactions.h \ dialog-options.h \ dialog-print-check.h \ + dialog-progress.h \ dialog-qif-import.h \ dialog-totd.h \ dialog-transfer.h \ diff --git a/src/gnome/dialog-progress.c b/src/gnome/dialog-progress.c new file mode 100644 index 0000000000..434996d6c7 --- /dev/null +++ b/src/gnome/dialog-progress.c @@ -0,0 +1,364 @@ +/********************************************************************\ + * dialog-progress.c -- GnuCash progress dialog * + * Copyright (C) 2000 Dave Peticolas * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 * + * Boston, MA 02111-1307, USA gnu@gnu.org * + * * +\********************************************************************/ + +#include "config.h" + +#include +#include + +#include "dialog-progress.h" +#include "glade-gnc-dialogs.h" +#include "messages.h" + + +struct _GNCProgressDialog +{ + GtkWidget *dialog; + + GtkWidget *heading_label; + GtkWidget *progress_bar; + + GtkWidget *ok_button; + GtkWidget *cancel_button; + + GNCProgressCancelFunc cancel_func; + gpointer user_data; + + SCM cancel_scm_func; + + gboolean closed; + gboolean finished; + gboolean destroyed; + gboolean title_set; +}; + + +static void +gnc_progress_maybe_destroy (GNCProgressDialog *progress) +{ + if (!(progress->closed && progress->destroyed)) + return; + + gtk_widget_destroy(progress->dialog); +} + +static void +ok_cb(GtkWidget * widget, gpointer data) +{ + GNCProgressDialog *progress = data; + + gtk_widget_hide(progress->dialog); + progress->closed = TRUE; + gnc_progress_maybe_destroy (progress); +} + +static void +cancel_cb(GtkWidget * widget, gpointer data) +{ + GNCProgressDialog *progress = data; + + if (progress->cancel_func && !progress->cancel_func (progress->user_data)) + return; + + if (progress->cancel_scm_func != SCM_UNDEFINED) + { + SCM result; + + result = gh_call0(progress->cancel_scm_func); + + if (!gh_scm2bool (result)) + return; + } + + gtk_widget_hide(progress->dialog); + progress->closed = TRUE; + gnc_progress_maybe_destroy (progress); +} + +static gboolean +delete_cb(GtkWidget *widget, GdkEvent *event, gpointer data) +{ + GNCProgressDialog *progress = data; + + if (progress->finished) + { + gtk_widget_hide(progress->dialog); + progress->closed = TRUE; + gnc_progress_maybe_destroy (progress); + return TRUE; + } + + if (progress->cancel_func) + { + if (progress->cancel_func (progress->user_data)) + { + gtk_widget_hide(progress->dialog); + progress->closed = TRUE; + gnc_progress_maybe_destroy (progress); + return TRUE; + } + } + + if (progress->cancel_scm_func != SCM_UNDEFINED) + { + SCM result; + + result = gh_call0(progress->cancel_scm_func); + + if (gh_scm2bool (result)) + { + gtk_widget_hide(progress->dialog); + progress->closed = TRUE; + gnc_progress_maybe_destroy (progress); + return TRUE; + } + } + + /* Don't delete the window, wait for gnc_progress_dialog_destroy. */ + return TRUE; +} + +static void +destroy_cb(GtkObject *object, gpointer data) +{ + GNCProgressDialog *progress = data; + + /* Make sure the callbacks aren't invoked */ + progress->cancel_func = NULL; + if (progress->cancel_scm_func != SCM_UNDEFINED) + scm_unprotect_object (progress->cancel_scm_func); + progress->cancel_scm_func = SCM_UNDEFINED; + + g_free(progress); +} + +static void +gnc_progress_dialog_create(GtkWidget * parent, GNCProgressDialog *progress) +{ + GtkWidget *dialog; + GtkObject *tdo; + + dialog = create_Progress_Dialog(); + progress->dialog = dialog; + tdo = GTK_OBJECT (dialog); + + /* parent */ + if (parent != NULL) + gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent)); + + gtk_signal_connect (tdo, "delete_event", + GTK_SIGNAL_FUNC (delete_cb), progress); + + gtk_signal_connect (tdo, "destroy", GTK_SIGNAL_FUNC (destroy_cb), progress); + + progress->heading_label = gtk_object_get_data(tdo, "heading_label"); + gtk_widget_hide(progress->heading_label); + + progress->progress_bar = gtk_object_get_data(tdo, "progress_bar"); + gtk_progress_set_show_text (GTK_PROGRESS(progress->progress_bar), TRUE); + gtk_progress_configure (GTK_PROGRESS(progress->progress_bar), + 0.0, 0.0, 100.0); + + progress->ok_button = gtk_object_get_data(tdo, "ok_button"); + + gtk_signal_connect(GTK_OBJECT(progress->ok_button), "clicked", + GTK_SIGNAL_FUNC(ok_cb), progress); + + progress->cancel_button = gtk_object_get_data(tdo, "cancel_button"); + + gtk_signal_connect(GTK_OBJECT(progress->cancel_button), "clicked", + GTK_SIGNAL_FUNC(cancel_cb), progress); + + progress->cancel_func = NULL; + progress->user_data = NULL; + + progress->cancel_scm_func = SCM_UNDEFINED; + + progress->closed = FALSE; + progress->finished = FALSE; + progress->destroyed = FALSE; + progress->title_set = FALSE; +} + +GNCProgressDialog * +gnc_progress_dialog_new (GtkWidget * parent) +{ + GNCProgressDialog *progress; + + progress = g_new0(GNCProgressDialog, 1); + + gnc_progress_dialog_create(parent, progress); + + gtk_widget_show(progress->dialog); + + gnc_progress_dialog_update (progress); + + return progress; +} + +void +gnc_progress_dialog_set_title (GNCProgressDialog *progress, const char *title) +{ + if (progress == NULL) + return; + + if (title == NULL) + title = ""; + + gtk_window_set_title (GTK_WINDOW (progress->dialog), title); + + progress->title_set = TRUE; + + gnc_progress_dialog_update (progress); +} + +void +gnc_progress_dialog_set_heading (GNCProgressDialog *progress, + const char *heading) +{ + if (progress == NULL) + return; + + if (heading == NULL || *heading == '\0') + gtk_widget_hide (progress->heading_label); + else + { + gtk_label_set_text (GTK_LABEL (progress->heading_label), heading); + gtk_widget_show (progress->heading_label); + } + + gnc_progress_dialog_update (progress); +} + +void +gnc_progress_dialog_set_limits (GNCProgressDialog *progress, + gfloat min, gfloat max) +{ + if (progress == NULL) + return; + + gtk_progress_configure (GTK_PROGRESS (progress->progress_bar), + min, min, max); + + gnc_progress_dialog_update (progress); +} + +void +gnc_progress_dialog_set_cancel_func (GNCProgressDialog *progress, + GNCProgressCancelFunc cancel_func, + gpointer user_data) +{ + if (progress == NULL) + return; + + progress->cancel_func = cancel_func; + progress->user_data = user_data; + + if (cancel_func) + gtk_widget_show (progress->cancel_button); +} + +void +gnc_progress_dialog_set_cancel_scm_func (GNCProgressDialog *progress, + SCM cancel_scm_func) +{ + if (progress == NULL) + return; + + if (progress->cancel_scm_func != SCM_UNDEFINED) + scm_unprotect_object (progress->cancel_scm_func); + + if (gh_procedure_p(cancel_scm_func)) + { + progress->cancel_scm_func = cancel_scm_func; + scm_protect_object (cancel_scm_func); + gtk_widget_show (progress->cancel_button); + } + else + progress->cancel_scm_func = SCM_UNDEFINED; +} + +void +gnc_progress_dialog_set_value (GNCProgressDialog *progress, gfloat value) +{ + if (progress == NULL) + return; + + gtk_progress_set_value (GTK_PROGRESS (progress->progress_bar), value); + + gnc_progress_dialog_update (progress); +} + +void +gnc_progress_dialog_update (GNCProgressDialog *progress) +{ + while (gtk_events_pending()) + gtk_main_iteration(); +} + +void +gnc_progress_dialog_finish (GNCProgressDialog *progress) +{ + if (progress == NULL) + return; + + gtk_progress_set_percentage (GTK_PROGRESS (progress->progress_bar), 1.0); + + gtk_widget_set_sensitive (progress->ok_button, TRUE); + gtk_widget_set_sensitive (progress->cancel_button, FALSE); + + if (GTK_WIDGET_VISIBLE(progress->heading_label)) + gnc_progress_dialog_set_heading (progress, _("Complete")); + + if (!progress->title_set) + gtk_window_set_title (GTK_WINDOW (progress->dialog), _("Complete")); + + gtk_window_set_modal (GTK_WINDOW (progress->dialog), FALSE); + + progress->finished = TRUE; + + gnc_progress_dialog_update (progress); +} + +void +gnc_progress_dialog_destroy (GNCProgressDialog *progress) +{ + if (progress == NULL) + return; + + /* Make sure the callbacks aren't invoked */ + progress->cancel_func = NULL; + if (progress->cancel_scm_func != SCM_UNDEFINED) + scm_unprotect_object (progress->cancel_scm_func); + progress->cancel_scm_func = SCM_UNDEFINED; + + if (!progress->finished) + { + gtk_widget_hide (progress->dialog); + progress->closed = TRUE; + } + + progress->destroyed = TRUE; + + gnc_progress_maybe_destroy (progress); +} diff --git a/src/gnome/dialog-progress.h b/src/gnome/dialog-progress.h new file mode 100644 index 0000000000..73c646cd44 --- /dev/null +++ b/src/gnome/dialog-progress.h @@ -0,0 +1,85 @@ +/********************************************************************\ + * dialog-progress.h -- public GnuCash progress dialog functions * + * Copyright (C) 2000 Dave Peticolas * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 59 Temple Place - Suite 330 Fax: +1-617-542-2652 * + * Boston, MA 02111-1307, USA gnu@gnu.org * + * * +\********************************************************************/ + +#ifndef __DIALOG_PROGRESS_H__ +#define __DIALOG_PROGRESS_H__ + +#include + + +typedef struct _GNCProgressDialog GNCProgressDialog; + +typedef gboolean (*GNCProgressCancelFunc) (gpointer user_data); + + +/* Create and return a dialog for displaying the progress of + * an activity. Useful for long-running operations. */ +GNCProgressDialog * gnc_progress_dialog_new (GtkWidget *parent); + +/* Set the title of the progress dialog. */ +void gnc_progress_dialog_set_title (GNCProgressDialog *progress, + const char *title); + +/* Set the heading (the text above the progress meter) of + * the progress dialog. If it is NULL or blank, the heading + * is hidden (this is the default state). */ +void gnc_progress_dialog_set_heading (GNCProgressDialog *progress, + const char *heading); + +/* Set the upper and lower bound of the progress meter. */ +void gnc_progress_dialog_set_limits (GNCProgressDialog *progress, + gfloat min, gfloat max); + +/* Set the C function which will be called if the user hits the + * 'cancel' button. The cancel function returns a boolean value. + * If the value is TRUE, the window is hidden. */ +void gnc_progress_dialog_set_cancel_func (GNCProgressDialog *progress, + GNCProgressCancelFunc cancel_func, + gpointer user_data); + +/* Set a guile function which will be called if the user hits cancel. + * Will be called after the C function, if any. The function should + * return #t if the dialog should be hidden. If there is no C or guile + * cancel callback (the default state), the cancel button is inactive. */ +void gnc_progress_dialog_set_cancel_scm_func (GNCProgressDialog *progress, + SCM cancel_scm_func); + +/* Set the value of the progress dialog. */ +void gnc_progress_dialog_set_value (GNCProgressDialog *progress, gfloat value); + +/* Update the GUI of the progress dialog, and call any pending cancel + * callbacks. This function will be called automatically by the other + * functions, including gnc_progress_dialog_set_value. */ +void gnc_progress_dialog_update (GNCProgressDialog *progress); + +/* Set the progress meter to fully complete, change the heading, if + * any, to "Complete", enable the 'OK' button, and make the dialog + * non-modal. */ +void gnc_progress_dialog_finish (GNCProgressDialog *progress); + +/* Destroy the dialog. If gnc_progress_dialog_finish has been called, + * the dialog will not be destroyed until the user dismisses the window. + * This function must be called in order to reclaim the dialog's memory. */ +void gnc_progress_dialog_destroy (GNCProgressDialog *progress); + +#endif diff --git a/src/gnome/glade-gnc-dialogs.c b/src/gnome/glade-gnc-dialogs.c index 1146e46755..e0054ad4d1 100644 --- a/src/gnome/glade-gnc-dialogs.c +++ b/src/gnome/glade-gnc-dialogs.c @@ -4528,3 +4528,69 @@ create_Transfer_Dialog (void) return Transfer_Dialog; } +GtkWidget* +create_Progress_Dialog (void) +{ + GtkWidget *Progress_Dialog; + GtkWidget *vbox85; + GtkWidget *heading_label; + GtkWidget *progress_bar; + GtkWidget *hbuttonbox3; + GtkWidget *ok_button; + GtkWidget *cancel_button; + + Progress_Dialog = gtk_window_new (GTK_WINDOW_DIALOG); + gtk_object_set_data (GTK_OBJECT (Progress_Dialog), "Progress_Dialog", Progress_Dialog); + gtk_window_set_title (GTK_WINDOW (Progress_Dialog), _("Working...")); + gtk_window_set_modal (GTK_WINDOW (Progress_Dialog), TRUE); + gtk_window_set_policy (GTK_WINDOW (Progress_Dialog), FALSE, FALSE, FALSE); + + vbox85 = gtk_vbox_new (FALSE, 5); + gtk_widget_ref (vbox85); + gtk_object_set_data_full (GTK_OBJECT (Progress_Dialog), "vbox85", vbox85, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (vbox85); + gtk_container_add (GTK_CONTAINER (Progress_Dialog), vbox85); + gtk_container_set_border_width (GTK_CONTAINER (vbox85), 5); + + heading_label = gtk_label_new (_("Heading")); + gtk_widget_ref (heading_label); + gtk_object_set_data_full (GTK_OBJECT (Progress_Dialog), "heading_label", heading_label, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (heading_label); + gtk_box_pack_start (GTK_BOX (vbox85), heading_label, FALSE, FALSE, 0); + + progress_bar = gtk_progress_bar_new (); + gtk_widget_ref (progress_bar); + gtk_object_set_data_full (GTK_OBJECT (Progress_Dialog), "progress_bar", progress_bar, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (progress_bar); + gtk_box_pack_start (GTK_BOX (vbox85), progress_bar, FALSE, FALSE, 0); + gtk_progress_set_show_text (GTK_PROGRESS (progress_bar), TRUE); + + hbuttonbox3 = gtk_hbutton_box_new (); + gtk_widget_ref (hbuttonbox3); + gtk_object_set_data_full (GTK_OBJECT (Progress_Dialog), "hbuttonbox3", hbuttonbox3, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (hbuttonbox3); + gtk_box_pack_start (GTK_BOX (vbox85), hbuttonbox3, TRUE, TRUE, 0); + + ok_button = gnome_stock_button (GNOME_STOCK_BUTTON_OK); + gtk_widget_ref (ok_button); + gtk_object_set_data_full (GTK_OBJECT (Progress_Dialog), "ok_button", ok_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_widget_show (ok_button); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), ok_button); + gtk_widget_set_sensitive (ok_button, FALSE); + GTK_WIDGET_SET_FLAGS (ok_button, GTK_CAN_DEFAULT); + + cancel_button = gnome_stock_button (GNOME_STOCK_BUTTON_CANCEL); + gtk_widget_ref (cancel_button); + gtk_object_set_data_full (GTK_OBJECT (Progress_Dialog), "cancel_button", cancel_button, + (GtkDestroyNotify) gtk_widget_unref); + gtk_container_add (GTK_CONTAINER (hbuttonbox3), cancel_button); + GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT); + + return Progress_Dialog; +} + diff --git a/src/gnome/glade-gnc-dialogs.h b/src/gnome/glade-gnc-dialogs.h index 50b3e08af9..0777f33299 100644 --- a/src/gnome/glade-gnc-dialogs.h +++ b/src/gnome/glade-gnc-dialogs.h @@ -15,3 +15,4 @@ GtkWidget* create_Financial_Calculator_Dialog (void); GtkWidget* create_Amortization_Schedule_Dialog (void); GtkWidget* create_Account_Dialog (void); GtkWidget* create_Transfer_Dialog (void); +GtkWidget* create_Progress_Dialog (void); diff --git a/src/gnome/gnc-dialogs.glade b/src/gnome/gnc-dialogs.glade index 536ea0975c..efefec8a51 100644 --- a/src/gnome/gnc-dialogs.glade +++ b/src/gnome/gnc-dialogs.glade @@ -6679,4 +6679,95 @@ Daily (365) + + GtkWindow + Progress Dialog + Working... + GTK_WINDOW_DIALOG + GTK_WIN_POS_NONE + True + False + False + False + + + GtkVBox + vbox85 + 5 + False + 5 + + + GtkLabel + heading_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + False + False + + + + + GtkProgressBar + progress_bar + 0 + 0 + 100 + GTK_PROGRESS_CONTINUOUS + GTK_PROGRESS_LEFT_TO_RIGHT + False + True + %P %% + 0.5 + 0.5 + + 0 + False + False + + + + + GtkHButtonBox + hbuttonbox3 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + ok_button + False + True + True + GNOME_STOCK_BUTTON_OK + + + + GtkButton + cancel_button + False + True + True + GNOME_STOCK_BUTTON_CANCEL + + + + + diff --git a/src/scm/extensions.scm b/src/scm/extensions.scm index 921bb5a22d..a750a65138 100644 --- a/src/scm/extensions.scm +++ b/src/scm/extensions.scm @@ -68,6 +68,30 @@ (list "Extensions" "") (lambda () (gnc:main-win-export-data-as-text win)))) + (define export-item + (gnc:make-menu-item "Test progress dialog" + "Test progress dialog" + (list "Extensions" "") + (lambda () + (let ((dialog (gnc:progress-dialog-new + (gnc:get-ui-data))) + (canceled #f)) + (gnc:progress-dialog-set-cancel-scm-func + dialog + (lambda () + (display "User canceled.") (newline) + (set! canceled #t) + #t)) + (let loop ((value 0.0)) + (gnc:progress-dialog-set-value dialog value) + (gnc:progress-dialog-set-heading + dialog (number->string value)) + (sleep 1) + (if (and (not canceled) (< value 90.0)) + (loop (+ value 5.0)))) + (gnc:progress-dialog-finish dialog) + (gnc:progress-dialog-destroy dialog))))) + (define strings-item (gnc:make-menu-item "Save Translatable Strings"