Exemplo n.º 1
0
void
glade_gtk_grid_replace_child (GladeWidgetAdaptor *adaptor,
                              GObject            *container,
                              GObject            *current,
                              GObject            *new_widget)
{
  g_return_if_fail (GTK_IS_GRID (container));
  g_return_if_fail (GTK_IS_WIDGET (current));
  g_return_if_fail (GTK_IS_WIDGET (new_widget));

  /* Chain Up */
  GWA_GET_CLASS (GTK_TYPE_CONTAINER)->replace_child (adaptor,
                                                     container,
                                                     current,
                                                     new_widget);

  /* If we are replacing a GladeWidget, we must refresh placeholders
   * because the widget may have spanned multiple rows/columns, we must
   * not do so in the case we are pasting multiple widgets into a grid,
   * where destroying placeholders results in default packing properties
   * (since the remaining placeholder templates no longer exist, only the
   * first pasted widget would have proper packing properties).
   */
  if (!GLADE_IS_PLACEHOLDER (new_widget))
    glade_gtk_grid_refresh_placeholders (GTK_GRID (container), FALSE);
}
Exemplo n.º 2
0
void
glade_gtk_grid_set_child_property (GladeWidgetAdaptor *adaptor,
                                   GObject            *container,
                                   GObject            *child,
                                   const gchar        *property_name,
                                   GValue             *value)
{
  g_return_if_fail (GTK_IS_GRID (container));
  g_return_if_fail (GTK_IS_WIDGET (child));
  g_return_if_fail (property_name != NULL && value != NULL);

  GWA_GET_CLASS
    (GTK_TYPE_CONTAINER)->child_set_property (adaptor,
                                              container, child,
                                              property_name, value);

  if (strcmp (property_name, "left-attach") == 0 ||
      strcmp (property_name, "top-attach")  == 0 ||
      strcmp (property_name, "width")       == 0 ||
      strcmp (property_name, "height")      == 0)
    {
      /* Refresh placeholders */
      glade_gtk_grid_refresh_placeholders (GTK_GRID (container), FALSE);
    }
}
Exemplo n.º 3
0
/**
 * e_webdav_discover_content_show_error:
 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
 * @error: (allow-none): a #GError to show in the UI, or %NULL
 *
 * Shows the @error within @content, unless it's a #G_IO_ERROR_CANCELLED, or %NULL,
 * which are safely ignored. The advantage of this function is that the error
 * message is removed when the refresh operation is started.
 *
 * Since: 3.18
 **/
void
e_webdav_discover_content_show_error (GtkWidget *content,
				      const GError *error)
{
	EWebDAVDiscoverContentData *data;
	GtkWidget *label;

	g_return_if_fail (GTK_IS_GRID (content));

	data = g_object_get_data (G_OBJECT (content), WEBDAV_DISCOVER_CONTENT_DATA_KEY);
	g_return_if_fail (data != NULL);

	if (data->info_bar) {
		gtk_widget_destroy (GTK_WIDGET (data->info_bar));
		data->info_bar = NULL;
	}

	if (!error || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	data->info_bar = GTK_INFO_BAR (gtk_info_bar_new ());
	gtk_info_bar_set_message_type (data->info_bar, GTK_MESSAGE_ERROR);
	gtk_info_bar_set_show_close_button (data->info_bar, TRUE);

	label = gtk_label_new (error->message);
	gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (data->info_bar)), label);
	gtk_widget_show (label);
	gtk_widget_show (GTK_WIDGET (data->info_bar));

	g_signal_connect (data->info_bar, "response", G_CALLBACK (e_webdav_discover_info_bar_error_response_cb), content);

	gtk_grid_attach (GTK_GRID (content), GTK_WIDGET (data->info_bar), 0, 2, 1, 1);
}
Exemplo n.º 4
0
/** \brief  Synchronize \a widget with its current resource value
 *
 * \param[in,out]   widget  PET video size widget
 */
void pet_video_size_widget_sync(GtkWidget *widget)
{
    GtkWidget *group;

    group = gtk_grid_get_child_at(GTK_GRID(widget), 0, 1);
    if (group != NULL && GTK_IS_GRID(group)) {
        vice_gtk3_resource_radiogroup_sync(group);
    }
}
Exemplo n.º 5
0
void
glade_gtk_grid_remove_child (GladeWidgetAdaptor *adaptor,
                             GObject            *object,
                             GObject            *child)
{
  g_return_if_fail (GTK_IS_GRID (object));
  g_return_if_fail (GTK_IS_WIDGET (child));

  gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));

  glade_gtk_grid_refresh_placeholders (GTK_GRID (object), FALSE);
}
Exemplo n.º 6
0
/**
 * e_webdav_discover_content_get_tree_selection:
 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
 *
 * Returns inner #GtkTreeViewSelection. This is meant to be able to connect
 * to its "changed" signal and update other parts of the parent widgets accordingly.
 *
 * Returns: (transfer none): inner #GtkTreeViewSelection
 *
 * Since: 3.18
 **/
GtkTreeSelection *
e_webdav_discover_content_get_tree_selection (GtkWidget *content)
{
	EWebDAVDiscoverContentData *data;

	g_return_val_if_fail (GTK_IS_GRID (content), NULL);

	data = g_object_get_data (G_OBJECT (content), WEBDAV_DISCOVER_CONTENT_DATA_KEY);
	g_return_val_if_fail (data != NULL, NULL);

	return gtk_tree_view_get_selection (data->sources_tree_view);
}
Exemplo n.º 7
0
/**
 * e_webdav_discover_content_get_selected:
 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
 * @index: an index of the selected source; counts from 0
 * @out_href: (out): an output location for the URL of the selected source
 * @out_supports: (out): an output location of a bit-or of #EWebDAVDiscoverSupports, the set
 *    of source types this server source location supports
 * @out_display_name: (out): an output location of the sources display name
 * @out_color: (out): an output location of the string representation of the color
 *    for the source, as set on the server
 *
 * Returns information about selected source at index @index. The function can be called
 * multiple times, with the index starting at zero and as long as it doesn't return %FALSE.
 * If the @content doesn't have allowed multiselection, then the only valid @index is 0.
 *
 * All the @out_href, @out_display_name and @out_color are newly allocated strings, which should
 * be freed with g_free(), when no longer needed.
 *
 * Returns: %TRUE, when a selected source of index @index exists, %FALSE otherwise.
 *
 * Since: 3.18
 **/
gboolean
e_webdav_discover_content_get_selected (GtkWidget *content,
					gint index,
					gchar **out_href,
					guint *out_supports,
					gchar **out_display_name,
					gchar **out_color)
{
	EWebDAVDiscoverContentData *data;
	GtkTreeSelection *selection;
	GtkTreeModel *model = NULL;
	GList *selected_rows, *link;
	gboolean success = FALSE;

	g_return_val_if_fail (GTK_IS_GRID (content), FALSE);
	g_return_val_if_fail (index >= 0, FALSE);
	g_return_val_if_fail (out_href != NULL, FALSE);
	g_return_val_if_fail (out_supports != NULL, FALSE);
	g_return_val_if_fail (out_display_name != NULL, FALSE);
	g_return_val_if_fail (out_color != NULL, FALSE);

	data = g_object_get_data (G_OBJECT (content), WEBDAV_DISCOVER_CONTENT_DATA_KEY);
	g_return_val_if_fail (data != NULL, FALSE);

	selection = gtk_tree_view_get_selection (data->sources_tree_view);
	selected_rows = gtk_tree_selection_get_selected_rows (selection, &model);

	for (link = selected_rows; link && index > 0; link = g_list_next (link)) {
		index--;
	}

	if (index == 0 && link) {
		GtkTreePath *path = link->data;

		if (path) {
			GtkTreeIter iter;

			success = gtk_tree_model_get_iter (model, &iter, path);
			if (success) {
				gtk_tree_model_get (model, &iter,
					COL_HREF_STRING, out_href,
					COL_SUPPORTS_UINT, out_supports,
					COL_DISPLAY_NAME_STRING, out_display_name,
					COL_COLOR_STRING, out_color,
					-1);
			}
		}
	}

	g_list_free_full (selected_rows, (GDestroyNotify) gtk_tree_path_free);

	return success;
}
Exemplo n.º 8
0
/**
 * e_webdav_discover_content_get_base_url:
 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
 *
 * Returns currently set base URL for the @content. This is used to overwrite the one
 * set on the #ESource from the creation time. The URL can be either a full URL, a path
 * or even a %NULL.
 *
 * Returns: currently set base URL for the @content.
 *
 * Since: 3.18
 **/
const gchar *
e_webdav_discover_content_get_base_url (GtkWidget *content)
{
	EWebDAVDiscoverContentData *data;

	g_return_val_if_fail (GTK_IS_GRID (content), NULL);

	data = g_object_get_data (G_OBJECT (content), WEBDAV_DISCOVER_CONTENT_DATA_KEY);
	g_return_val_if_fail (data != NULL, NULL);

	return data->base_url;
}
Exemplo n.º 9
0
GList *
glade_gtk_grid_get_children (GladeWidgetAdaptor *adaptor, 
                             GtkContainer       *container)
{
  GList *children = NULL;

  g_return_val_if_fail (GTK_IS_GRID (container), NULL);

  gtk_container_forall (container, gtk_grid_children_callback, &children);

  /* GtkGrid has the children list already reversed */
  return children;
}
Exemplo n.º 10
0
/**
 * e_webdav_discover_content_get_multiselect:
 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
 *
 * Returns: whether multiselect is allowed for the @content.
 *
 * Since: 3.18
 **/
gboolean
e_webdav_discover_content_get_multiselect (GtkWidget *content)
{
	EWebDAVDiscoverContentData *data;
	GtkTreeSelection *selection;

	g_return_val_if_fail (GTK_IS_GRID (content), FALSE);

	data = g_object_get_data (G_OBJECT (content), WEBDAV_DISCOVER_CONTENT_DATA_KEY);
	g_return_val_if_fail (data != NULL, FALSE);

	selection = gtk_tree_view_get_selection (data->sources_tree_view);
	return gtk_tree_selection_get_mode (selection) == GTK_SELECTION_MULTIPLE;
}
Exemplo n.º 11
0
/**
 * gel_ui_container_replace_children:
 * @container: A #GtkContainer
 * @widget: (transfer full): A #GtkWidget
 *
 * Removes all children from @container using gel_ui_container_clear() and
 * then packs @widget into @container
 */
void
gel_ui_container_replace_children(GtkContainer *container, GtkWidget *widget)
{
	g_return_if_fail(GTK_IS_CONTAINER(container));
	g_return_if_fail(GTK_IS_WIDGET(widget));

	gtk_container_foreach(container, (GtkCallback) gtk_widget_destroy, NULL);
	if (GTK_IS_BOX(container))
		gtk_box_pack_start(GTK_BOX(container), widget, TRUE, TRUE, 0);
	else if (GTK_IS_GRID(container))
	{
		gtk_grid_attach(GTK_GRID(container), widget, 0, 0, 1, 1);
		g_object_set((GObject *) widget, "hexpand", TRUE, "vexpand", TRUE, NULL);
	}
}
Exemplo n.º 12
0
static void
e_webdav_discover_info_bar_error_response_cb (GtkInfoBar *info_bar,
					      gint response_id,
					      GtkWidget *content)
{
	EWebDAVDiscoverContentData *data;

	g_return_if_fail (GTK_IS_GRID (content));

	data = g_object_get_data (G_OBJECT (content), WEBDAV_DISCOVER_CONTENT_DATA_KEY);
	g_return_if_fail (data != NULL);

	if (data->info_bar == info_bar) {
		gtk_widget_destroy (GTK_WIDGET (data->info_bar));
		data->info_bar = NULL;
	}
}
Exemplo n.º 13
0
/**
 * e_webdav_discover_content_set_base_url:
 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
 *
 * Sets base URL for the @content. This is used to overwrite the one set on
 * the #ESource from the creation time. The URL can be either a full URL, a path
 * or even a %NULL.
 *
 * Since: 3.18
 **/
void
e_webdav_discover_content_set_base_url (GtkWidget *content,
					const gchar *base_url)
{
	EWebDAVDiscoverContentData *data;

	g_return_if_fail (GTK_IS_GRID (content));
	g_return_if_fail (base_url != NULL);

	data = g_object_get_data (G_OBJECT (content), WEBDAV_DISCOVER_CONTENT_DATA_KEY);
	g_return_if_fail (data != NULL);

	if (g_strcmp0 (base_url, data->base_url) != 0) {
		g_free (data->base_url);
		data->base_url = g_strdup (base_url);
	}
}
Exemplo n.º 14
0
void
go_gtk_widget_replace (GtkWidget *victim, GtkWidget *replacement)
{
	GtkContainer *parent = GTK_CONTAINER (gtk_widget_get_parent (victim));

	if (GTK_IS_GRID (parent)) {
		int col, row, width, height;
		gtk_container_child_get (parent,
					 victim,
					 "left-attach", &col,
					 "top-attach", &row,
					 "width", &width,
					 "height", &height,
					 NULL);
		gtk_container_remove (parent, victim);
		gtk_grid_attach (GTK_GRID (parent), replacement,
				 col, row, width, height);
	} else if (GTK_IS_BOX (parent)) {
		GtkBox *box = GTK_BOX (parent);
		gboolean expand, fill;
		guint padding;
		GtkPackType pack_type;
		int pos;

		gtk_box_query_child_packing (box, victim,
					     &expand, &fill,
					     &padding, &pack_type);
		gtk_container_child_get (parent, victim,
					 "position", &pos,
					 NULL);
		gtk_container_remove (parent, victim);
		gtk_container_add (parent, replacement);
		gtk_box_set_child_packing (box, replacement,
					   expand, fill,
					   padding, pack_type);
		gtk_box_reorder_child (box, replacement, pos);
	} else {
		g_error ("Unsupported container: %s",
			 g_type_name_from_instance ((gpointer)parent));
	}
}
Exemplo n.º 15
0
/**
 * e_webdav_discover_content_refresh_finish:
 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
 * @result: a #GAsyncResult
 * @error: (allow-none): return location for a #GError, or %NULL
 *
 * Finishes the operation started with e_webdav_discover_content_refresh(). If an
 * error occurred, the function will set @error and return %FALSE. There is
 * available e_webdav_discover_content_show_error() for convenience, which
 * shows the error within @content and takes care of it when refreshing
 * the content.
 *
 * Returns: %TRUE on success, %FALSE on failure
 *
 * Since: 3.18
 **/
gboolean
e_webdav_discover_content_refresh_finish (GtkWidget *content,
					  GAsyncResult *result,
					  GError **error)
{
	EWebDAVDiscoverContentData *data;
	GSimpleAsyncResult *simple;

	g_return_val_if_fail (GTK_IS_GRID (content), FALSE);

	data = g_object_get_data (G_OBJECT (content), WEBDAV_DISCOVER_CONTENT_DATA_KEY);
	g_return_val_if_fail (data != NULL, FALSE);
	g_return_val_if_fail (g_simple_async_result_is_valid (
		result, G_OBJECT (content), e_webdav_discover_content_refresh), FALSE);

	simple = G_SIMPLE_ASYNC_RESULT (result);

	if (g_simple_async_result_propagate_error (simple, error))
		return FALSE;

	return g_simple_async_result_get_op_res_gboolean (simple);
}
Exemplo n.º 16
0
/**
 * e_webdav_discover_content_get_user_address:
 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
 *
 * Get currently selected user address in the @content, if the server returned any.
 * This value has meaning only with calendar sources.
 *
 * Returns: (transfer full): currently selected user address. The returned string
 *   is newly allocated and should be freed with g_free() when no longer needed.
 *   If there are none addresses provided by the server, or no calendar sources
 *   were found, then %NULL is returned instead.
 *
 * Since: 3.18
 **/
gchar *
e_webdav_discover_content_get_user_address (GtkWidget *content)
{
	EWebDAVDiscoverContentData *data;
	gchar *active_text;

	g_return_val_if_fail (GTK_IS_GRID (content), NULL);

	data = g_object_get_data (G_OBJECT (content), WEBDAV_DISCOVER_CONTENT_DATA_KEY);
	g_return_val_if_fail (data != NULL, NULL);

	if (!data->email_addresses_combo)
		return NULL;

	active_text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (data->email_addresses_combo));
	if (active_text && !*active_text) {
		g_free (active_text);
		active_text = NULL;
	}

	return active_text;
}
Exemplo n.º 17
0
static void
gog_trend_line_populate_editor (GogObject *gobj,
				GOEditor *editor,
				GogDataAllocator *dalloc,
				GOCmdContext *cc)
{
	GtkWidget *w, *box;
	GogTrendLine *line = GOG_TREND_LINE (gobj);

	box = go_editor_get_page (editor, _("Properties"));
	if (!box)
		box = go_editor_get_page (editor, _("Details"));
	if (!box) {
		box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
		gtk_container_set_border_width (GTK_CONTAINER (box), 12);
		gtk_widget_show_all (box);
		go_editor_add_page (editor, box, _("Legend"));
	}
	w = gtk_check_button_new_with_mnemonic (_("_Show in Legend"));
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
		gog_trend_line_has_legend (line));
	g_signal_connect (G_OBJECT (w),
		"toggled",
		G_CALLBACK (cb_show_in_legend), gobj);
	if (GTK_IS_BOX (box))
		gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
	else if (GTK_IS_GRID (box)) {
		GtkGrid *grid = GTK_GRID (box);
		gtk_grid_insert_row (grid, 1);
		gtk_grid_attach (grid, w, 0, 1, 2, 1);
	} else if (GTK_IS_CONTAINER (box))
		gtk_container_add (GTK_CONTAINER (box), w);
	else
		g_warning ("Unsupported container");
	gtk_widget_show (w);

	(GOG_OBJECT_CLASS (trend_line_parent_klass)->populate_editor) (gobj, editor, dalloc, cc);
}
Exemplo n.º 18
0
/**
 * e_webdav_discover_content_refresh:
 * @content: a WebDAV discovery content, created by e_webdav_discover_content_new()
 * @display_name: (allow-none): optional display name to use for scratch sources
 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
 * @callback: (scope async): a #GAsyncReadyCallback to call when the request
 *            is satisfied
 * @user_data: (closure): data to pass to the callback function
 *
 * Asynchronously starts refresh of the @content. This means to access the server
 * and search it for available sources. The @content shows a feedback and a Cancel
 * button during the operation.
 *
 * The @display_name is used only if the @content wasn't created with an #ESource and
 * it's shown in the password prompts, if there are required any.
 *
 * When the operation is finished, @callback will be called. You can then
 * call e_webdav_discover_content_refresh_finish() to get the result of the operation.
 *
 * Since: 3.18
 **/
void
e_webdav_discover_content_refresh (GtkWidget *content,
				   const gchar *display_name,
				   GCancellable *cancellable,
				   GAsyncReadyCallback callback,
				   gpointer user_data)
{
	EWebDAVDiscoverContentData *data;
	RefreshData *rd;
	ESource *source;
	SoupURI *soup_uri;
	GtkWidget *label;

	g_return_if_fail (GTK_IS_GRID (content));

	data = g_object_get_data (G_OBJECT (content), WEBDAV_DISCOVER_CONTENT_DATA_KEY);
	g_return_if_fail (data != NULL);
	g_return_if_fail (data->base_url != NULL);

	soup_uri = soup_uri_new (data->base_url);
	if (!soup_uri) {
		GSimpleAsyncResult *simple;

		simple = g_simple_async_result_new (G_OBJECT (content), callback, user_data, e_webdav_discover_content_refresh);
		g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
			_("Invalid URL"));
		g_simple_async_result_complete_in_idle (simple);
		g_object_unref (simple);

		return;
	}

	if (!soup_uri_get_user (soup_uri)) {
		GSimpleAsyncResult *simple;

		soup_uri_free (soup_uri);

		simple = g_simple_async_result_new (G_OBJECT (content), callback, user_data, e_webdav_discover_content_refresh);
		g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
			_("User name not filled"));
		g_simple_async_result_complete_in_idle (simple);
		g_object_unref (simple);

		return;
	}

	rd = g_new0 (RefreshData, 1);
	rd->content = g_object_ref (content);
	rd->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
	rd->simple = g_simple_async_result_new (G_OBJECT (content), callback, user_data, e_webdav_discover_content_refresh);
	rd->base_url = g_strdup (data->base_url);
	rd->credentials = NULL;

	if (data->source) {
		source = g_object_ref (data->source);
	} else {
		ESourceWebdav *webdav_extension;
		ESourceAuthentication *auth_extension;

		source = e_source_new_with_uid (data->base_url, NULL, NULL);
		g_return_if_fail (source != NULL);

		webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
		auth_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);

		if (display_name && *display_name)
			e_source_set_display_name (source, display_name);
		e_source_webdav_set_soup_uri (webdav_extension, soup_uri);
		e_source_authentication_set_host (auth_extension, soup_uri_get_host (soup_uri));
		e_source_authentication_set_port (auth_extension, soup_uri_get_port (soup_uri));
		e_source_authentication_set_user (auth_extension, soup_uri_get_user (soup_uri));
	}

	gtk_list_store_clear (GTK_LIST_STORE (gtk_tree_view_get_model (data->sources_tree_view)));
	if (data->email_addresses_combo)
		gtk_combo_box_text_remove_all (GTK_COMBO_BOX_TEXT (data->email_addresses_combo));

	if (data->info_bar)
		gtk_widget_destroy (GTK_WIDGET (data->info_bar));

	data->info_bar = GTK_INFO_BAR (gtk_info_bar_new_with_buttons (_("Cancel"), GTK_RESPONSE_CANCEL, NULL));
	gtk_info_bar_set_message_type (data->info_bar, GTK_MESSAGE_INFO);
	gtk_info_bar_set_show_close_button (data->info_bar, FALSE);
	label = gtk_label_new (_("Searching server sources..."));
	gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (data->info_bar)), label);
	gtk_widget_show (label);
	gtk_widget_show (GTK_WIDGET (data->info_bar));

	g_signal_connect (data->info_bar, "response", G_CALLBACK (e_webdav_discover_info_bar_response_cb), rd);

	gtk_widget_set_sensitive (GTK_WIDGET (data->sources_tree_view), FALSE);
	if (data->email_addresses_combo)
		gtk_widget_set_sensitive (GTK_WIDGET (data->email_addresses_combo), FALSE);

	gtk_grid_attach (GTK_GRID (content), GTK_WIDGET (data->info_bar), 0, 2, 1, 1);

	e_webdav_discover_sources (source, rd->base_url, E_WEBDAV_DISCOVER_SUPPORTS_NONE, rd->credentials, rd->cancellable,
		e_webdav_discover_content_refresh_done_cb, rd);

	g_object_unref (source);
	soup_uri_free (soup_uri);
}
Exemplo n.º 19
0
/** At dialog creation time, this function will be called once per
 *  adds-in.  It performs the work of adding the page into the main
 *  dialog.  It handles both the case of a full page being added to
 *  the dialog, and a partial page being added.
 *
 *  @internal
 *
 *  @param data A pointer to an addition data structure.
 *
 *  @param user_data A pointer to the dialog.
 */
static void
gnc_preferences_build_page (gpointer data,
                            gpointer user_data)
{
    GtkBuilder *builder;
    GtkWidget *dialog, *existing_content, *new_content, *label;
    GtkNotebook *notebook;
    addition *add_in;
    struct copy_data copydata;
    gchar **widgetname;
    gint i;

    ENTER("add_in %p, dialog %p", data, user_data);
    add_in = (addition *)data;
    dialog = user_data;

    DEBUG("Opening %s to get %s", add_in->filename, add_in->widgetname);
    builder = gtk_builder_new();

    /* Adjustments etc... must come before dialog information */
    widgetname = g_strsplit(add_in->widgetname, ",", -1);

    for (i = 0; widgetname[i]; i++)
    {
        DEBUG("Opening %s to get content %s", add_in->filename, widgetname[i]);
        gnc_builder_add_from_file (builder, add_in->filename, widgetname[i]);
    }

    DEBUG("Widget Content is %s", widgetname[i - 1]);
    new_content = GTK_WIDGET(gtk_builder_get_object (builder, widgetname[i - 1]));

    g_strfreev(widgetname);
    DEBUG("done");

    /* Add to the list of interesting widgets */
    gnc_prefs_build_widget_table(builder, dialog);

    /* Connect the signals in this glade file. The dialog is passed in
     * so the the callback can find "interesting" widgets from other
     * glade files if necessary (via the GPREFS_WIDGET_HASH hash table). */
    gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, dialog);

    /* Prepare for recursion */
    notebook = g_object_get_data(G_OBJECT(dialog), NOTEBOOK);

    if (add_in->full_page)
    {
        label = gtk_label_new(add_in->tabname);
        gnc_label_set_alignment(label, 0.0, 0.5);
        gtk_notebook_append_page(notebook, new_content, label);
        g_object_unref(G_OBJECT(builder));
        LEAVE("appended page");
        return;
    }

    /* Copied grids must be grids */
    if (!GTK_IS_GRID(new_content))
    {
        g_critical("The object name %s in file %s is not a GtkGrid. It cannot "
                   "be added to the preferences dialog.",
                   add_in->widgetname, add_in->filename);
        g_object_unref(G_OBJECT(builder));
        LEAVE("");
        return;
    }

    /* Does the page exist or must we create it */
    existing_content = gnc_prefs_find_page(notebook, add_in->tabname);

    if (!existing_content)
    {
        /* No existing content with this name.  Create a blank page */
        existing_content = gtk_grid_new();
        gtk_container_set_border_width(GTK_CONTAINER(existing_content), 6);
        label = gtk_label_new(add_in->tabname);
        gnc_label_set_alignment(label, 0.0, 0.5);
        gtk_notebook_append_page(notebook, existing_content, label);
        gtk_widget_show_all(existing_content);
        DEBUG("created new page %s, appended it", add_in->tabname);
    }
    else
    {
        /* Lets get the size of the existing grid */
        copydata.grid_to = GTK_GRID(existing_content);
        gtk_container_foreach(GTK_CONTAINER(existing_content), gnc_prefs_get_grid_size, &copydata);

        DEBUG("found existing page %s, grid size is %d x %d", add_in->tabname, copydata.rows, copydata.cols);
    }

    /* Maybe add a spacer row */
    if (copydata.rows > 0)
    {
        label = gtk_label_new("");
        gtk_widget_show(label);
        gtk_grid_attach (GTK_GRID(existing_content), label, 0, copydata.rows, 1, 1);
        copydata.rows = copydata.rows + 1;

        DEBUG("add spacer row");
    }

    /* Now copy all the entries in the grid */
    copydata.grid_from = GTK_GRID(new_content);
    copydata.grid_to = GTK_GRID(existing_content);
    gtk_container_foreach(GTK_CONTAINER(new_content), gnc_prefs_move_grid_entry, &copydata);

    g_object_ref_sink(new_content);
    g_object_unref(G_OBJECT(builder));

    LEAVE("added content to page");
}