From 01e2fc5b5a99fc9c5096b13bfe6323174465fd35 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Wed, 2 Jun 2010 16:00:16 -0400 Subject: [PATCH] Bug 596428 - GtkAssistant: Support ending with a progress page - Add gtk_assistant_commit() This function discards the visited pages list so the back button is not shown on the current page, and removes the cancel button from subsequent pages. Use this when information provided thus far cannot be revisited. - Don't show the Forward button on a GTK_ASSISTANT_PAGE_PROGRESS if it's the last page (according to the forward page function). - Append a progress page to the GtkAssistant demo. --- demos/gtk-demo/assistant.c | 55 ++++++++++++++++++++++++- docs/reference/gtk/gtk-sections.txt | 1 + gtk/gtk.symbols | 1 + gtk/gtkassistant.c | 64 +++++++++++++++++++++++++---- gtk/gtkassistant.h | 4 +- 5 files changed, 115 insertions(+), 10 deletions(-) diff --git a/demos/gtk-demo/assistant.c b/demos/gtk-demo/assistant.c index 6cb5399f6b..a00c595370 100644 --- a/demos/gtk-demo/assistant.c +++ b/demos/gtk-demo/assistant.c @@ -9,12 +9,35 @@ #include "demo-common.h" static GtkWidget *assistant = NULL; +static GtkWidget *progress_bar = NULL; + +static gboolean +apply_changes_gradually (gpointer data) +{ + gdouble fraction; + + /* Work, work, work... */ + fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (progress_bar)); + fraction += 0.05; + + if (fraction < 1.0) + { + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress_bar), fraction); + return TRUE; + } + else + { + /* Close automatically once changes are fully applied. */ + gtk_widget_destroy (assistant); + return FALSE; + } +} static void on_assistant_apply (GtkWidget *widget, gpointer data) { - /* Apply here changes, this is a fictional - example, so we just do nothing here */ + /* Start a timer to simulate changes taking a few seconds to apply. */ + g_timeout_add (100, apply_changes_gradually, NULL); } static void @@ -38,6 +61,13 @@ on_assistant_prepare (GtkWidget *widget, GtkWidget *page, gpointer data) title = g_strdup_printf ("Sample assistant (%d of %d)", current_page + 1, n_pages); gtk_window_set_title (GTK_WINDOW (widget), title); g_free (title); + + /* The fourth page (counting from zero) is the progress page. The + * user clicked Apply to get here so we tell the assistant to commit, + * which means the changes up to this point are permanent and cannot + * be cancelled or revisited. */ + if (current_page == 3) + gtk_assistant_commit (GTK_ASSISTANT (widget)); } static void @@ -127,6 +157,26 @@ create_page3 (GtkWidget *assistant) g_object_unref (pixbuf); } +static void +create_page4 (GtkWidget *assistant) +{ + GtkWidget *page; + + page = gtk_alignment_new (0.5, 0.5, 0.5, 0.0); + + progress_bar = gtk_progress_bar_new (); + gtk_container_add (GTK_CONTAINER (page), progress_bar); + + gtk_widget_show_all (page); + gtk_assistant_append_page (GTK_ASSISTANT (assistant), page); + gtk_assistant_set_page_type (GTK_ASSISTANT (assistant), page, GTK_ASSISTANT_PAGE_PROGRESS); + gtk_assistant_set_page_title (GTK_ASSISTANT (assistant), page, "Applying changes"); + + /* This prevents the assistant window from being + * closed while we're "busy" applying changes. */ + gtk_assistant_set_page_complete (GTK_ASSISTANT (assistant), page, FALSE); +} + GtkWidget* do_assistant (GtkWidget *do_widget) { @@ -142,6 +192,7 @@ do_assistant (GtkWidget *do_widget) create_page1 (assistant); create_page2 (assistant); create_page3 (assistant); + create_page4 (assistant); g_signal_connect (G_OBJECT (assistant), "cancel", G_CALLBACK (on_assistant_close_cancel), &assistant); diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt index dda9c478af..733e32c779 100644 --- a/docs/reference/gtk/gtk-sections.txt +++ b/docs/reference/gtk/gtk-sections.txt @@ -371,6 +371,7 @@ gtk_assistant_get_page_complete gtk_assistant_add_action_widget gtk_assistant_remove_action_widget gtk_assistant_update_buttons_state +gtk_assistant_commit GtkAssistantClass diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 24ad5da00e..a4d54cf6f9 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -302,6 +302,7 @@ gtk_assistant_get_page_complete gtk_assistant_add_action_widget gtk_assistant_remove_action_widget gtk_assistant_update_buttons_state +gtk_assistant_commit #endif #endif diff --git a/gtk/gtkassistant.c b/gtk/gtkassistant.c index 41ecd1311b..8f18f133e9 100644 --- a/gtk/gtkassistant.c +++ b/gtk/gtkassistant.c @@ -103,6 +103,8 @@ struct _GtkAssistantPrivate GtkAssistantPageFunc forward_function; gpointer forward_function_data; GDestroyNotify forward_data_destroy; + + guint committed : 1; }; static void gtk_assistant_class_init (GtkAssistantClass *class); @@ -267,7 +269,7 @@ gtk_assistant_class_init (GtkAssistantClass *class) * * A handler for the ::apply signal should carry out the actions for which * the wizard has collected data. If the action takes a long time to complete, - * you might consider to put a page of type %GTK_ASSISTANT_PAGE_PROGRESS + * you might consider putting a page of type %GTK_ASSISTANT_PAGE_PROGRESS * after the confirmation page and handle this operation within the * #GtkAssistant::prepare signal of the progress page. * @@ -472,6 +474,23 @@ compute_last_button_state (GtkAssistant *assistant) gtk_widget_hide (assistant->last); } +static void +compute_progress_state (GtkAssistant *assistant) +{ + GtkAssistantPrivate *priv = assistant->priv; + gint page_num, n_pages; + + n_pages = gtk_assistant_get_n_pages (assistant); + page_num = gtk_assistant_get_current_page (assistant); + + page_num = (priv->forward_function) (page_num, priv->forward_function_data); + + if (page_num >= 0 && page_num < n_pages) + gtk_widget_show (assistant->forward); + else + gtk_widget_hide (assistant->forward); +} + static void set_assistant_header_image (GtkAssistant *assistant) { @@ -509,7 +528,6 @@ set_assistant_buttons_state (GtkAssistant *assistant) gtk_widget_set_sensitive (assistant->cancel, TRUE); gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete); gtk_widget_grab_default (assistant->forward); - gtk_widget_show (assistant->cancel); gtk_widget_show (assistant->forward); gtk_widget_hide (assistant->back); gtk_widget_hide (assistant->apply); @@ -521,7 +539,6 @@ set_assistant_buttons_state (GtkAssistant *assistant) gtk_widget_set_sensitive (assistant->back, TRUE); gtk_widget_set_sensitive (assistant->apply, priv->current_page->complete); gtk_widget_grab_default (assistant->apply); - gtk_widget_show (assistant->cancel); gtk_widget_show (assistant->back); gtk_widget_show (assistant->apply); gtk_widget_hide (assistant->forward); @@ -533,7 +550,6 @@ set_assistant_buttons_state (GtkAssistant *assistant) gtk_widget_set_sensitive (assistant->back, TRUE); gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete); gtk_widget_grab_default (assistant->forward); - gtk_widget_show (assistant->cancel); gtk_widget_show (assistant->back); gtk_widget_show (assistant->forward); gtk_widget_hide (assistant->apply); @@ -544,7 +560,6 @@ set_assistant_buttons_state (GtkAssistant *assistant) gtk_widget_set_sensitive (assistant->close, priv->current_page->complete); gtk_widget_grab_default (assistant->close); gtk_widget_show (assistant->close); - gtk_widget_hide (assistant->cancel); gtk_widget_hide (assistant->back); gtk_widget_hide (assistant->forward); gtk_widget_hide (assistant->apply); @@ -555,17 +570,23 @@ set_assistant_buttons_state (GtkAssistant *assistant) gtk_widget_set_sensitive (assistant->back, priv->current_page->complete); gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete); gtk_widget_grab_default (assistant->forward); - gtk_widget_show (assistant->cancel); gtk_widget_show (assistant->back); - gtk_widget_show (assistant->forward); gtk_widget_hide (assistant->apply); gtk_widget_hide (assistant->close); gtk_widget_hide (assistant->last); + compute_progress_state (assistant); break; default: g_assert_not_reached (); } + if (priv->committed) + gtk_widget_hide (assistant->cancel); + else if (priv->current_page->type == GTK_ASSISTANT_PAGE_SUMMARY) + gtk_widget_hide (assistant->cancel); + else + gtk_widget_show (assistant->cancel); + /* this is quite general, we don't want to * go back if it's the first page */ if (!priv->visited_pages) @@ -2259,6 +2280,35 @@ gtk_assistant_update_buttons_state (GtkAssistant *assistant) set_assistant_buttons_state (assistant); } +/** + * gtk_assistant_commit: + * @assistant: a #GtkAssistant + * + * Erases the visited page history so the back button is not + * shown on the current page, and removes the cancel button + * from subsequent pages. + * + * Use this when the information provided up to the current + * page is hereafter deemed permanent and cannot be modified + * or undone. For example, showing a progress page to track + * a long-running, unreversible operation after the user has + * clicked apply on a confirmation page. + * + * Since: 2.22 + **/ +void +gtk_assistant_commit (GtkAssistant *assistant) +{ + g_return_if_fail (GTK_IS_ASSISTANT (assistant)); + + g_slist_free (assistant->priv->visited_pages); + assistant->priv->visited_pages = NULL; + + assistant->priv->committed = TRUE; + + set_assistant_buttons_state (assistant); +} + /* accessible implementation */ diff --git a/gtk/gtkassistant.h b/gtk/gtkassistant.h index 5f26325bfa..766b9d0eec 100644 --- a/gtk/gtkassistant.h +++ b/gtk/gtkassistant.h @@ -57,7 +57,8 @@ G_BEGIN_DECLS * used to handle buttons sensitivity and visibility. * * Note that an assistant needs to end its page flow with a page of type - * %GTK_ASSISTANT_PAGE_CONFIRM or %GTK_ASSISTANT_PAGE_SUMMARY to be correct. + * %GTK_ASSISTANT_PAGE_CONFIRM, %GTK_ASSISTANT_PAGE_SUMMARY or + * %GTK_ASSISTANT_PAGE_PROGRESS to be correct. */ typedef enum { @@ -168,6 +169,7 @@ void gtk_assistant_remove_action_widget (GtkAssistant GtkWidget *child); void gtk_assistant_update_buttons_state (GtkAssistant *assistant); +void gtk_assistant_commit (GtkAssistant *assistant); G_END_DECLS