]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkassistant.c
Merge branch 'button-box-orientable-584598'
[~andy/gtk] / gtk / gtkassistant.c
index bb9d03b10d420d27f256f89e6591b32e7a464f4b..b7ed75641d3ed91e351061de9afbc0055bdb4e62 100644 (file)
@@ -23,7 +23,7 @@
  * Boston, MA 02111-1307, USA.
  */
 
-#include <config.h>
+#include "config.h"
 
 #include <atk/atk.h>
 
@@ -40,6 +40,7 @@
 
 #include "gtkintl.h"
 #include "gtkprivate.h"
+#include "gtkbuildable.h"
 
 #include "gtkalias.h"
 
@@ -119,6 +120,23 @@ static void     gtk_assistant_get_child_property (GtkContainer      *container,
 
 static AtkObject *gtk_assistant_get_accessible   (GtkWidget         *widget);
 
+static void       gtk_assistant_buildable_interface_init     (GtkBuildableIface *iface);
+static GObject   *gtk_assistant_buildable_get_internal_child (GtkBuildable  *buildable,
+                                                              GtkBuilder    *builder,
+                                                              const gchar   *childname);
+static gboolean   gtk_assistant_buildable_custom_tag_start   (GtkBuildable  *buildable,
+                                                              GtkBuilder    *builder,
+                                                              GObject       *child,
+                                                              const gchar   *tagname,
+                                                              GMarkupParser *parser,
+                                                              gpointer      *data);
+static void       gtk_assistant_buildable_custom_finished    (GtkBuildable  *buildable,
+                                                              GtkBuilder    *builder,
+                                                              GObject       *child,
+                                                              const gchar   *tagname,
+                                                              gpointer       user_data);
+
+
 enum
 {
   CHILD_PROP_0,
@@ -141,7 +159,9 @@ enum
 static guint signals [LAST_SIGNAL] = { 0 };
 
 
-G_DEFINE_TYPE (GtkAssistant, gtk_assistant, GTK_TYPE_WINDOW)
+G_DEFINE_TYPE_WITH_CODE (GtkAssistant, gtk_assistant, GTK_TYPE_WINDOW,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+                                                gtk_assistant_buildable_interface_init))
 
 
 static void
@@ -197,8 +217,8 @@ gtk_assistant_class_init (GtkAssistantClass *class)
    * @assistant: the #GtkAssistant
    * @page: the current page
    *
-   * The ::prepared signal is emitted when a new page is set as the assistant's 
-   * current page, before making the new page visible. A handler for this signal 
+   * The ::prepare signal is emitted when a new page is set as the assistant's
+   * current page, before making the new page visible. A handler for this signal
    * can do any preparation which are necessary before showing @page.
    *
    * Since: 2.10
@@ -217,14 +237,14 @@ gtk_assistant_class_init (GtkAssistantClass *class)
    * @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 page,
-   * unless the current page is the last one.
+   * behavior of the #GtkAssistant is to switch to the page after the current
+   * page, unless the current page is the last one.
    *
-   * 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 after the
-   * confirmation page and handle this operation within the ::prepare signal of
-   * the progress page.
+   * 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
+   * after the confirmation page and handle this operation within the
+   * #GtkAssistant::prepare signal of the progress page.
    *
    * Since: 2.10
    */
@@ -243,7 +263,7 @@ gtk_assistant_class_init (GtkAssistantClass *class)
    *
    * The ::close signal is emitted either when the close button of
    * a summary page is clicked, or when the apply button in the last
-   * page in the flow (of type GTK_ASSISTANT_PAGE_CONFIRM) is clicked.
+   * page in the flow (of type %GTK_ASSISTANT_PAGE_CONFIRM) is clicked.
    *
    * Since: 2.10
    */
@@ -276,7 +296,7 @@ gtk_assistant_class_init (GtkAssistantClass *class)
   /**
    * GtkAssistant:page-type:
    *
-   * The type of the assistant page. 
+   * The type of the assistant page.
    *
    * Since: 2.10
    */
@@ -292,7 +312,7 @@ gtk_assistant_class_init (GtkAssistantClass *class)
   /**
    * GtkAssistant:title:
    *
-   * The title that is displayed in the page header. 
+   * The title that is displayed in the page header.
    *
    * If title and header-image are both %NULL, no header is displayed.
    *
@@ -326,7 +346,7 @@ gtk_assistant_class_init (GtkAssistantClass *class)
   /**
    * GtkAssistant:header-image:
    *
-   * The image that is displayed next to the page. 
+   * The image that is displayed next to the page.
    *
    * Set this to %NULL to make the sidebar disappear.
    *
@@ -410,14 +430,12 @@ compute_last_button_state (GtkAssistant *assistant)
       page_info = g_list_nth_data (priv->pages, page_num);
 
       count++;
-
-      g_assert (page_info);
     }
 
   /* make the last button visible if we can skip multiple
-   * pages and end on a confirmation or summary page 
+   * pages and end on a confirmation or summary page
    */
-  if (count > 1 && 
+  if (count > 1 && page_info &&
       (page_info->type == GTK_ASSISTANT_PAGE_CONFIRM ||
        page_info->type == GTK_ASSISTANT_PAGE_SUMMARY))
     {
@@ -457,6 +475,9 @@ set_assistant_buttons_state (GtkAssistant *assistant)
 {
   GtkAssistantPrivate *priv = assistant->priv;
 
+  if (!priv->current_page)
+    return;
+  
   switch (priv->current_page->type)
     {
     case GTK_ASSISTANT_PAGE_INTRO:
@@ -556,6 +577,28 @@ set_current_page (GtkAssistant     *assistant,
       gtk_widget_unmap (old_page->title);
     }
 
+  if (!gtk_widget_child_focus (priv->current_page->page, GTK_DIR_TAB_FORWARD))
+    {
+      GtkWidget *button[6];
+      gint i;
+
+      /* find the best button to focus */
+      button[0] = assistant->apply;
+      button[1] = assistant->close;
+      button[2] = assistant->forward;
+      button[3] = assistant->back;
+      button[4] = assistant->cancel;
+      button[5] = assistant->last;
+      for (i = 0; i < 6; i++)
+        {
+          if (GTK_WIDGET_VISIBLE (button[i]) && GTK_WIDGET_SENSITIVE (button[i]))
+            {
+              gtk_widget_grab_focus (button[i]);
+              break;
+            }
+        }
+    }
+
   gtk_widget_queue_resize (GTK_WIDGET (assistant));
 }
 
@@ -585,30 +628,32 @@ compute_next_step (GtkAssistant *assistant)
 }
 
 static void
-on_assistant_close (GtkWidget *widget, GtkAssistant *assistant)
+on_assistant_close (GtkWidget    *widget,
+                    GtkAssistant *assistant)
 {
   g_signal_emit (assistant, signals [CLOSE], 0, NULL);
 }
 
 static void
-on_assistant_apply (GtkWidget *widget, GtkAssistant *assistant)
+on_assistant_apply (GtkWidget    *widget,
+                    GtkAssistant *assistant)
 {
-  GtkAssistantPrivate *priv = assistant->priv;
   gboolean success;
 
   success = compute_next_step (assistant);
 
-  g_signal_emit (assistant, signals [APPLY], 0, priv->current_page->page);
+  g_signal_emit (assistant, signals [APPLY], 0);
 
   /* if the assistant hasn't switched to another page, just emit
    * the CLOSE signal, it't the last page in the assistant flow
    */
   if (!success)
-    g_signal_emit (assistant, signals [CLOSE], 0, priv->current_page->page);
+    g_signal_emit (assistant, signals [CLOSE], 0);
 }
 
 static void
-on_assistant_forward (GtkWidget *widget, GtkAssistant *assistant)
+on_assistant_forward (GtkWidget    *widget,
+                      GtkAssistant *assistant)
 {
   if (!compute_next_step (assistant))
     g_critical ("Page flow is broken, you may want to end it with a page of "
@@ -616,7 +661,8 @@ on_assistant_forward (GtkWidget *widget, GtkAssistant *assistant)
 }
 
 static void
-on_assistant_back (GtkWidget *widget, GtkAssistant *assistant)
+on_assistant_back (GtkWidget    *widget,
+                   GtkAssistant *assistant)
 {
   GtkAssistantPrivate *priv = assistant->priv;
   GtkAssistantPage *page_info;
@@ -640,13 +686,15 @@ on_assistant_back (GtkWidget *widget, GtkAssistant *assistant)
 }
 
 static void
-on_assistant_cancel (GtkWidget *widget, GtkAssistant *assistant)
+on_assistant_cancel (GtkWidget    *widget,
+                     GtkAssistant *assistant)
 {
   g_signal_emit (assistant, signals [CANCEL], 0, NULL);
 }
 
 static void
-on_assistant_last (GtkWidget *widget, GtkAssistant *assistant)
+on_assistant_last (GtkWidget    *widget,
+                   GtkAssistant *assistant)
 {
   GtkAssistantPrivate *priv = assistant->priv;
 
@@ -678,6 +726,9 @@ gtk_assistant_init (GtkAssistant *assistant)
 
   priv = assistant->priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
 
+  gtk_container_set_reallocate_redraws (GTK_CONTAINER (assistant), TRUE);
+  gtk_container_set_border_width (GTK_CONTAINER (assistant), 12);
+
   gtk_widget_push_composite_child ();
 
   /* Header */
@@ -723,10 +774,10 @@ gtk_assistant_init (GtkAssistant *assistant)
     {
       gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0);
       gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0);
-      gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0);
-      gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0);
-      gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0);
       gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0);
+      gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0);
+      gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0);
+      gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0);
     }
 
   gtk_widget_set_parent (priv->action_area, GTK_WIDGET (assistant));
@@ -847,12 +898,32 @@ remove_page (GtkAssistant *assistant,
 {
   GtkAssistantPrivate *priv = assistant->priv;
   GtkAssistantPage *page_info;
+  GList *page_node;
 
   page_info = element->data;
 
-  /* If we are mapped and visible, we want to deal with changing the page. */
-  if ((GTK_WIDGET_MAPPED (page_info->page)) && (page_info == priv->current_page))
-    compute_next_step (assistant);
+  /* If this is the current page, we need to switch away. */
+  if (page_info == priv->current_page)
+    {
+      if (!compute_next_step (assistant))
+        {
+         /* The best we can do at this point is probably to pick the first
+          * visible page.
+          */
+         page_node = priv->pages;
+
+         while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
+           page_node = page_node->next;
+
+          if (page_node == element)
+            page_node = page_node->next;
+
+         if (page_node)
+           priv->current_page = page_node->data;
+         else
+           priv->current_page = NULL;
+        }
+    }
 
   priv->pages = g_list_remove_link (priv->pages, element);
   priv->visited_pages = g_slist_remove_all (priv->visited_pages, page_info);
@@ -867,7 +938,7 @@ remove_page (GtkAssistant *assistant,
     g_object_unref (page_info->sidebar_image);
 
   gtk_widget_destroy (page_info->title);
-  g_free (page_info);
+  g_slice_free (GtkAssistantPage, page_info);
   g_list_free_1 (element);
 }
 
@@ -1088,16 +1159,16 @@ gtk_assistant_size_allocate (GtkWidget      *widget,
   /* Header */
   gtk_widget_get_child_requisition (priv->header_image, &header_requisition);
 
-  header_allocation.x = allocation->x + GTK_CONTAINER (widget)->border_width + header_padding;
-  header_allocation.y = allocation->y + GTK_CONTAINER (widget)->border_width + header_padding;
+  header_allocation.x = GTK_CONTAINER (widget)->border_width + header_padding;
+  header_allocation.y = GTK_CONTAINER (widget)->border_width + header_padding;
   header_allocation.width  = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * header_padding;
   header_allocation.height = header_requisition.height;
 
   gtk_widget_size_allocate (priv->header_image, &header_allocation);
 
   /* Action area */
-  child_allocation.x = allocation->x + GTK_CONTAINER (widget)->border_width;
-  child_allocation.y = allocation->y + allocation->height -
+  child_allocation.x = GTK_CONTAINER (widget)->border_width;
+  child_allocation.y = allocation->height -
     GTK_CONTAINER (widget)->border_width - priv->action_area->requisition.height;
   child_allocation.width  = allocation->width - 2 * GTK_CONTAINER (widget)->border_width;
   child_allocation.height = priv->action_area->requisition.height;
@@ -1106,12 +1177,12 @@ gtk_assistant_size_allocate (GtkWidget      *widget,
 
   /* Sidebar */
   if (rtl)
-    child_allocation.x = allocation->x + allocation->width -
+    child_allocation.x = allocation->width -
       GTK_CONTAINER (widget)->border_width - priv->sidebar_image->requisition.width;
   else
-    child_allocation.x = allocation->x + GTK_CONTAINER (widget)->border_width;
+    child_allocation.x = GTK_CONTAINER (widget)->border_width;
 
-  child_allocation.y = allocation->y + 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.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
@@ -1120,8 +1191,8 @@ gtk_assistant_size_allocate (GtkWidget      *widget,
   gtk_widget_size_allocate (priv->sidebar_image, &child_allocation);
 
   /* Pages */
-  child_allocation.x = allocation->x + GTK_CONTAINER (widget)->border_width + content_padding;
-  child_allocation.y = allocation->y + GTK_CONTAINER (widget)->border_width +
+  child_allocation.x = GTK_CONTAINER (widget)->border_width + content_padding;
+  child_allocation.y = GTK_CONTAINER (widget)->border_width +
     priv->header_image->allocation.height + 2 * header_padding + content_padding;
   child_allocation.width  = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * content_padding;
   child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
@@ -1355,8 +1426,6 @@ static void
 gtk_assistant_add (GtkContainer *container,
                   GtkWidget    *page)
 {
-  g_return_if_fail (GTK_IS_WIDGET (page));
-
   gtk_assistant_append_page (GTK_ASSISTANT (container), page);
 }
 
@@ -1364,11 +1433,9 @@ static void
 gtk_assistant_remove (GtkContainer *container,
                      GtkWidget    *page)
 {
-  GtkAssistant *assistant;
+  GtkAssistant *assistant = (GtkAssistant*) container;
   GList *element;
 
-  assistant = (GtkAssistant*) container;
-
   element = find_page (assistant, page);
 
   if (element)
@@ -1424,9 +1491,8 @@ gtk_assistant_new (void)
 {
   GtkWidget *assistant;
 
-  assistant = g_object_new (GTK_TYPE_ASSISTANT,
-                           "border-width", 12,
-                           NULL);
+  assistant = g_object_new (GTK_TYPE_ASSISTANT, NULL);
+
   return assistant;
 }
 
@@ -1497,7 +1563,8 @@ gtk_assistant_set_current_page (GtkAssistant *assistant,
    * initial page is != to 0
    */
   if (GTK_WIDGET_MAPPED (assistant))
-    priv->visited_pages = g_slist_prepend (priv->visited_pages, page);
+    priv->visited_pages = g_slist_prepend (priv->visited_pages,
+                                          priv->current_page);
 
   set_current_page (assistant, page);
 }
@@ -1628,7 +1695,7 @@ gtk_assistant_insert_page (GtkAssistant *assistant,
 
   priv = assistant->priv;
 
-  page_info = g_new0 (GtkAssistantPage, 1);
+  page_info = g_slice_new0 (GtkAssistantPage);
   page_info->page  = page;
   page_info->title = gtk_label_new (NULL);
 
@@ -1708,8 +1775,7 @@ gtk_assistant_set_forward_page_func (GtkAssistant         *assistant,
 
   /* Page flow has possibly changed, so the
      buttons state might need to change too */
-  if (priv->current_page)
-    set_assistant_buttons_state (assistant);
+  set_assistant_buttons_state (assistant);
 }
 
 /**
@@ -1863,8 +1929,7 @@ gtk_assistant_set_page_type (GtkAssistant         *assistant,
 
       /* Always set buttons state, a change in a future page
         might change current page buttons */
-      if (priv->current_page)
-       set_assistant_buttons_state (assistant);
+      set_assistant_buttons_state (assistant);
 
       gtk_widget_child_notify (page, "page-type");
     }
@@ -2096,8 +2161,7 @@ gtk_assistant_set_page_complete (GtkAssistant *assistant,
 
       /* Always set buttons state, a change in a future page
         might change current page buttons */
-      if (priv->current_page)
-       set_assistant_buttons_state (assistant);
+      set_assistant_buttons_state (assistant);
 
       gtk_widget_child_notify (page, "complete");
     }
@@ -2108,7 +2172,7 @@ gtk_assistant_set_page_complete (GtkAssistant *assistant,
  * @assistant: a #GtkAssistant
  * @page: a page of @assistant
  * 
- * Gets whether @page is complete..
+ * Gets whether @page is complete.
  * 
  * Return value: %TRUE if @page is complete.
  *
@@ -2187,6 +2251,7 @@ gtk_assistant_accessible_ref_child (AtkObject *accessible,
   GtkWidget *widget, *child;
   gint n_pages;
   AtkObject *obj;
+  const gchar *title;
 
   widget = GTK_ACCESSIBLE (accessible)->widget;
   if (!widget)
@@ -2200,19 +2265,24 @@ gtk_assistant_accessible_ref_child (AtkObject *accessible,
     return NULL;
   else if (index < n_pages)
     {
-      GtkAssistantPage *page = g_list_nth_data (priv->pages, index / 2);
+      GtkAssistantPage *page = g_list_nth_data (priv->pages, index);
 
       child = page->page;
+      title = gtk_assistant_get_page_title (assistant, child);
     }
   else if (index == n_pages)
     {
       child = priv->action_area;
+      title = NULL;
     }
   else
     return NULL;
   
   obj = gtk_widget_get_accessible (child);
 
+  if (title)
+    atk_object_set_name (obj, title);
+
   return g_object_ref (obj);
 }
 
@@ -2238,15 +2308,15 @@ gtk_assistant_accessible_get_type (void)
       GType derived_type;
       GTypeQuery query;
       GType derived_atk_type;
-      
+
       derived_type = g_type_parent (GTK_TYPE_ASSISTANT);
       factory = atk_registry_get_factory (atk_get_default_registry (),
                                          derived_type);
       derived_atk_type = atk_object_factory_get_accessible_type (factory);
       g_type_query (derived_atk_type, &query);
-      
-      type = g_type_register_static_simple (derived_atk_type, 
-                                           "GtkAssistantAccessible", 
+
+      type = g_type_register_static_simple (derived_atk_type,
+                                           I_("GtkAssistantAccessible"),
                                            query.class_size,
                                            (GClassInitFunc) gtk_assistant_accessible_class_init,
                                            query.instance_size,
@@ -2263,9 +2333,9 @@ gtk_assistant_accessible_new (GObject *obj)
 
   g_return_val_if_fail (GTK_IS_ASSISTANT (obj), NULL);
 
-  accessible = g_object_new (gtk_assistant_accessible_get_type (), NULL); 
+  accessible = g_object_new (gtk_assistant_accessible_get_type (), NULL);
   atk_object_initialize (accessible, obj);
-  
+
   return accessible;
 }
 
@@ -2293,16 +2363,16 @@ gtk_assistant_accessible_factory_get_type (void)
 {
   static GType type = 0;
 
-  if (!type) 
+  if (!type)
     {
-      type = g_type_register_static_simple (ATK_TYPE_OBJECT_FACTORY, 
-                                           "GtkAssistantAccessibleFactory",
+      type = g_type_register_static_simple (ATK_TYPE_OBJECT_FACTORY,
+                                           I_("GtkAssistantAccessibleFactory"),
                                            sizeof (AtkObjectFactoryClass),
                                            (GClassInitFunc) gtk_assistant_accessible_factory_class_init,
                                            sizeof (AtkObjectFactory),
                                            NULL, 0);
     }
-  
+
   return type;
 }
 
@@ -2311,12 +2381,12 @@ gtk_assistant_get_accessible (GtkWidget *widget)
 {
   static gboolean first_time = TRUE;
 
-  if (first_time) 
+  if (first_time)
     {
       AtkObjectFactory *factory;
       AtkRegistry *registry;
-      GType derived_type; 
-      GType derived_atk_type; 
+      GType derived_type;
+      GType derived_atk_type;
 
       /*
        * Figure out whether accessibility is enabled by looking at the
@@ -2331,7 +2401,7 @@ gtk_assistant_get_accessible (GtkWidget *widget)
       derived_atk_type = atk_object_factory_get_accessible_type (factory);
       if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE))
        {
-         atk_registry_set_factory_type (registry, 
+         atk_registry_set_factory_type (registry,
                                         GTK_TYPE_ASSISTANT,
                                         gtk_assistant_accessible_factory_get_type ());
        }
@@ -2342,5 +2412,53 @@ gtk_assistant_get_accessible (GtkWidget *widget)
 }
 
 
+static GtkBuildableIface *parent_buildable_iface;
+
+static void
+gtk_assistant_buildable_interface_init (GtkBuildableIface *iface)
+{
+  parent_buildable_iface = g_type_interface_peek_parent (iface);
+  iface->get_internal_child = gtk_assistant_buildable_get_internal_child;
+  iface->custom_tag_start = gtk_assistant_buildable_custom_tag_start;
+  iface->custom_finished = gtk_assistant_buildable_custom_finished;
+}
+
+static GObject *
+gtk_assistant_buildable_get_internal_child (GtkBuildable *buildable,
+                                            GtkBuilder   *builder,
+                                            const gchar  *childname)
+{
+    if (strcmp (childname, "action_area") == 0)
+      return G_OBJECT (GTK_ASSISTANT (buildable)->priv->action_area);
+
+    return parent_buildable_iface->get_internal_child (buildable,
+                                                       builder,
+                                                       childname);
+}
+
+gboolean
+gtk_assistant_buildable_custom_tag_start (GtkBuildable  *buildable,
+                                          GtkBuilder    *builder,
+                                          GObject       *child,
+                                          const gchar   *tagname,
+                                          GMarkupParser *parser,
+                                          gpointer      *data)
+{
+  return parent_buildable_iface->custom_tag_start (buildable, builder, child,
+                                                   tagname, parser, data);
+}
+
+static void
+gtk_assistant_buildable_custom_finished (GtkBuildable *buildable,
+                                         GtkBuilder   *builder,
+                                         GObject      *child,
+                                         const gchar  *tagname,
+                                         gpointer      user_data)
+{
+  parent_buildable_iface->custom_finished (buildable, builder, child,
+                                           tagname, user_data);
+}
+
+
 #define __GTK_ASSISTANT_C__
 #include "gtkaliasdef.c"