]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkassistant.c
Merge branch 'native-layout-incubator'
[~andy/gtk] / gtk / gtkassistant.c
index b7ed75641d3ed91e351061de9afbc0055bdb4e62..97caaa0ad715ba8f8b0fea915b3ad5d094bfe328 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/**
+ * SECTION:gtkassistant
+ * @Short_description: A widget used to guide users through multi-step operations
+ * @Title: GtkAssistant
+ *
+ * A #GtkAssistant is a widget used to represent a generally complex
+ * operation splitted in several steps, guiding the user through its pages
+ * and controlling the page flow to collect the necessary data.
+ *
+ * <refsect2 id="GtkAssistant-BUILDER-UI">
+ * <title>GtkAssistant as GtkBuildable</title>
+ * <para>
+ * The GtkAssistant implementation of the GtkBuildable interface exposes the
+ * @action_area as internal children with the name "action_area".
+ *
+ * To add pages to an assistant in GtkBuilder, simply add it as a
+ * &lt;child&gt; to the GtkAssistant object, and set its child properties
+ * as necessary.
+ * </para>
+ * </refsect2>
+ */
+
 #include "config.h"
 
 #include <atk/atk.h>
@@ -55,7 +77,8 @@ struct _GtkAssistantPage
 {
   GtkWidget *page;
   GtkAssistantPageType type;
-  gboolean   complete;
+  guint      complete : 1;
+  guint      complete_set : 1;
 
   GtkWidget *title;
   GdkPixbuf *header_image;
@@ -136,6 +159,8 @@ static void       gtk_assistant_buildable_custom_finished    (GtkBuildable  *bui
                                                               const gchar   *tagname,
                                                               gpointer       user_data);
 
+static GList*     find_page                                  (GtkAssistant  *assistant,
+                                                              GtkWidget     *page);
 
 enum
 {
@@ -234,7 +259,7 @@ gtk_assistant_class_init (GtkAssistantClass *class)
 
   /**
    * GtkAssistant::apply:
-   * @assistant: the @GtkAssistant
+   * @assistant: the #GtkAssistant
    *
    * The ::apply signal is emitted when the apply button is clicked. The default
    * behavior of the #GtkAssistant is to switch to the page after the current
@@ -397,7 +422,7 @@ default_forward_function (gint current_page, gpointer data)
 
   page_info = (GtkAssistantPage *) page_node->data;
 
-  while (page_node && !GTK_WIDGET_VISIBLE (page_info->page))
+  while (page_node && !gtk_widget_get_visible (page_info->page))
     {
       page_node = page_node->next;
       current_page++;
@@ -483,6 +508,7 @@ set_assistant_buttons_state (GtkAssistant *assistant)
     case GTK_ASSISTANT_PAGE_INTRO:
       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);
@@ -494,6 +520,7 @@ set_assistant_buttons_state (GtkAssistant *assistant)
       gtk_widget_set_sensitive (assistant->cancel, TRUE);
       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);
@@ -505,6 +532,7 @@ set_assistant_buttons_state (GtkAssistant *assistant)
       gtk_widget_set_sensitive (assistant->cancel, TRUE);
       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);
@@ -513,7 +541,8 @@ set_assistant_buttons_state (GtkAssistant *assistant)
       compute_last_button_state (assistant);
       break;
     case GTK_ASSISTANT_PAGE_SUMMARY:
-      gtk_widget_set_sensitive (assistant->close, TRUE);
+      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);
@@ -525,6 +554,7 @@ set_assistant_buttons_state (GtkAssistant *assistant)
       gtk_widget_set_sensitive (assistant->cancel, priv->current_page->complete);
       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);
@@ -550,7 +580,7 @@ set_current_page (GtkAssistant     *assistant,
   GtkAssistantPage *old_page;
 
   if (priv->current_page &&
-      GTK_WIDGET_DRAWABLE (priv->current_page->page))
+      gtk_widget_is_drawable (priv->current_page->page))
     old_page = priv->current_page;
   else
     old_page = NULL;
@@ -563,14 +593,14 @@ set_current_page (GtkAssistant     *assistant,
 
   g_signal_emit (assistant, signals [PREPARE], 0, priv->current_page->page);
 
-  if (GTK_WIDGET_VISIBLE (priv->current_page->page) && GTK_WIDGET_MAPPED (assistant))
+  if (gtk_widget_get_visible (priv->current_page->page) && gtk_widget_get_mapped (GTK_WIDGET (assistant)))
     {
       gtk_widget_set_child_visible (priv->current_page->page, TRUE);
       gtk_widget_map (priv->current_page->page);
       gtk_widget_map (priv->current_page->title);
     }
   
-  if (old_page && GTK_WIDGET_MAPPED (old_page->page))
+  if (old_page && gtk_widget_get_mapped (old_page->page))
     {
       gtk_widget_set_child_visible (old_page->page, FALSE);
       gtk_widget_unmap (old_page->page);
@@ -591,7 +621,7 @@ set_current_page (GtkAssistant     *assistant,
       button[5] = assistant->last;
       for (i = 0; i < 6; i++)
         {
-          if (GTK_WIDGET_VISIBLE (button[i]) && GTK_WIDGET_SENSITIVE (button[i]))
+          if (gtk_widget_get_visible (button[i]) && gtk_widget_get_sensitive (button[i]))
             {
               gtk_widget_grab_focus (button[i]);
               break;
@@ -640,10 +670,10 @@ on_assistant_apply (GtkWidget    *widget,
 {
   gboolean success;
 
-  success = compute_next_step (assistant);
-
   g_signal_emit (assistant, signals [APPLY], 0);
 
+  success = compute_next_step (assistant);
+
   /* if the assistant hasn't switched to another page, just emit
    * the CLOSE signal, it't the last page in the assistant flow
    */
@@ -680,7 +710,7 @@ on_assistant_back (GtkWidget    *widget,
       g_slist_free_1 (page_node);
     }
   while (page_info->type == GTK_ASSISTANT_PAGE_PROGRESS ||
-        !GTK_WIDGET_VISIBLE (page_info->page));
+        !gtk_widget_get_visible (page_info->page));
 
   set_current_page (assistant, page_info);
 }
@@ -752,6 +782,9 @@ gtk_assistant_init (GtkAssistant *assistant)
   assistant->back    = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
   assistant->cancel  = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
   assistant->last    = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
+  gtk_widget_set_can_default (assistant->close, TRUE);
+  gtk_widget_set_can_default (assistant->apply, TRUE);
+  gtk_widget_set_can_default (assistant->forward, TRUE);
 
   priv->size_group   = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
   gtk_size_group_add_widget (priv->size_group, assistant->close);
@@ -888,7 +921,7 @@ on_page_notify_visibility (GtkWidget  *widget,
   GtkAssistant *assistant = GTK_ASSISTANT (data);
 
   /* update buttons state, flow may have changed */
-  if (GTK_WIDGET_MAPPED (assistant))
+  if (gtk_widget_get_mapped (GTK_WIDGET (assistant)))
     set_assistant_buttons_state (assistant);
 }
 
@@ -912,7 +945,7 @@ remove_page (GtkAssistant *assistant,
           */
          page_node = priv->pages;
 
-         while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
+         while (page_node && !gtk_widget_get_visible (((GtkAssistantPage *) page_node->data)->page))
            page_node = page_node->next;
 
           if (page_node == element)
@@ -1134,13 +1167,14 @@ gtk_assistant_size_request (GtkWidget      *widget,
   requisition->height = height;
 }
 
+
 static void
 gtk_assistant_size_allocate (GtkWidget      *widget,
                             GtkAllocation  *allocation)
 {
   GtkAssistant *assistant = GTK_ASSISTANT (widget);
   GtkAssistantPrivate *priv = assistant->priv;
-  GtkRequisition header_requisition;
+  GtkRequisition header_requisition, action_requisition, sidebar_requisition;
   GtkAllocation child_allocation, header_allocation;
   gint header_padding, content_padding;
   gboolean rtl;
@@ -1167,24 +1201,28 @@ gtk_assistant_size_allocate (GtkWidget      *widget,
   gtk_widget_size_allocate (priv->header_image, &header_allocation);
 
   /* Action area */
+  gtk_widget_get_child_requisition (priv->action_area, &action_requisition);
+
   child_allocation.x = GTK_CONTAINER (widget)->border_width;
   child_allocation.y = allocation->height -
-    GTK_CONTAINER (widget)->border_width - priv->action_area->requisition.height;
+    GTK_CONTAINER (widget)->border_width - action_requisition.height;
   child_allocation.width  = allocation->width - 2 * GTK_CONTAINER (widget)->border_width;
-  child_allocation.height = priv->action_area->requisition.height;
+  child_allocation.height = action_requisition.height;
 
   gtk_widget_size_allocate (priv->action_area, &child_allocation);
 
   /* Sidebar */
+  gtk_widget_get_child_requisition (priv->sidebar_image, &sidebar_requisition);
+
   if (rtl)
     child_allocation.x = allocation->width -
-      GTK_CONTAINER (widget)->border_width - priv->sidebar_image->requisition.width;
+      GTK_CONTAINER (widget)->border_width - sidebar_requisition.width;
   else
     child_allocation.x = GTK_CONTAINER (widget)->border_width;
 
   child_allocation.y = GTK_CONTAINER (widget)->border_width +
     priv->header_image->allocation.height + 2 * header_padding;
-  child_allocation.width = priv->sidebar_image->requisition.width;
+  child_allocation.width = sidebar_requisition.width;
   child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
     priv->header_image->allocation.height - 2 * header_padding - priv->action_area->allocation.height;
 
@@ -1198,7 +1236,7 @@ gtk_assistant_size_allocate (GtkWidget      *widget,
   child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
     priv->header_image->allocation.height - 2 * header_padding - ACTION_AREA_SPACING - priv->action_area->allocation.height - 2 * content_padding;
 
-  if (GTK_WIDGET_VISIBLE (priv->sidebar_image))
+  if (gtk_widget_get_visible (priv->sidebar_image))
     {
       if (!rtl)
        child_allocation.x += priv->sidebar_image->allocation.width;
@@ -1222,41 +1260,34 @@ gtk_assistant_map (GtkWidget *widget)
   GtkAssistant *assistant = GTK_ASSISTANT (widget);
   GtkAssistantPrivate *priv = assistant->priv;
   GList *page_node;
+  GtkAssistantPage *page;
 
-  GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
+  gtk_widget_set_mapped (widget, TRUE);
 
   gtk_widget_map (priv->header_image);
   gtk_widget_map (priv->action_area);
 
-  if (GTK_WIDGET_VISIBLE (priv->sidebar_image) &&
-      !GTK_WIDGET_MAPPED (priv->sidebar_image))
+  if (gtk_widget_get_visible (priv->sidebar_image) &&
+      !gtk_widget_get_mapped (priv->sidebar_image))
     gtk_widget_map (priv->sidebar_image);
 
   /* if there's no default page, pick the first one */
-  if (!priv->current_page && priv->pages)
+  page = NULL;
+  if (!priv->current_page)
     {
       page_node = priv->pages;
 
-      while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
+      while (page_node && !gtk_widget_get_visible (((GtkAssistantPage *) page_node->data)->page))
        page_node = page_node->next;
 
       if (page_node)
-       priv->current_page = page_node->data;
+       page = page_node->data;
     }
 
-  if (priv->current_page &&
-      GTK_WIDGET_VISIBLE (priv->current_page->page) &&
-      !GTK_WIDGET_MAPPED (priv->current_page->page))
-    {
-      set_assistant_buttons_state ((GtkAssistant *) widget);
-      set_assistant_header_image ((GtkAssistant*) widget);
-      set_assistant_sidebar_image ((GtkAssistant*) widget);
-
-      g_signal_emit (widget, signals [PREPARE], 0, priv->current_page->page);
-      gtk_widget_set_child_visible (priv->current_page->page, TRUE);
-      gtk_widget_map (priv->current_page->page);
-      gtk_widget_map (priv->current_page->title);
-    }
+  if (page &&
+      gtk_widget_get_visible (page->page) &&
+      !gtk_widget_get_mapped (page->page))
+    set_current_page (assistant, page);
 
   GTK_WIDGET_CLASS (gtk_assistant_parent_class)->map (widget);
 }
@@ -1267,16 +1298,16 @@ gtk_assistant_unmap (GtkWidget *widget)
   GtkAssistant *assistant = GTK_ASSISTANT (widget);
   GtkAssistantPrivate *priv = assistant->priv;
 
-  GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
+  gtk_widget_set_mapped (widget, FALSE);
 
   gtk_widget_unmap (priv->header_image);
   gtk_widget_unmap (priv->action_area);
 
-  if (GTK_WIDGET_DRAWABLE (priv->sidebar_image))
+  if (gtk_widget_is_drawable (priv->sidebar_image))
     gtk_widget_unmap (priv->sidebar_image);
 
   if (priv->current_page &&
-      GTK_WIDGET_DRAWABLE (priv->current_page->page))
+      gtk_widget_is_drawable (priv->current_page->page))
     gtk_widget_unmap (priv->current_page->page);
 
   g_slist_free (priv->visited_pages);
@@ -1334,7 +1365,7 @@ assistant_paint_colored_box (GtkWidget *widget)
   content_x = content_padding + border_width;
   content_width = widget->allocation.width - 2 * content_padding - 2 * border_width;
 
-  if (GTK_WIDGET_VISIBLE (priv->sidebar_image))
+  if (gtk_widget_get_visible (priv->sidebar_image))
     {
       if (!rtl)
        content_x += priv->sidebar_image->allocation.width;
@@ -1362,7 +1393,7 @@ gtk_assistant_expose (GtkWidget      *widget,
   GtkAssistantPrivate *priv = assistant->priv;
   GtkContainer *container;
 
-  if (GTK_WIDGET_DRAWABLE (widget))
+  if (gtk_widget_is_drawable (widget))
     {
       container = GTK_CONTAINER (widget);
 
@@ -1550,7 +1581,7 @@ gtk_assistant_set_current_page (GtkAssistant *assistant,
   if (page_num >= 0)
     page = (GtkAssistantPage *) g_list_nth_data (priv->pages, page_num);
   else
-    page = (GtkAssistantPage *) g_list_last (priv->pages);
+    page = (GtkAssistantPage *) g_list_last (priv->pages)->data;
 
   g_return_if_fail (page != NULL);
 
@@ -1562,7 +1593,7 @@ gtk_assistant_set_current_page (GtkAssistant *assistant,
    * initial page setting, for the cases where the
    * initial page is != to 0
    */
-  if (GTK_WIDGET_MAPPED (assistant))
+  if (gtk_widget_get_mapped (GTK_WIDGET (assistant)))
     priv->visited_pages = g_slist_prepend (priv->visited_pages,
                                           priv->current_page);
 
@@ -1611,10 +1642,14 @@ gtk_assistant_get_nth_page (GtkAssistant *assistant,
   GList *elem;
 
   g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
+  g_return_val_if_fail (page_num >= -1, NULL);
 
   priv = assistant->priv;
 
-  elem = g_list_nth (priv->pages, page_num);
+  if (page_num == -1)
+    elem = g_list_last (priv->pages);
+  else
+    elem = g_list_nth (priv->pages, page_num);
 
   if (!elem)
     return NULL;
@@ -1691,7 +1726,7 @@ gtk_assistant_insert_page (GtkAssistant *assistant,
   g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
   g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
   g_return_val_if_fail (page->parent == NULL, 0);
-  g_return_val_if_fail (!GTK_WIDGET_TOPLEVEL (page), 0);
+  g_return_val_if_fail (!gtk_widget_is_toplevel (page), 0);
 
   priv = assistant->priv;
 
@@ -1718,7 +1753,7 @@ gtk_assistant_insert_page (GtkAssistant *assistant,
   gtk_widget_set_parent (page_info->page,  GTK_WIDGET (assistant));
   gtk_widget_set_parent (page_info->title, GTK_WIDGET (assistant));
 
-  if (GTK_WIDGET_REALIZED (GTK_WIDGET (assistant)))
+  if (gtk_widget_get_realized (GTK_WIDGET (assistant)))
     {
       gtk_widget_realize (page_info->page);
       gtk_widget_realize (page_info->title);
@@ -1732,7 +1767,7 @@ gtk_assistant_insert_page (GtkAssistant *assistant,
 /**
  * gtk_assistant_set_forward_page_func:
  * @assistant: a #GtkAssistant
- * @page_func: the #GtkAssistantPageFunc, or %NULL to use the default one
+ * @page_func: (allow-none): the #GtkAssistantPageFunc, or %NULL to use the default one
  * @data: user data for @page_func
  * @destroy: destroy notifier for @data
  *
@@ -1927,6 +1962,13 @@ gtk_assistant_set_page_type (GtkAssistant         *assistant,
     {
       page_info->type = type;
 
+      /* backwards compatibility to the era before fixing bug 604289 */
+      if (type == GTK_ASSISTANT_PAGE_SUMMARY && !page_info->complete_set)
+        {
+          gtk_assistant_set_page_complete (assistant, page, TRUE);
+          page_info->complete_set = FALSE;
+        }
+
       /* Always set buttons state, a change in a future page
         might change current page buttons */
       set_assistant_buttons_state (assistant);
@@ -1969,8 +2011,8 @@ gtk_assistant_get_page_type (GtkAssistant *assistant,
  * gtk_assistant_set_page_header_image:
  * @assistant: a #GtkAssistant
  * @page: a page of @assistant
- * @pixbuf: the new header image @page
- * 
+ * @pixbuf: (allow-none): the new header image @page
+ *
  * Sets a header image for @page. This image is displayed in the header
  * area of the assistant when @page is the current page.
  *
@@ -2049,8 +2091,8 @@ gtk_assistant_get_page_header_image (GtkAssistant *assistant,
  * gtk_assistant_set_page_side_image:
  * @assistant: a #GtkAssistant
  * @page: a page of @assistant
- * @pixbuf: the new header image @page
- * 
+ * @pixbuf: (allow-none): the new header image @page
+ *
  * Sets a header image for @page. This image is displayed in the side
  * area of the assistant when @page is the current page.
  *
@@ -2158,6 +2200,7 @@ gtk_assistant_set_page_complete (GtkAssistant *assistant,
   if (complete != page_info->complete)
     {
       page_info->complete = complete;
+      page_info->complete_set = TRUE;
 
       /* Always set buttons state, a change in a future page
         might change current page buttons */