[libhandy] tab-view: Add hdy_tab_view_add_page()



commit 56426a718a6657ed1b73393e7cd02cafcf3adc10
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Tue Feb 2 14:38:27 2021 +0500

    tab-view: Add hdy_tab_view_add_page()
    
    Support a parent->child relationship between pages, position new pages and
    manage behavior after closing the selected page based on that.
    
    Fixes https://gitlab.gnome.org/GNOME/libhandy/-/issues/408

 debian/libhandy-1-0.symbols |   2 +
 src/hdy-tab-view.c          | 265 ++++++++++++++++++++++++++++++++++++++++----
 src/hdy-tab-view.h          |   8 ++
 tests/test-tab-view.c       | 170 +++++++++++++++++++++++++++-
 4 files changed, 421 insertions(+), 24 deletions(-)
---
diff --git a/debian/libhandy-1-0.symbols b/debian/libhandy-1-0.symbols
index 72426339..72363c3c 100644
--- a/debian/libhandy-1-0.symbols
+++ b/debian/libhandy-1-0.symbols
@@ -355,6 +355,7 @@ libhandy-1.so.0 libhandy-1-0 #MINVER#
  hdy_tab_page_get_pinned@LIBHANDY_1_0 1.1.0
  hdy_tab_page_get_indicator_activatable@LIBHANDY_1_0 1.1.0
  hdy_tab_page_get_indicator_icon@LIBHANDY_1_0 1.1.0
+ hdy_tab_page_get_parent@LIBHANDY_1_0 1.1.0
  hdy_tab_page_get_selected@LIBHANDY_1_0 1.1.0
  hdy_tab_page_get_title@LIBHANDY_1_0 1.1.0
  hdy_tab_page_get_tooltip@LIBHANDY_1_0 1.1.0
@@ -366,6 +367,7 @@ libhandy-1.so.0 libhandy-1-0 #MINVER#
  hdy_tab_page_set_indicator_icon@LIBHANDY_1_0 1.1.0
  hdy_tab_page_set_title@LIBHANDY_1_0 1.1.0
  hdy_tab_page_set_tooltip@LIBHANDY_1_0 1.1.0
+ hdy_tab_view_add_page@LIBHANDY_1_0 1.1.0
  hdy_tab_view_append@LIBHANDY_1_0 1.1.0
  hdy_tab_view_append_pinned@LIBHANDY_1_0 1.1.0
  hdy_tab_view_close_other_pages@LIBHANDY_1_0 1.1.0
diff --git a/src/hdy-tab-view.c b/src/hdy-tab-view.c
index 7810d46b..f0e4fc14 100644
--- a/src/hdy-tab-view.c
+++ b/src/hdy-tab-view.c
@@ -64,6 +64,7 @@ struct _HdyTabPage
   GObject parent_instance;
 
   GtkWidget *child;
+  HdyTabPage *parent;
   gboolean selected;
   gboolean pinned;
   gchar *title;
@@ -82,6 +83,7 @@ G_DEFINE_TYPE (HdyTabPage, hdy_tab_page, G_TYPE_OBJECT)
 enum {
   PAGE_PROP_0,
   PAGE_PROP_CHILD,
+  PAGE_PROP_PARENT,
   PAGE_PROP_SELECTED,
   PAGE_PROP_PINNED,
   PAGE_PROP_TITLE,
@@ -174,6 +176,57 @@ set_page_pinned (HdyTabPage *self,
   g_object_notify_by_pspec (G_OBJECT (self), page_props[PAGE_PROP_PINNED]);
 }
 
+static void set_page_parent (HdyTabPage *self,
+                             HdyTabPage *parent);
+
+static void
+page_parent_notify_cb (HdyTabPage *self)
+{
+  HdyTabPage *grandparent = hdy_tab_page_get_parent (self->parent);
+
+  self->parent = NULL;
+
+  if (grandparent)
+    set_page_parent (self, grandparent);
+  else
+    g_object_notify_by_pspec (G_OBJECT (self), props[PAGE_PROP_PARENT]);
+}
+
+static void
+set_page_parent (HdyTabPage *self,
+                 HdyTabPage *parent)
+{
+  g_return_if_fail (HDY_IS_TAB_PAGE (self));
+  g_return_if_fail (HDY_IS_TAB_PAGE (parent) || parent == NULL);
+
+  if (self->parent == parent)
+    return;
+
+  if (self->parent)
+    g_object_weak_unref (G_OBJECT (self->parent),
+                         (GWeakNotify) page_parent_notify_cb,
+                         self);
+
+  self->parent = parent;
+
+  if (self->parent)
+    g_object_weak_ref (G_OBJECT (self->parent),
+                       (GWeakNotify) page_parent_notify_cb,
+                       self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PAGE_PROP_PARENT]);
+}
+
+static void
+hdy_tab_page_dispose (GObject *object)
+{
+  HdyTabPage *self = HDY_TAB_PAGE (object);
+
+  set_page_parent (self, NULL);
+
+  G_OBJECT_CLASS (hdy_tab_page_parent_class)->dispose (object);
+}
+
 static void
 hdy_tab_page_finalize (GObject *object)
 {
@@ -201,6 +254,10 @@ hdy_tab_page_get_property (GObject    *object,
     g_value_set_object (value, hdy_tab_page_get_child (self));
     break;
 
+  case PAGE_PROP_PARENT:
+    g_value_set_object (value, hdy_tab_page_get_parent (self));
+    break;
+
   case PAGE_PROP_SELECTED:
     g_value_set_boolean (value, hdy_tab_page_get_selected (self));
     break;
@@ -255,6 +312,10 @@ hdy_tab_page_set_property (GObject      *object,
     g_set_object (&self->child, g_value_get_object (value));
     break;
 
+  case PAGE_PROP_PARENT:
+    set_page_parent (self, g_value_get_object (value));
+    break;
+
   case PAGE_PROP_TITLE:
     hdy_tab_page_set_title (self, g_value_get_string (value));
     break;
@@ -293,6 +354,7 @@ hdy_tab_page_class_init (HdyTabPageClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
+  object_class->dispose = hdy_tab_page_dispose;
   object_class->finalize = hdy_tab_page_finalize;
   object_class->get_property = hdy_tab_page_get_property;
   object_class->set_property = hdy_tab_page_set_property;
@@ -311,6 +373,22 @@ hdy_tab_page_class_init (HdyTabPageClass *klass)
                          GTK_TYPE_WIDGET,
                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
 
+  /**
+   * HdyTabPage:parent:
+   *
+   * The parent page of the page.
+   *
+   * See hdy_tab_view_add_page() and hdy_tab_view_close_page().
+
+   * Since: 1.1
+   */
+  page_props[PAGE_PROP_PARENT] =
+    g_param_spec_object ("parent",
+                         _("Parent"),
+                         _("The parent page of the page"),
+                         HDY_TYPE_TAB_PAGE,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
+
   /**
    * HdyTabPage:selected:
    *
@@ -545,12 +623,33 @@ set_n_pinned_pages (HdyTabView *self,
   g_object_notify_by_pspec (G_OBJECT (self), props[PROP_N_PINNED_PAGES]);
 }
 
+static inline gboolean
+page_belongs_to_this_view (HdyTabView *self,
+                           HdyTabPage *page)
+{
+  if (!page)
+    return FALSE;
+
+  return gtk_widget_get_parent (page->child) == GTK_WIDGET (self->stack);
+}
+
+static inline gboolean
+is_descendant_of (HdyTabPage *page,
+                  HdyTabPage *parent)
+{
+  while (page && page != parent)
+    page = hdy_tab_page_get_parent (page);
+
+  return page == parent;
+}
+
 static void
 attach_page (HdyTabView *self,
              HdyTabPage *page,
              gint        position)
 {
   GtkWidget *child = hdy_tab_page_get_child (page);
+  HdyTabPage *parent;
 
   g_list_store_insert (self->pages, position, page);
 
@@ -568,20 +667,64 @@ attach_page (HdyTabView *self,
 
   g_object_thaw_notify (G_OBJECT (self));
 
+  parent = hdy_tab_page_get_parent (page);
+
+  if (parent && !page_belongs_to_this_view (self, parent))
+    set_page_parent (page, NULL);
+
   g_signal_emit (self, signals[SIGNAL_PAGE_ATTACHED], 0, page, position);
 }
 
+static void
+select_previous_page (HdyTabView *self,
+                      HdyTabPage *page)
+{
+  gint pos = hdy_tab_view_get_page_position (self, page);
+  HdyTabPage *parent;
+
+  if (page != self->selected_page)
+    return;
+
+  parent = hdy_tab_page_get_parent (page);
+
+  if (parent && pos > 0) {
+    HdyTabPage *prev_page = hdy_tab_view_get_nth_page (self, pos - 1);
+
+    /* This usually means we opened a few pages from the same page in a row, or
+     * the previous page is the parent. Switch there. */
+    if (is_descendant_of (prev_page, parent)) {
+      hdy_tab_view_set_selected_page (self, prev_page);
+
+      return;
+    }
+
+    /* Pinned pages are special in that opening a page from a pinned parent
+     * will place it not directly after the parent, but after the last pinned
+     * page. This means that if we're closing the first non-pinned page, we need
+     * to jump to the parent directly instead of the previous page which might
+     * be different. */
+    if (hdy_tab_page_get_pinned (prev_page) &&
+        hdy_tab_page_get_pinned (parent)) {
+      hdy_tab_view_set_selected_page (self, parent);
+
+      return;
+    }
+  }
+
+  if (hdy_tab_view_select_next_page (self))
+    return;
+
+  hdy_tab_view_select_previous_page (self);
+}
+
 static void
 detach_page (HdyTabView *self,
              HdyTabPage *page)
 {
   gint pos = hdy_tab_view_get_page_position (self, page);
   GtkWidget *child;
-  gboolean deselect;
 
-  deselect = page == self->selected_page &&
-             !hdy_tab_view_select_next_page (self) &&
-             !hdy_tab_view_select_previous_page (self);
+  select_previous_page (self, page);
 
   child = hdy_tab_page_get_child (page);
 
@@ -597,7 +740,7 @@ detach_page (HdyTabView *self,
   if (hdy_tab_page_get_pinned (page))
     set_n_pinned_pages (self, self->n_pinned_pages - 1);
 
-  if (deselect)
+  if (self->n_pages == 0)
     hdy_tab_view_set_selected_page (self, NULL);
 
   g_object_thaw_notify (G_OBJECT (self));
@@ -613,11 +756,15 @@ detach_page (HdyTabView *self,
 static HdyTabPage *
 insert_page (HdyTabView *self,
              GtkWidget  *child,
+             HdyTabPage *parent,
              gint        position,
              gboolean    pinned)
 {
   g_autoptr (HdyTabPage) page =
-    g_object_new (HDY_TYPE_TAB_PAGE, "child", child, NULL);
+    g_object_new (HDY_TYPE_TAB_PAGE,
+                  "child", child,
+                  "parent", parent,
+                  NULL);
 
   set_page_pinned (page, pinned);
 
@@ -820,16 +967,6 @@ shortcut_key_press_cb (HdyTabView  *self,
   return GDK_EVENT_PROPAGATE;
 }
 
-static inline gboolean
-page_belongs_to_this_view (HdyTabView *self,
-                           HdyTabPage *page)
-{
-  if (!page)
-    return FALSE;
-
-  return gtk_widget_get_parent (page->child) == GTK_WIDGET (self->stack);
-}
-
 static void
 shortcut_widget_notify_cb (HdyTabView *self)
 {
@@ -1339,6 +1476,26 @@ hdy_tab_page_get_child (HdyTabPage *self)
   return self->child;
 }
 
+/**
+ * hdy_tab_page_get_parent:
+ * @self: a #HdyTabPage
+ *
+ * Gets the parent page of @self, or %NULL if the @self does not have a parent.
+ *
+ * See hdy_tab_view_add_page() and hdy_tab_view_close_page().
+ *
+ * Returns: (transfer none) (nullable): the parent page of @self, or %NULL
+ *
+ * Since: 1.1
+ */
+HdyTabPage *
+hdy_tab_page_get_parent (HdyTabPage *self)
+{
+  g_return_val_if_fail (HDY_IS_TAB_PAGE (self), NULL);
+
+  return self->parent;
+}
+
 /**
  * hdy_tab_page_get_selected:
  * @self: a #HdyTabPage
@@ -2303,6 +2460,60 @@ hdy_tab_view_get_page_position (HdyTabView *self,
   g_assert_not_reached ();
 }
 
+/**
+ * hdy_tab_view_add_page:
+ * @self: a #HdyTabView
+ * @child: a widget to add
+ * @parent: (nullable): a parent page for @child, or %NULL
+ *
+ * Adds @child to @self with @parent as the parent.
+ *
+ * This function can be used to automatically position new pages, and to select
+ * the correct page when this page is closed while being selected (see
+ * hdy_tab_view_close_page()).
+ *
+ * If @parent is %NULL, this function is equivalent to hdy_tab_view_append().
+ *
+ * Returns: (transfer none): the page object representing @child
+ *
+ * Since: 1.1
+ */
+HdyTabPage *
+hdy_tab_view_add_page (HdyTabView *self,
+                       GtkWidget  *child,
+                       HdyTabPage *parent)
+{
+  gint position;
+
+  g_return_val_if_fail (HDY_IS_TAB_VIEW (self), NULL);
+  g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
+  g_return_val_if_fail (HDY_IS_TAB_PAGE (parent) || parent == NULL, NULL);
+
+  if (parent) {
+    HdyTabPage *page;
+
+    g_return_val_if_fail (page_belongs_to_this_view (self, parent), NULL);
+
+    if (hdy_tab_page_get_pinned (parent))
+      position = self->n_pinned_pages - 1;
+    else
+      position = hdy_tab_view_get_page_position (self, parent);
+
+    do {
+      position++;
+
+      if (position >= self->n_pages)
+        break;
+
+      page = hdy_tab_view_get_nth_page (self, position);
+    } while (is_descendant_of (page, parent));
+  } else {
+    position = self->n_pages;
+  }
+
+  return insert_page (self, child, parent, position, FALSE);
+}
+
 /**
  * hdy_tab_view_insert:
  * @self: a #HdyTabView
@@ -2328,7 +2539,7 @@ hdy_tab_view_insert (HdyTabView *self,
   g_return_val_if_fail (position >= self->n_pinned_pages, NULL);
   g_return_val_if_fail (position <= self->n_pages, NULL);
 
-  return insert_page (self, child, position, FALSE);
+  return insert_page (self, child, NULL, position, FALSE);
 }
 
 /**
@@ -2349,7 +2560,7 @@ hdy_tab_view_prepend (HdyTabView *self,
   g_return_val_if_fail (HDY_IS_TAB_VIEW (self), NULL);
   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
 
-  return insert_page (self, child, self->n_pinned_pages, FALSE);
+  return insert_page (self, child, NULL, self->n_pinned_pages, FALSE);
 }
 
 /**
@@ -2370,7 +2581,7 @@ hdy_tab_view_append (HdyTabView *self,
   g_return_val_if_fail (HDY_IS_TAB_VIEW (self), NULL);
   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
 
-  return insert_page (self, child, self->n_pages, FALSE);
+  return insert_page (self, child, NULL, self->n_pages, FALSE);
 }
 
 /**
@@ -2398,7 +2609,7 @@ hdy_tab_view_insert_pinned (HdyTabView *self,
   g_return_val_if_fail (position >= 0, NULL);
   g_return_val_if_fail (position <= self->n_pinned_pages, NULL);
 
-  return insert_page (self, child, position, TRUE);
+  return insert_page (self, child, NULL, position, TRUE);
 }
 
 /**
@@ -2419,7 +2630,7 @@ hdy_tab_view_prepend_pinned (HdyTabView *self,
   g_return_val_if_fail (HDY_IS_TAB_VIEW (self), NULL);
   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
 
-  return insert_page (self, child, 0, TRUE);
+  return insert_page (self, child, NULL, 0, TRUE);
 }
 
 /**
@@ -2440,7 +2651,7 @@ hdy_tab_view_append_pinned (HdyTabView *self,
   g_return_val_if_fail (HDY_IS_TAB_VIEW (self), NULL);
   g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
 
-  return insert_page (self, child, self->n_pinned_pages, TRUE);
+  return insert_page (self, child, NULL, self->n_pinned_pages, TRUE);
 }
 
 /**
@@ -2461,6 +2672,16 @@ hdy_tab_view_append_pinned (HdyTabView *self,
  * closing the page if it's non-pinned, or reject it if it's pinned. This
  * behavior can be changed by registering your own handler for that signal.
  *
+ * If @page was selected, another page will be selected instead:
+ *
+ * If the #HdyTabPage:parent value is %NULL, the next page will be selected when
+ * possible, or if the page was already last, the previous page will be selected
+ * instead.
+ *
+ * If it's not %NULL, the previous page will be selected if it's a
+ * descendant (possibly indirect) of the parent. If both the previous page and
+ * the parent are pinned, the parent will be selected instead.
+ *
  * Since: 1.1
  */
 void
diff --git a/src/hdy-tab-view.h b/src/hdy-tab-view.h
index 4df5c9d0..374c64c9 100644
--- a/src/hdy-tab-view.h
+++ b/src/hdy-tab-view.h
@@ -26,6 +26,9 @@ G_DECLARE_FINAL_TYPE (HdyTabPage, hdy_tab_page, HDY, TAB_PAGE, GObject)
 HDY_AVAILABLE_IN_1_1
 GtkWidget *hdy_tab_page_get_child (HdyTabPage *self);
 
+HDY_AVAILABLE_IN_1_1
+HdyTabPage *hdy_tab_page_get_parent (HdyTabPage *self);
+
 HDY_AVAILABLE_IN_1_1
 gboolean hdy_tab_page_get_selected (HdyTabPage *self);
 
@@ -136,6 +139,11 @@ HDY_AVAILABLE_IN_1_1
 gint hdy_tab_view_get_page_position (HdyTabView *self,
                                      HdyTabPage *page);
 
+HDY_AVAILABLE_IN_1_1
+HdyTabPage *hdy_tab_view_add_page (HdyTabView *self,
+                                   GtkWidget  *child,
+                                   HdyTabPage *parent);
+
 HDY_AVAILABLE_IN_1_1
 HdyTabPage *hdy_tab_view_insert  (HdyTabView *self,
                                   GtkWidget  *child,
diff --git a/tests/test-tab-view.c b/tests/test-tab-view.c
index b6457bfa..efa85743 100644
--- a/tests/test-tab-view.c
+++ b/tests/test-tab-view.c
@@ -314,7 +314,7 @@ test_hdy_tab_view_select (void)
 }
 
 static void
-test_hdy_tab_view_add_remove (void)
+test_hdy_tab_view_add_basic (void)
 {
   g_autoptr (HdyTabView) view = NULL;
   HdyTabPage *pages[6];
@@ -347,6 +347,98 @@ test_hdy_tab_view_add_remove (void)
                          3, 5, 4, 1, 2, 0);
 }
 
+static void
+test_hdy_tab_view_add_auto (void)
+{
+  g_autoptr (HdyTabView) view = NULL;
+  HdyTabPage *pages[17];
+
+  view = g_object_ref_sink (HDY_TAB_VIEW (hdy_tab_view_new ()));
+  g_assert_nonnull (view);
+
+  add_pages (view, pages, 3, 3);
+  assert_page_positions (view, pages, 3, 3,
+                         0, 1, 2);
+
+  /* No parent */
+
+  pages[3] = hdy_tab_view_add_page (view, gtk_button_new (), NULL);
+  g_assert_null (hdy_tab_page_get_parent (pages[3]));
+  assert_page_positions (view, pages, 4, 3,
+                         0, 1, 2, 3);
+
+  pages[4] = hdy_tab_view_add_page (view, gtk_button_new (), NULL);
+  g_assert_null (hdy_tab_page_get_parent (pages[4]));
+  assert_page_positions (view, pages, 5, 3,
+                         0, 1, 2, 3, 4);
+
+  pages[5] = hdy_tab_view_add_page (view, gtk_button_new (), NULL);
+  g_assert_null (hdy_tab_page_get_parent (pages[5]));
+  assert_page_positions (view, pages, 6, 3,
+                         0, 1, 2, 3, 4, 5);
+
+  /* Parent is a regular page */
+
+  pages[6] = hdy_tab_view_add_page (view, gtk_button_new (), pages[4]);
+  g_assert_true (hdy_tab_page_get_parent (pages[6]) == pages[4]);
+  assert_page_positions (view, pages, 7, 3,
+                         0, 1, 2, 3, 4, 6, 5);
+
+  pages[7] = hdy_tab_view_add_page (view, gtk_button_new (), pages[4]);
+  g_assert_true (hdy_tab_page_get_parent (pages[7]) == pages[4]);
+  assert_page_positions (view, pages, 8, 3,
+                         0, 1, 2, 3, 4, 6, 7, 5);
+
+  pages[8] = hdy_tab_view_add_page (view, gtk_button_new (), pages[6]);
+  g_assert_true (hdy_tab_page_get_parent (pages[8]) == pages[6]);
+  assert_page_positions (view, pages, 9, 3,
+                         0, 1, 2, 3, 4, 6, 8, 7, 5);
+
+  pages[9] = hdy_tab_view_add_page (view, gtk_button_new (), pages[6]);
+  g_assert_true (hdy_tab_page_get_parent (pages[9]) == pages[6]);
+  assert_page_positions (view, pages, 10, 3,
+                         0, 1, 2, 3, 4, 6, 8, 9, 7, 5);
+
+  pages[10] = hdy_tab_view_add_page (view, gtk_button_new (), pages[4]);
+  g_assert_true (hdy_tab_page_get_parent (pages[10]) == pages[4]);
+  assert_page_positions (view, pages, 11, 3,
+                         0, 1, 2, 3, 4, 6, 8, 9, 7, 10, 5);
+
+  /* Parent is a pinned page */
+
+  pages[11] = hdy_tab_view_add_page (view, gtk_button_new (), pages[1]);
+  g_assert_true (hdy_tab_page_get_parent (pages[11]) == pages[1]);
+  assert_page_positions (view, pages, 12, 3,
+                         0, 1, 2, 11, 3, 4, 6, 8, 9, 7, 10, 5);
+
+  pages[12] = hdy_tab_view_add_page (view, gtk_button_new (), pages[11]);
+  g_assert_true (hdy_tab_page_get_parent (pages[12]) == pages[11]);
+  assert_page_positions (view, pages, 13, 3,
+                         0, 1, 2, 11, 12, 3, 4, 6, 8, 9, 7, 10, 5);
+
+  pages[13] = hdy_tab_view_add_page (view, gtk_button_new (), pages[1]);
+  g_assert_true (hdy_tab_page_get_parent (pages[13]) == pages[1]);
+  assert_page_positions (view, pages, 14, 3,
+                         0, 1, 2, 11, 12, 13, 3, 4, 6, 8, 9, 7, 10, 5);
+
+  pages[14] = hdy_tab_view_add_page (view, gtk_button_new (), pages[0]);
+  g_assert_true (hdy_tab_page_get_parent (pages[14]) == pages[0]);
+  assert_page_positions (view, pages, 15, 3,
+                         0, 1, 2, 14, 11, 12, 13, 3, 4, 6, 8, 9, 7, 10, 5);
+
+  pages[15] = hdy_tab_view_add_page (view, gtk_button_new (), pages[1]);
+  g_assert_true (hdy_tab_page_get_parent (pages[15]) == pages[1]);
+  assert_page_positions (view, pages, 16, 3,
+                         0, 1, 2, 15, 14, 11, 12, 13, 3, 4, 6, 8, 9, 7, 10, 5);
+
+  /* Parent is the last page */
+
+  pages[16] = hdy_tab_view_add_page (view, gtk_button_new (), pages[5]);
+  g_assert_true (hdy_tab_page_get_parent (pages[16]) == pages[5]);
+  assert_page_positions (view, pages, 17, 3,
+                         0, 1, 2, 15, 14, 11, 12, 13, 3, 4, 6, 8, 9, 7, 10, 5, 16);
+}
+
 static void
 test_hdy_tab_view_reorder (void)
 {
@@ -693,6 +785,78 @@ test_hdy_tab_view_close_signal (void)
   g_signal_handler_disconnect (view, handler);
 }
 
+static void
+test_hdy_tab_view_close_select (void)
+{
+  g_autoptr (HdyTabView) view = NULL;
+  HdyTabPage *pages[14];
+
+  view = g_object_ref_sink (HDY_TAB_VIEW (hdy_tab_view_new ()));
+  g_assert_nonnull (view);
+
+  add_pages (view, pages, 9, 3);
+  pages[9] = hdy_tab_view_add_page (view, gtk_button_new (), pages[4]);
+  pages[10] = hdy_tab_view_add_page (view, gtk_button_new (), pages[4]);
+  pages[11] = hdy_tab_view_add_page (view, gtk_button_new (), pages[9]);
+  pages[12] = hdy_tab_view_add_page (view, gtk_button_new (), pages[1]);
+  pages[13] = hdy_tab_view_add_page (view, gtk_button_new (), pages[1]);
+
+  assert_page_positions (view, pages, 14, 3,
+                         0, 1, 2, 12, 13, 3, 4, 9, 11, 10, 5, 6, 7, 8);
+
+  /* Nothing happens when closing unselected pages */
+
+  hdy_tab_view_set_selected_page (view, pages[0]);
+
+  hdy_tab_view_close_page (view, pages[8]);
+  g_assert_true (hdy_tab_view_get_selected_page (view) == pages[0]);
+
+  /* No parent */
+
+  assert_page_positions (view, pages, 13, 3,
+                         0, 1, 2, 12, 13, 3, 4, 9, 11, 10, 5, 6, 7);
+
+  hdy_tab_view_set_selected_page (view, pages[6]);
+
+  hdy_tab_view_close_page (view, pages[6]);
+  g_assert_true (hdy_tab_view_get_selected_page (view) == pages[7]);
+
+  hdy_tab_view_close_page (view, pages[7]);
+  g_assert_true (hdy_tab_view_get_selected_page (view) == pages[5]);
+
+  /* Regular parent */
+
+  assert_page_positions (view, pages, 11, 3,
+                         0, 1, 2, 12, 13, 3, 4, 9, 11, 10, 5);
+
+  hdy_tab_view_set_selected_page (view, pages[10]);
+
+  hdy_tab_view_close_page (view, pages[10]);
+  g_assert_true (hdy_tab_view_get_selected_page (view) == pages[11]);
+
+  hdy_tab_view_close_page (view, pages[11]);
+  g_assert_true (hdy_tab_view_get_selected_page (view) == pages[9]);
+
+  hdy_tab_view_close_page (view, pages[9]);
+  g_assert_true (hdy_tab_view_get_selected_page (view) == pages[4]);
+
+  hdy_tab_view_close_page (view, pages[4]);
+  g_assert_true (hdy_tab_view_get_selected_page (view) == pages[5]);
+
+  /* Pinned parent */
+
+  assert_page_positions (view, pages, 7, 3,
+                         0, 1, 2, 12, 13, 3, 5);
+
+  hdy_tab_view_set_selected_page (view, pages[13]);
+
+  hdy_tab_view_close_page (view, pages[13]);
+  g_assert_true (hdy_tab_view_get_selected_page (view) == pages[12]);
+
+  hdy_tab_view_close_page (view, pages[12]);
+  g_assert_true (hdy_tab_view_get_selected_page (view) == pages[1]);
+}
+
 static void
 test_hdy_tab_view_transfer (void)
 {
@@ -957,7 +1121,8 @@ main (gint argc,
   g_test_add_func ("/Handy/TabView/shortcut_widget", test_hdy_tab_view_shortcut_widget);
   g_test_add_func ("/Handy/TabView/pages", test_hdy_tab_view_pages);
   g_test_add_func ("/Handy/TabView/select", test_hdy_tab_view_select);
-  g_test_add_func ("/Handy/TabView/add_remove", test_hdy_tab_view_add_remove);
+  g_test_add_func ("/Handy/TabView/add_basic", test_hdy_tab_view_add_basic);
+  g_test_add_func ("/Handy/TabView/add_auto", test_hdy_tab_view_add_auto);
   g_test_add_func ("/Handy/TabView/reorder", test_hdy_tab_view_reorder);
   g_test_add_func ("/Handy/TabView/reorder_first_last", test_hdy_tab_view_reorder_first_last);
   g_test_add_func ("/Handy/TabView/reorder_forward_backward", test_hdy_tab_view_reorder_forward_backward);
@@ -966,6 +1131,7 @@ main (gint argc,
   g_test_add_func ("/Handy/TabView/close_other", test_hdy_tab_view_close_other);
   g_test_add_func ("/Handy/TabView/close_before_after", test_hdy_tab_view_close_before_after);
   g_test_add_func ("/Handy/TabView/close_signal", test_hdy_tab_view_close_signal);
+  g_test_add_func ("/Handy/TabView/close_select", test_hdy_tab_view_close_select);
   g_test_add_func ("/Handy/TabView/transfer", test_hdy_tab_view_transfer);
   g_test_add_func ("/Handy/TabPage/title", test_hdy_tab_page_title);
   g_test_add_func ("/Handy/TabPage/tooltip", test_hdy_tab_page_tooltip);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]