static void
gppsl_row_activated_cb(GtkTreeView *tree_view,
                       GtkTreePath *path,
                       GtkTreeViewColumn *column,
                       gpointer user_data)
{
    GncPluginPageSxList *page = GNC_PLUGIN_PAGE_SX_LIST(user_data);
    GncPluginPageSxListPrivate *priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);

    SchedXaction *sx = gnc_tree_view_sx_list_get_sx_from_path(GNC_TREE_VIEW_SX_LIST(priv->tree_view), path);
    gnc_ui_scheduled_xaction_editor_dialog_create(sx, FALSE);
}
static void
gnc_plugin_page_sx_list_finalize (GObject *object)
{
    GncPluginPageSxList *page;
    GncPluginPageSxListPrivate *priv;

    page = GNC_PLUGIN_PAGE_SX_LIST (object);
    g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST (page));
    priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
    g_return_if_fail(priv != NULL);

    G_OBJECT_CLASS (parent_class)->finalize (object);
}
GncPluginPage *
gnc_plugin_page_sx_list_new (void)
{
    GncPluginPageSxList *plugin_page;
    const GList *object = gnc_gobject_tracking_get_list (GNC_PLUGIN_PAGE_SX_LIST_NAME);
    if (object && GNC_IS_PLUGIN_PAGE_SX_LIST (object->data))
	plugin_page = GNC_PLUGIN_PAGE_SX_LIST (object->data);
    else
    {
	plugin_page = g_object_new (GNC_TYPE_PLUGIN_PAGE_SX_LIST, NULL);
    }
    return GNC_PLUGIN_PAGE(plugin_page);
}
/** Save enough information about this page that it can be recreated next time
 * the user starts gnucash.
 * @param plugin_page The page to save.
 * @param key_file A pointer to the GKeyFile data structure where the
 * page information should be written.
 * @param group_name The group name to use when saving data.
 **/
static void
gnc_plugin_page_sx_list_save_page (GncPluginPage *plugin_page,
                                   GKeyFile *key_file,
                                   const gchar *group_name)
{
    GncPluginPageSxList *page;
    GncPluginPageSxListPrivate *priv;

    g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST(plugin_page));
    g_return_if_fail(key_file != NULL);
    g_return_if_fail(group_name != NULL);

    page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
    priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);

    g_key_file_set_integer(key_file, group_name, "dense_cal_num_months",
                           gnc_dense_cal_get_num_months(priv->gdcal));

    g_key_file_set_integer(key_file, group_name, "paned_position",
                           gtk_paned_get_position(GTK_PANED(priv->widget)));
}
static void
gnc_plugin_page_sx_list_destroy_widget (GncPluginPage *plugin_page)
{
    GncPluginPageSxList *page;
    GncPluginPageSxListPrivate *priv;

    page = GNC_PLUGIN_PAGE_SX_LIST (plugin_page);
    priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);

    if (priv->widget)
    {
        g_object_unref(G_OBJECT(priv->widget));
        priv->widget = NULL;
    }

    if (priv->gnc_component_id)
    {
        gnc_unregister_gui_component(priv->gnc_component_id);
        priv->gnc_component_id = 0;
    }
}
/**
 * Create a new sx list page based on the information saved during a previous
 * instantiation of gnucash.
 *  @param window The window where this page should be installed.
 *  @param key_file A pointer to the GKeyFile data structure where the
 *  page information should be read.
 *  @param group_name The group name to use when restoring data.
 **/
static GncPluginPage *
gnc_plugin_page_sx_list_recreate_page (GtkWidget *window,
                                       GKeyFile *key_file,
                                       const gchar *group_name)
{
    GncPluginPageSxList *page;
    GncPluginPageSxListPrivate *priv;

    g_return_val_if_fail(key_file, NULL);
    g_return_val_if_fail(group_name, NULL);

    /* Create the new page. */
    page = GNC_PLUGIN_PAGE_SX_LIST(gnc_plugin_page_sx_list_new());
    priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);

    /* Install it now so we can them manipulate the created widget */
    gnc_main_window_open_page(GNC_MAIN_WINDOW(window), GNC_PLUGIN_PAGE(page));

    {
        GError *err = NULL;
        gint num_months = g_key_file_get_integer(key_file, group_name, "dense_cal_num_months", &err);
        if (err == NULL)
            gnc_dense_cal_set_num_months(priv->gdcal, num_months);
        else
            g_error_free(err);
    }

    {
        GError *err = NULL;
        gint paned_position = g_key_file_get_integer(key_file, group_name,
                              "paned_position", &err);
        if (err == NULL)
            gtk_paned_set_position(GTK_PANED(priv->widget), paned_position);
        else
            g_error_free(err);
    }

    return GNC_PLUGIN_PAGE(page);
}
static void
gnc_plugin_page_sx_list_dispose(GObject *object)
{
    GncPluginPageSxList *page;
    GncPluginPageSxListPrivate *priv;

    page = GNC_PLUGIN_PAGE_SX_LIST (object);
    g_return_if_fail(GNC_IS_PLUGIN_PAGE_SX_LIST (page));
    priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
    g_return_if_fail(priv != NULL);

    g_return_if_fail(!priv->disposed);
    priv->disposed = TRUE;

    g_object_unref(G_OBJECT(priv->dense_cal_model));
    priv->dense_cal_model = NULL;
    g_object_unref(GTK_WIDGET(priv->gdcal));
    priv->gdcal = NULL;
    g_object_unref(G_OBJECT(priv->instances));
    priv->instances = NULL;

    G_OBJECT_CLASS (parent_class)->dispose(object);
}
static GtkWidget *
gnc_plugin_page_sx_list_create_widget (GncPluginPage *plugin_page)
{
    GncPluginPageSxList *page;
    GncPluginPageSxListPrivate *priv;
    GtkWidget *widget;
    GtkWidget *vbox;
    GtkWidget *label;
    GtkWidget *swin;
    char *markup;
    char *text;

    page = GNC_PLUGIN_PAGE_SX_LIST(plugin_page);
    priv = GNC_PLUGIN_PAGE_SX_LIST_GET_PRIVATE(page);
    if (priv->widget != NULL)
        return priv->widget;

    /* Create Vpaned widget for top level */
    widget = gtk_vpaned_new();
    priv->widget = widget;
    gtk_widget_show (priv->widget);

    /* Add vbox and label */
    vbox = gtk_vbox_new(FALSE, 0);
    gtk_paned_pack1( GTK_PANED(widget), vbox, TRUE, FALSE);

    label = gtk_label_new(NULL);
    text = g_strdup_printf(_("Transactions"));
    markup = g_markup_printf_escaped ("<b> %s</b>", text);
    gtk_label_set_markup (GTK_LABEL (label), markup);
    g_free (markup);
    g_free (text);
    gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0);
    gtk_widget_show (label);
    gtk_box_pack_start ( GTK_BOX(vbox), label, FALSE, FALSE, 0);
    gtk_widget_show (vbox);

    /* Create scrolled window for top area */
    swin = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
                                    GTK_POLICY_AUTOMATIC,
                                    GTK_POLICY_AUTOMATIC);
    gtk_box_pack_start ( GTK_BOX(vbox), swin, TRUE, TRUE, 5);
    gtk_widget_show (swin);

    {
        // gint half_way;
        // half_way = plugin_page->notebook_page->allocation.height * 0.5;
        // fixme; get a real value:
        gtk_paned_set_position(GTK_PANED(priv->widget), 160);
    }

    {
        GDate end;
        g_date_clear(&end, 1);
        gnc_gdate_set_today (&end);
        g_date_add_years(&end, 1);
        priv->instances = GNC_SX_INSTANCE_MODEL(gnc_sx_get_instances(&end, TRUE));
    }

    {
        GtkAction *edit_action, *delete_action;
        edit_action = gnc_plugin_page_get_action(GNC_PLUGIN_PAGE(page), "SxListEditAction");
        delete_action = gnc_plugin_page_get_action(GNC_PLUGIN_PAGE(page), "SxListDeleteAction");
        gtk_action_set_sensitive(edit_action, FALSE);
        gtk_action_set_sensitive(delete_action, FALSE);
    }

    {
        GtkTreeSelection *selection;

        priv->tree_view = GTK_TREE_VIEW(gnc_tree_view_sx_list_new(priv->instances));
        g_object_set(G_OBJECT(priv->tree_view),
                     "gconf-section", GCONF_SECTION,
                     "show-column-menu", TRUE,
                     NULL);
        gtk_container_add(GTK_CONTAINER( swin ), GTK_WIDGET(priv->tree_view));

        selection = gtk_tree_view_get_selection(priv->tree_view);
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
        g_signal_connect(G_OBJECT(selection), "changed", (GCallback)gppsl_selection_changed_cb, (gpointer)page);
        g_signal_connect(G_OBJECT(priv->tree_view), "row-activated", (GCallback)gppsl_row_activated_cb, (gpointer)page);
    }

    /* Add vbox and label */
    vbox = gtk_vbox_new(FALSE, 0);
    gtk_paned_pack2( GTK_PANED(widget), vbox, TRUE, FALSE);

    label = gtk_label_new(NULL);
    text = g_strdup_printf(_("Upcoming Transactions"));
    markup = g_markup_printf_escaped ("<b> %s</b>", text);
    gtk_label_set_markup (GTK_LABEL (label), markup);
    g_free (markup);
    g_free (text);
    gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0);
    gtk_widget_show (label);

    gtk_box_pack_start ( GTK_BOX(vbox), label, FALSE, FALSE, 0);
    gtk_widget_show (vbox);

    /* Create scrolled window for bottom area */
    swin = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
                                    GTK_POLICY_AUTOMATIC,
                                    GTK_POLICY_AUTOMATIC);
    gtk_box_pack_start ( GTK_BOX(vbox), swin, TRUE, TRUE, 5);
    gtk_widget_show (swin);

    {
        priv->dense_cal_model = gnc_sx_instance_dense_cal_adapter_new(GNC_SX_INSTANCE_MODEL(priv->instances));
        priv->gdcal = GNC_DENSE_CAL(gnc_dense_cal_new_with_model(GNC_DENSE_CAL_MODEL(priv->dense_cal_model)));
        g_object_ref_sink(priv->gdcal);

        gnc_dense_cal_set_months_per_col(priv->gdcal, 4);
        gnc_dense_cal_set_num_months(priv->gdcal, 12);

        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swin), GTK_WIDGET(priv->gdcal));
    }

    priv->gnc_component_id = gnc_register_gui_component("plugin-page-sx-list",
                             gnc_plugin_page_sx_list_refresh_cb,
                             gnc_plugin_page_sx_list_close_cb,
                             page);

    return priv->widget;
}