void
gb_view_stack_remove (GbViewStack *self,
                      GbView      *view)
{
  GtkWidget *controls;
  GtkWidget *focus_after_close = NULL;

  g_assert (GB_IS_VIEW_STACK (self));
  g_assert (GB_IS_VIEW (view));

  focus_after_close = g_list_nth_data (self->focus_history, 1);
  if (focus_after_close != NULL)
    g_object_ref (focus_after_close);

  gb_view_stack_remove_list_row (self, view);

  self->focus_history = g_list_remove (self->focus_history, view);
  controls = gb_view_get_controls (view);
  if (controls)
    gtk_container_remove (GTK_CONTAINER (self->controls_stack), controls);
  gtk_container_remove (GTK_CONTAINER (self->stack), GTK_WIDGET (view));

  if (focus_after_close != NULL)
    {
      gtk_stack_set_visible_child (self->stack, focus_after_close);
      gtk_widget_grab_focus (GTK_WIDGET (focus_after_close));
      g_clear_object (&focus_after_close);
    }
  else
    g_signal_emit (self, gSignals [EMPTY], 0);
}
static void
gb_command_provider_set_active_view (GbCommandProvider *provider,
                                    GbView             *tab)
{
  GbCommandProviderPrivate *priv = gb_command_provider_get_instance_private (provider);

  g_return_if_fail (GB_IS_COMMAND_PROVIDER (provider));
  g_return_if_fail (!tab || GB_IS_VIEW (tab));

  if (priv->active_view)
    {
      g_object_remove_weak_pointer (G_OBJECT (priv->active_view),
                                    (gpointer *)&priv->active_view);
      priv->active_view = NULL;
    }

  if (tab)
    {
      priv->active_view = tab;
      g_object_add_weak_pointer (G_OBJECT (priv->active_view),
                                 (gpointer *)&priv->active_view);
    }

  g_object_notify_by_pspec (G_OBJECT (provider),
                            gParamSpecs [PROP_ACTIVE_VIEW]);
}
static void
gb_view_stack_remove_list_row (GbViewStack *self,
                               GbView      *child)
{
  GList *children;
  GList *iter;

  g_assert (GB_IS_VIEW_STACK (self));
  g_assert (GB_IS_VIEW (child));

  children = gtk_container_get_children (GTK_CONTAINER (self->views_listbox));

  for (iter = children; iter; iter = iter->next)
    {
      GbView *view = g_object_get_data (iter->data, "GB_VIEW");

      if (view == child)
        {
          gtk_container_remove (GTK_CONTAINER (self->views_listbox), iter->data);
          break;
        }
    }

  g_list_free (children);
}
GtkWidget *
gb_view_stack_find_with_document (GbViewStack *self,
                                  GbDocument  *document)
{
  GtkWidget *ret = NULL;
  GList *iter;
  GList *children;

  g_return_val_if_fail (GB_IS_VIEW_STACK (self), NULL);
  g_return_val_if_fail (GB_IS_DOCUMENT (document), NULL);

  children = gtk_container_get_children (GTK_CONTAINER (self->stack));

  for (iter = children; iter; iter = iter->next)
    {
      GbView *view = iter->data;
      GbDocument *item;

      g_assert (GB_IS_VIEW (view));

      item = gb_view_get_document (view);

      if (item == document)
        {
          ret = GTK_WIDGET (view);
          break;
        }
    }

  g_list_free (children);

  return ret;
}
void
gb_view_stack_add (GtkContainer *container,
                   GtkWidget    *child)
{
  GbViewStack *self = (GbViewStack *)container;

  g_assert (GB_IS_VIEW_STACK (self));

  if (GB_IS_VIEW (child))
    {
      GtkWidget *controls;

      gtk_widget_set_sensitive (GTK_WIDGET (self->close_button), TRUE);
      gtk_widget_set_sensitive (GTK_WIDGET (self->document_button), TRUE);
      gtk_widget_set_visible (GTK_WIDGET (self->views_button), TRUE);

      self->focus_history = g_list_prepend (self->focus_history, child);
      controls = gb_view_get_controls (GB_VIEW (child));
      if (controls)
        gtk_container_add (GTK_CONTAINER (self->controls_stack), controls);
      gtk_container_add (GTK_CONTAINER (self->stack), child);
      gb_view_set_back_forward_list (GB_VIEW (child), self->back_forward_list);
      gb_view_stack_add_list_row (self, GB_VIEW (child));
      gtk_stack_set_visible_child (self->stack, child);
    }
  else
    {
      GTK_CONTAINER_CLASS (gb_view_stack_parent_class)->add (container, child);
    }
}
static void
gb_view_stack_move_top_list_row (GbViewStack *self,
                                 GbView      *view)
{
  GList *children;
  GList *iter;

  g_assert (GB_IS_VIEW_STACK (self));
  g_assert (GB_IS_VIEW (view));

  children = gtk_container_get_children (GTK_CONTAINER (self->views_listbox));

  for (iter = children; iter; iter = iter->next)
    {
      GtkWidget *row = iter->data;
      GbView *item = g_object_get_data (G_OBJECT (row), "GB_VIEW");

      if (item == view)
        {
          g_object_ref (row);
          gtk_container_remove (GTK_CONTAINER (self->views_listbox), row);
          gtk_list_box_prepend (self->views_listbox, row);
          gtk_list_box_select_row (self->views_listbox, GTK_LIST_BOX_ROW (row));
          g_object_unref (row);
          break;
        }
    }

  g_list_free (children);
}
static void
on_workbench_set_focus (GbCommandProvider *provider,
                        GtkWidget         *widget,
                        GbWorkbench       *workbench)
{
  g_return_if_fail (GB_IS_COMMAND_PROVIDER (provider));
  g_return_if_fail (GB_IS_WORKBENCH (workbench));
  g_return_if_fail (!widget || GTK_IS_WIDGET (widget));

  /* walk the hierarchy to find a tab */
  if (widget)
    while (!GB_IS_VIEW (widget))
      if (!(widget = gtk_widget_get_parent (widget)))
        break;

  if (GB_IS_VIEW (widget))
    gb_command_provider_set_active_view (provider,
                                         GB_VIEW (widget));
}
void
gb_view_stack_raise_document (GbViewStack *self,
                              GbDocument  *document,
                              gboolean     focus)
{
  GtkWidget *view;

  g_return_if_fail (GB_IS_VIEW_STACK (self));
  g_return_if_fail (GB_IS_DOCUMENT (document));

  view = gb_view_stack_find_with_document (self, document);

  if (view != NULL && GB_IS_VIEW (view))
    {
      gb_view_stack_set_active_view (self, view);
      if (focus)
        gtk_widget_grab_focus (view);
      return;
    }

  view = gb_document_create_view (document);

  if (view == NULL)
    {
      g_warning ("Document %s failed to create a view",
                 gb_document_get_title (document));
      return;
    }

  if (!GB_IS_VIEW (view))
    {
      g_warning ("Document %s did not create a GbView instance.",
                 gb_document_get_title (document));
      return;
    }

  gb_view_stack_add (GTK_CONTAINER (self), view);
  gb_view_stack_set_active_view (self, view);

  if (focus)
    gtk_widget_grab_focus (view);
}
static void
gb_view_stack_real_remove (GtkContainer *container,
                           GtkWidget    *child)
{
  GbViewStack *self = (GbViewStack *)container;

  g_assert (GB_IS_VIEW_STACK (self));

  if (GB_IS_VIEW (child))
    gb_view_stack_remove (self, GB_VIEW (child));
  else
    GTK_CONTAINER_CLASS (gb_view_stack_parent_class)->remove (container, child);
}
static void
gb_editor_view_set_back_forward_list (GbView             *view,
                                      IdeBackForwardList *back_forward_list)
{
  GbEditorView *self = (GbEditorView *)view;

  g_assert (GB_IS_VIEW (view));
  g_assert (IDE_IS_BACK_FORWARD_LIST (back_forward_list));

  g_object_set (self->frame1, "back-forward-list", back_forward_list, NULL);
  if (self->frame2)
    g_object_set (self->frame2, "back-forward-list", back_forward_list, NULL);
}
static void
gb_view_stack_add_list_row (GbViewStack *self,
                            GbView      *child)
{
  GtkWidget *row;
  GtkWidget *label;
  GtkWidget *box;

  g_assert (GB_IS_VIEW_STACK (self));
  g_assert (GB_IS_VIEW (child));

  row = g_object_new (GTK_TYPE_LIST_BOX_ROW,
                      "visible", TRUE,
                      NULL);
  g_object_set_data (G_OBJECT (row), "GB_VIEW", child);

  box = g_object_new (GTK_TYPE_BOX,
                      "orientation", GTK_ORIENTATION_HORIZONTAL,
                      "visible", TRUE,
                      NULL);
  gtk_container_add (GTK_CONTAINER (row), box);

  label = g_object_new (GTK_TYPE_LABEL,
                        "margin-bottom", 3,
                        "margin-end", 6,
                        "margin-start", 6,
                        "margin-top", 3,
                        "visible", TRUE,
                        "xalign", 0.0f,
                        NULL);
  g_object_bind_property (child, "title", label, "label", G_BINDING_SYNC_CREATE);
  gtk_container_add (GTK_CONTAINER (box), label);

  label = g_object_new (GTK_TYPE_LABEL,
                        "visible", FALSE,
                        "label", "•",
                        "margin-start", 3,
                        "margin-end", 3,
                        NULL);
  g_object_bind_property (child, "modified", label, "visible", G_BINDING_SYNC_CREATE);
  gtk_container_add (GTK_CONTAINER (box), label);

  gtk_container_add (GTK_CONTAINER (self->views_listbox), row);
}
static void
gb_view_stack__views_listbox_row_activated_cb (GbViewStack   *self,
                                               GtkListBoxRow *row,
                                               GtkListBox    *list_box)
{
  GbView *view;

  g_assert (GB_IS_VIEW_STACK (self));
  g_assert (GTK_IS_LIST_BOX_ROW (row));
  g_assert (GTK_IS_LIST_BOX (list_box));

  view = g_object_get_data (G_OBJECT (row), "GB_VIEW");

  if (GB_IS_VIEW (view))
    {
      gtk_widget_hide (GTK_WIDGET (self->views_popover));
      gb_view_stack_set_active_view (self, GTK_WIDGET (view));
      gtk_widget_grab_focus (GTK_WIDGET (view));
    }
}
void
gb_view_stack_set_active_view (GbViewStack *self,
                               GtkWidget   *active_view)
{
  g_return_if_fail (GB_IS_VIEW_STACK (self));
  g_return_if_fail (!active_view || GB_IS_VIEW (active_view));

  if (self->destroyed)
    return;

  if (self->active_view != active_view)
    {
      if (self->active_view)
        {
          if (self->title_binding)
            g_binding_unbind (self->title_binding);
          ide_clear_weak_pointer (&self->title_binding);
          if (self->modified_binding)
            g_binding_unbind (self->modified_binding);
          ide_clear_weak_pointer (&self->modified_binding);
          gtk_label_set_label (self->title_label, NULL);
          ide_clear_weak_pointer (&self->active_view);
          gtk_widget_hide (GTK_WIDGET (self->controls_stack));
        }

      if (active_view)
        {
          GtkWidget *controls;
          GBinding *binding;
          GActionGroup *group;

          ide_set_weak_pointer (&self->active_view, active_view);
          if (active_view != gtk_stack_get_visible_child (self->stack))
            gtk_stack_set_visible_child (self->stack, active_view);

          self->focus_history = g_list_remove (self->focus_history, active_view);
          self->focus_history = g_list_prepend (self->focus_history, active_view);

          binding = g_object_bind_property (active_view, "title",
                                            self->title_label, "label",
                                            G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
          ide_set_weak_pointer (&self->title_binding, binding);

          binding = g_object_bind_property (active_view, "modified",
                                            self->modified_label, "visible",
                                            G_BINDING_SYNC_CREATE);
          ide_set_weak_pointer (&self->modified_binding, binding);

          controls = gb_view_get_controls (GB_VIEW (active_view));
          if (controls)
            {
              gtk_stack_set_visible_child (self->controls_stack, controls);
              gtk_widget_show (GTK_WIDGET (self->controls_stack));
            }

          group = gtk_widget_get_action_group (active_view, "view");
          if (group)
            gtk_widget_insert_action_group (GTK_WIDGET (self), "view", group);

          gb_view_stack_move_top_list_row (self, GB_VIEW (active_view));
        }

      g_object_notify_by_pspec (G_OBJECT (self), gParamSpecs [PROP_ACTIVE_VIEW]);
    }
}