gnome-control-center/panels/online-accounts/cc-online-accounts-add-account-dialog.c
Debarshi Ray 7509af9d22 online-accounts: Don't scroll single entry lists
Create the scrolled window with vertical scrolling turned off. Turn it
on when there are more than one items in the list.

Note that the immediate parent of the list is a GtkViewport, so we
need to explicitly look for the GtkScrolledWindow.

https://bugzilla.gnome.org/show_bug.cgi?id=745584
2015-03-22 07:59:46 +01:00

479 lines
16 KiB
C

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2012, 2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
* Author: Debarshi Ray <debarshir@gnome.org>
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#define GOA_API_IS_SUBJECT_TO_CHANGE
#define GOA_BACKEND_API_IS_SUBJECT_TO_CHANGE
#include <goabackend/goabackend.h>
#include "shell/list-box-helper.h"
#include "cc-online-accounts-add-account-dialog.h"
#define BRANDED_PAGE "_branded"
#define OTHER_PAGE "_other"
struct _GoaPanelAddAccountDialogPrivate
{
GtkListBox *branded_list_box;
GtkListBox *contacts_list_box;
GtkListBox *mail_list_box;
GtkListBox *chat_list_box;
GtkListBox *ticketing_list_box;
GError *error;
GoaClient *client;
GoaObject *object;
GoaProvider *provider;
GtkListStore *list_store;
GtkWidget *contacts_grid;
GtkWidget *mail_grid;
GtkWidget *chat_grid;
GtkWidget *ticketing_grid;
GtkWidget *stack;
gboolean add_other;
};
#define GOA_ADD_ACCOUNT_DIALOG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOA_TYPE_PANEL_ADD_ACCOUNT_DIALOG, GoaPanelAddAccountDialogPrivate))
enum
{
PROP_0,
PROP_CLIENT,
};
enum
{
COLUMN_PROVIDER,
COLUMN_ICON,
COLUMN_MARKUP,
N_COLUMNS
};
G_DEFINE_TYPE (GoaPanelAddAccountDialog, goa_panel_add_account_dialog, GTK_TYPE_DIALOG)
static void
add_account_dialog_add_account (GoaPanelAddAccountDialog *add_account,
GoaProvider *provider)
{
GoaPanelAddAccountDialogPrivate *priv = add_account->priv;
GtkWidget *vbox;
vbox = gtk_dialog_get_content_area (GTK_DIALOG (add_account));
gtk_container_foreach (GTK_CONTAINER (vbox), (GtkCallback) gtk_widget_destroy, NULL);
/* This spins gtk_dialog_run() */
priv->object = goa_provider_add_account (provider,
priv->client,
GTK_DIALOG (add_account),
GTK_BOX (vbox),
&priv->error);
}
static void
list_box_row_activated_cb (GoaPanelAddAccountDialog *add_account, GtkListBoxRow *row)
{
GoaProvider *provider;
provider = g_object_get_data (G_OBJECT (row), "provider");
if (provider == NULL)
{
gtk_stack_set_visible_child_name (GTK_STACK (add_account->priv->stack), OTHER_PAGE);
return;
}
add_account_dialog_add_account (add_account, provider);
}
static void
add_account_dialog_create_group_ui (GoaPanelAddAccountDialog *add_account,
GtkListBox **list_box,
GtkWidget **group_grid,
GtkWidget *page_grid,
const gchar *name)
{
GtkWidget *label;
GtkWidget *sw;
gchar *markup;
*group_grid = gtk_grid_new ();
gtk_widget_set_no_show_all (*group_grid, TRUE);
gtk_orientable_set_orientation (GTK_ORIENTABLE (*group_grid), GTK_ORIENTATION_VERTICAL);
gtk_grid_set_row_spacing (GTK_GRID (*group_grid), 6);
gtk_container_add (GTK_CONTAINER (page_grid), *group_grid);
markup = g_strdup_printf ("<b>%s</b>", name);
label = gtk_label_new (NULL);
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_hexpand (label, TRUE);
gtk_label_set_markup (GTK_LABEL (label), markup);
gtk_container_add (GTK_CONTAINER (*group_grid), label);
g_free (markup);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_set_hexpand (sw, TRUE);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (*group_grid), sw);
*list_box = GTK_LIST_BOX (gtk_list_box_new ());
gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (*list_box));
gtk_list_box_set_selection_mode (*list_box, GTK_SELECTION_NONE);
gtk_list_box_set_header_func (*list_box, cc_list_box_update_header_func, NULL, NULL);
g_signal_connect_swapped (*list_box, "row-activated",
G_CALLBACK (list_box_row_activated_cb), add_account);
}
static void
add_account_dialog_create_provider_ui (GoaPanelAddAccountDialog *add_account,
GoaProvider *provider,
GtkListBox *list_box)
{
GIcon *icon;
GList *children;
GtkWidget *row;
GtkWidget *row_grid;
GtkWidget *image;
GtkWidget *label;
gchar *markup;
gchar *name;
row = gtk_list_box_row_new ();
row_grid = gtk_grid_new ();
gtk_orientable_set_orientation (GTK_ORIENTABLE (row_grid), GTK_ORIENTATION_HORIZONTAL);
gtk_grid_set_column_spacing (GTK_GRID (row_grid), 6);
gtk_container_add (GTK_CONTAINER (row), row_grid);
if (provider == NULL)
{
g_object_set_data (G_OBJECT (row), "provider", NULL);
icon = g_themed_icon_new_with_default_fallbacks ("goa-account");
name = g_strdup (C_("Online Account", "Other"));
}
else
{
g_object_set_data_full (G_OBJECT (row), "provider", g_object_ref (provider), g_object_unref);
icon = goa_provider_get_provider_icon (provider, NULL);
name = goa_provider_get_provider_name (provider, NULL);
}
children = gtk_container_get_children (GTK_CONTAINER (list_box));
if (children != NULL)
{
/* FIXME: Ideally we want the list boxes to use as much space as
* it's available to try to show all the content, but GtkScrolledView
* ignores its child's natural size,
* see https://bugzilla.gnome.org/show_bug.cgi?id=660654
* For now we just make list boxes with multiple children expand as
* the result is quite similar. For those with only one child,
* we turn off the scrolling. */
GtkWidget *sw;
sw = gtk_widget_get_ancestor (GTK_WIDGET (list_box), GTK_TYPE_SCROLLED_WINDOW);
g_assert_nonnull (sw);
gtk_widget_set_vexpand (sw, TRUE);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
g_list_free (children);
}
gtk_container_add (GTK_CONTAINER (list_box), row);
image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_DIALOG);
gtk_container_add (GTK_CONTAINER (row_grid), image);
markup = g_strdup_printf ("<b>%s</b>", name);
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), markup);
gtk_container_add (GTK_CONTAINER (row_grid), label);
g_free (markup);
g_free (name);
g_object_unref (icon);
}
static void
goa_panel_add_account_dialog_realize (GtkWidget *widget)
{
GoaPanelAddAccountDialog *add_account = GOA_PANEL_ADD_ACCOUNT_DIALOG (widget);
GtkWindow *parent;
parent = gtk_window_get_transient_for (GTK_WINDOW (add_account));
if (parent != NULL)
{
gint width;
gint height;
gtk_window_get_size (parent, &width, &height);
gtk_widget_set_size_request (GTK_WIDGET (add_account), (gint) (0.5 * width), (gint) (1.25 * height));
}
GTK_WIDGET_CLASS (goa_panel_add_account_dialog_parent_class)->realize (widget);
}
static void
goa_panel_add_account_dialog_dispose (GObject *object)
{
GoaPanelAddAccountDialog *add_account = GOA_PANEL_ADD_ACCOUNT_DIALOG (object);
GoaPanelAddAccountDialogPrivate *priv = add_account->priv;
g_clear_object (&priv->object);
g_clear_object (&priv->client);
g_clear_object (&priv->provider);
G_OBJECT_CLASS (goa_panel_add_account_dialog_parent_class)->dispose (object);
}
static void
goa_panel_add_account_dialog_finalize (GObject *object)
{
GoaPanelAddAccountDialog *add_account = GOA_PANEL_ADD_ACCOUNT_DIALOG (object);
GoaPanelAddAccountDialogPrivate *priv = add_account->priv;
g_clear_error (&priv->error);
G_OBJECT_CLASS (goa_panel_add_account_dialog_parent_class)->finalize (object);
}
static void
goa_panel_add_account_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GoaPanelAddAccountDialog *add_account = GOA_PANEL_ADD_ACCOUNT_DIALOG (object);
GoaPanelAddAccountDialogPrivate *priv = add_account->priv;
switch (prop_id)
{
case PROP_CLIENT:
priv->client = GOA_CLIENT (g_value_dup_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
goa_panel_add_account_dialog_init (GoaPanelAddAccountDialog *add_account)
{
GoaPanelAddAccountDialogPrivate *priv;
GtkWidget *sw;
GtkWidget *vbox;
GtkWidget *grid;
add_account->priv = GOA_ADD_ACCOUNT_DIALOG_GET_PRIVATE (add_account);
priv = add_account->priv;
gtk_container_set_border_width (GTK_CONTAINER (add_account), 6);
gtk_window_set_modal (GTK_WINDOW (add_account), TRUE);
gtk_window_set_resizable (GTK_WINDOW (add_account), FALSE);
/* translators: This is the title of the "Add Account" dialog. */
gtk_window_set_title (GTK_WINDOW (add_account), _("Add Account"));
vbox = gtk_dialog_get_content_area (GTK_DIALOG (add_account));
grid = gtk_grid_new ();
gtk_container_set_border_width (GTK_CONTAINER (grid), 5);
gtk_widget_set_margin_bottom (grid, 6);
gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL);
gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
gtk_container_add (GTK_CONTAINER (vbox), grid);
priv->list_store = gtk_list_store_new (N_COLUMNS, GOA_TYPE_PROVIDER, G_TYPE_ICON, G_TYPE_STRING);
priv->stack = gtk_stack_new ();
gtk_stack_set_transition_type (GTK_STACK (priv->stack), GTK_STACK_TRANSITION_TYPE_CROSSFADE);
gtk_container_add (GTK_CONTAINER (grid), priv->stack);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
gtk_widget_set_hexpand (sw, TRUE);
gtk_widget_set_vexpand (sw, TRUE);
gtk_stack_add_named (GTK_STACK (priv->stack), sw, BRANDED_PAGE);
priv->branded_list_box = GTK_LIST_BOX (gtk_list_box_new ());
gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (priv->branded_list_box));
gtk_list_box_set_selection_mode (priv->branded_list_box, GTK_SELECTION_NONE);
gtk_list_box_set_header_func (priv->branded_list_box, cc_list_box_update_header_func, NULL, NULL);
g_signal_connect_swapped (priv->branded_list_box, "row-activated",
G_CALLBACK (list_box_row_activated_cb), add_account);
grid = gtk_grid_new ();
gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL);
gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
gtk_stack_add_named (GTK_STACK (priv->stack), grid, OTHER_PAGE);
add_account_dialog_create_group_ui (add_account,
&priv->mail_list_box,
&priv->mail_grid,
grid,
_("Mail"));
add_account_dialog_create_group_ui (add_account,
&priv->contacts_list_box,
&priv->contacts_grid,
grid,
_("Contacts"));
add_account_dialog_create_group_ui (add_account,
&priv->chat_list_box,
&priv->chat_grid,
grid,
_("Chat"));
add_account_dialog_create_group_ui (add_account,
&priv->ticketing_list_box,
&priv->ticketing_grid,
grid,
_("Resources"));
gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), BRANDED_PAGE);
}
static void
goa_panel_add_account_dialog_class_init (GoaPanelAddAccountDialogClass *klass)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
object_class = G_OBJECT_CLASS (klass);
object_class->dispose = goa_panel_add_account_dialog_dispose;
object_class->finalize = goa_panel_add_account_dialog_finalize;
object_class->set_property = goa_panel_add_account_dialog_set_property;
widget_class = GTK_WIDGET_CLASS (klass);
widget_class->realize = goa_panel_add_account_dialog_realize;
g_type_class_add_private (object_class, sizeof (GoaPanelAddAccountDialogPrivate));
g_object_class_install_property (object_class,
PROP_CLIENT,
g_param_spec_object ("client",
"Goa Client",
"A Goa client for talking to the Goa daemon.",
GOA_TYPE_CLIENT,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
}
GtkWidget *
goa_panel_add_account_dialog_new (GoaClient *client)
{
return g_object_new (GOA_TYPE_PANEL_ADD_ACCOUNT_DIALOG, "client", client, "use-header-bar", TRUE, NULL);
}
void
goa_panel_add_account_dialog_set_preseed_data (GoaPanelAddAccountDialog *add_account,
GoaProvider *provider,
GVariant *preseed)
{
GoaPanelAddAccountDialogPrivate *priv = add_account->priv;
g_clear_object (&priv->provider);
if (provider != NULL)
{
priv->provider = g_object_ref (provider);
goa_provider_set_preseed_data (provider, preseed);
}
}
void
goa_panel_add_account_dialog_add_provider (GoaPanelAddAccountDialog *add_account, GoaProvider *provider)
{
GoaPanelAddAccountDialogPrivate *priv = add_account->priv;
GtkListBox *list_box;
GoaProviderGroup group;
GtkWidget *group_grid = NULL;
g_return_if_fail (provider != NULL);
group = goa_provider_get_provider_group (provider);
/* The list of providers returned by GOA are sorted such that all
* the branded providers are at the beginning of the list, followed
* by the others. Since this is the order in which they are added,
* we can rely on this fact, which helps to simplify the code.
*/
if (group != GOA_PROVIDER_GROUP_BRANDED && !priv->add_other)
{
add_account_dialog_create_provider_ui (add_account, NULL, priv->branded_list_box);
priv->add_other = TRUE;
}
switch (group)
{
case GOA_PROVIDER_GROUP_BRANDED:
list_box = priv->branded_list_box;
break;
case GOA_PROVIDER_GROUP_CONTACTS:
group_grid = priv->contacts_grid;
list_box = priv->contacts_list_box;
break;
case GOA_PROVIDER_GROUP_MAIL:
group_grid = priv->mail_grid;
list_box = priv->mail_list_box;
break;
case GOA_PROVIDER_GROUP_CHAT:
group_grid = priv->chat_grid;
list_box = priv->chat_list_box;
break;
case GOA_PROVIDER_GROUP_TICKETING:
group_grid = priv->ticketing_grid;
list_box = priv->ticketing_list_box;
break;
default:
g_assert_not_reached ();
break;
}
add_account_dialog_create_provider_ui (add_account, provider, list_box);
if (group_grid != NULL)
{
gtk_widget_set_no_show_all (group_grid, FALSE);
gtk_widget_show_all (group_grid);
}
}
void
goa_panel_add_account_dialog_run (GoaPanelAddAccountDialog *add_account)
{
GoaPanelAddAccountDialogPrivate *priv = add_account->priv;
if (priv->provider != NULL)
add_account_dialog_add_account (add_account, priv->provider);
else
gtk_dialog_run (GTK_DIALOG (add_account));
}
GoaObject *
goa_panel_add_account_dialog_get_account (GoaPanelAddAccountDialog *add_account, GError **error)
{
GoaPanelAddAccountDialogPrivate *priv = add_account->priv;
if (error != NULL && priv->error != NULL)
*error = g_error_copy (priv->error);
if (priv->object != NULL)
g_object_ref (priv->object);
return priv->object;
}