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