aboutsummaryrefslogblamecommitdiffstats
path: root/e-util/e-alert.c
blob: cc7488744e06056378009c5793a5762ba0b29839 (plain) (tree)
1
2
3
4
5
6
7
8
9
10




                                                                
  



                                                                    
  
                                                                   
                                                                             
  
  

                                                  
  
                                                        


   
                   


                      



                             
                    
                       
 

                                       
                   
                           
                    
 
            
 
              





                        
                            
 
                          
                       
                            

                                                                                
                                             

 

                                     


                           

  
                 
                      






                               
                        
                                        

  
                       

                                        
                           

  
                               


                                                                            
                                                   


                                             
                                           



                                                                                                                                           




                                                                            

                          











                                                       
           
                               
 
               
 
                                                         






                                                        

                          
                



                                                  

  
           
                           
 
               

                   
                                                             






















                                                                                                      
                          
 
                             
                                     


                                           
                   

                                                   
 
                                      






                                                             

                                                                                     




                                                                  
                                                      
                            
                            


                                                  

                                                                                  
 
                                                                                       



                                                                   
                                                                                                  









                                                                                           

                                                                               




                                                  

                                          
                                     
                                                                           
 
                                                                                  





                                                                     
                                                                                 



                                                
                                                                                    



                                                                        
 
                                                                                   




                                                         

                                                                           

                                                                                       


                                                                                                                

                                                                                       


                                                                                                                  

                                                                                       


                                                                                                              

                                                                                               



                                                                            
                                                                                    
                                                                  

                                                            

                                                                  
                                                                                                 
                                                  

                                                                      

                                                             
                                                                                                 
                                                  

                                                                                                           

                                                             
                                                                                                    




                                                                                
                                                                             
                                                                                                                                

                                                              







                                                                     
                                                                                








                        
                  

                       
                                     
               
 
                                

                       
                                                                
 
                                      

                                          



                                                                                                        
 
                                             



                                                                        
                       
         
 
                                              
                            
 
                                

                                 
                                                       



                              

                         



                                                                           
                                               
 
                

















                                                       
                                                               
                                    
 

                                    





                                                            





                                                                      







                                                                                             
                                                           
 

                                                              
                                                             


         

                                                             


                        
                                            












                                                            


                                                                    

                      

                                                                     
                                                                    
                            
    

                                                     
 
                  


                           
                                        




                   
           
                                                    
 


                                     
                                          

                                
                                 
                            
                          
                                           
 
                                                   
 
                                


                                               


                                                            


                                                      

                                                                         
 
                   
                                                                           
            


                                                                              
 

                                              




                                 



                                                                                                     

                                                                              



                                                              
                                                          
                                   
                                                                               












































                                                                                                    
                                                                
 

                               
                                    
                                                                  


                                                                    
                                                                    
 

                                                                               
                                                                   
                                                    
                                        
                                                                     

                                            

                                                                             
 
                           
                                                                     
                                        
                                                                      


                                            
 



                                                                                                                     



                                                      
                                                  
                                 



                                                                                       
              
                                                                     
 

                                  
                                                                         

                                                                               
 


                                   
    
                                                    

                     
                 
 
                                              






                                             
   
                                






                                                         
                                                
 
                             




                                                      

                                                                          









                                                              

           
                                                                                         

                     
                  


                           
                                        

                   

                                           




                 
                                                                                         
 
                  



                           
                                        

                   

                                                  


                        
/*
 * This program 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) version 3.
 *
 * This program 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 the program; if not, see <http://www.gnu.org/licenses/>
 *
 *
 * Authors:
 *      Michael Zucchi <notzed@ximian.com>
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 */

#include <config.h>

#include <string.h>
#include <sys/types.h>

#include <libxml/parser.h>
#include <libxml/xmlmemory.h>

#include <gtk/gtk.h>
#include <glib/gi18n.h>

#include <libedataserver/e-xml-utils.h>

#include "e-util.h"
#include "e-util-private.h"
#include "e-alert.h"

#define d(x)

struct _EAlert
{
    gchar *tag;
    GPtrArray *args;
};

void
e_alert_free (EAlert *alert)
{
    if (alert == NULL)
        return;
    g_free (alert->tag);
    /* arg strings will be freed automatically since we set a free func when
     * creating the ptr array */
    g_ptr_array_free (alert->args, TRUE);
}

struct _e_alert_button {
    struct _e_alert_button *next;
    const gchar *stock;
    const gchar *label;
    gint response;
};

struct _e_alert {
    guint32 flags;
    const gchar *id;
    gint type;
    gint default_response;
    const gchar *title;
    const gchar *primary;
    const gchar *secondary;
    const gchar *help_uri;
    gboolean scroll;
    struct _e_alert_button *buttons;
};

struct _e_alert_table {
    const gchar *domain;
    const gchar *translation_domain;
    GHashTable *alerts;
};

static GHashTable *alert_table;

/* ********************************************************************** */

static struct _e_alert_button default_ok_button = {
    NULL, "gtk-ok", NULL, GTK_RESPONSE_OK
};

static struct _e_alert default_alerts[] = {
    { GTK_DIALOG_MODAL, "error", 3, GTK_RESPONSE_OK, N_("Evolution Error"), "{0}", "{1}", NULL, FALSE, &default_ok_button },
    { GTK_DIALOG_MODAL, "error-primary", 3, GTK_RESPONSE_OK, N_("Evolution Error"), "{0}", NULL, NULL, FALSE, &default_ok_button },
    { GTK_DIALOG_MODAL, "warning", 1, GTK_RESPONSE_OK, N_("Evolution Warning"), "{0}", "{1}", NULL, FALSE, &default_ok_button },
    { GTK_DIALOG_MODAL, "warning-primary", 1, GTK_RESPONSE_OK, N_("Evolution Warning"), "{0}", NULL, NULL, FALSE, &default_ok_button },
};

/* ********************************************************************** */

static struct {
    const gchar *name;
    gint id;
} response_map[] = {
    { "GTK_RESPONSE_REJECT", GTK_RESPONSE_REJECT },
    { "GTK_RESPONSE_ACCEPT", GTK_RESPONSE_ACCEPT },
    { "GTK_RESPONSE_OK", GTK_RESPONSE_OK },
    { "GTK_RESPONSE_CANCEL", GTK_RESPONSE_CANCEL },
    { "GTK_RESPONSE_CLOSE", GTK_RESPONSE_CLOSE },
    { "GTK_RESPONSE_YES", GTK_RESPONSE_YES },
    { "GTK_RESPONSE_NO", GTK_RESPONSE_NO },
    { "GTK_RESPONSE_APPLY", GTK_RESPONSE_APPLY },
    { "GTK_RESPONSE_HELP", GTK_RESPONSE_HELP },
};

static gint
map_response(const gchar *name)
{
    gint i;

    for (i = 0; i < G_N_ELEMENTS (response_map); i++)
        if (!strcmp(name, response_map[i].name))
            return response_map[i].id;

    return 0;
}

static struct {
    const gchar *name;
    const gchar *icon;
} type_map[] = {
    { "info", GTK_STOCK_DIALOG_INFO },
    { "warning", GTK_STOCK_DIALOG_WARNING },
    { "question", GTK_STOCK_DIALOG_QUESTION },
    { "error", GTK_STOCK_DIALOG_ERROR },
};

static gint
map_type(const gchar *name)
{
    gint i;

    if (name) {
        for (i = 0; i < G_N_ELEMENTS (type_map); i++)
            if (!strcmp(name, type_map[i].name))
                return i;
    }

    return 3;
}

/*
  XML format:

 <error id="error-id" type="info|warning|question|error"? response="default_response"? modal="true"? >
  <title>Window Title</title>?
  <primary>Primary error text.</primary>?
  <secondary>Secondary error text.</secondary>?
  <help uri="help uri"/> ?
  <button stock="stock-button-id"? label="button label"? response="response_id"? /> *
 </error>

 The tool e-error-tool is used to extract the translatable strings for
 translation.

*/
static void
ee_load(const gchar *path)
{
    xmlDocPtr doc = NULL;
    xmlNodePtr root, error, scan;
    struct _e_alert *e;
    struct _e_alert_button *lastbutton;
    struct _e_alert_table *table;
    gchar *tmp;

    d(printf("loading error file %s\n", path));

    doc = e_xml_parse_file (path);
    if (doc == NULL) {
        g_warning("Error file '%s' not found", path);
        return;
    }

    root = xmlDocGetRootElement(doc);
    if (root == NULL
        || strcmp((gchar *)root->name, "error-list") != 0
        || (tmp = (gchar *)xmlGetProp(root, (const guchar *)"domain")) == NULL) {
        g_warning("Error file '%s' invalid format", path);
        xmlFreeDoc(doc);
        return;
    }

    table = g_hash_table_lookup(alert_table, tmp);
    if (table == NULL) {
        gchar *tmp2;

        table = g_malloc0(sizeof(*table));
        table->domain = g_strdup(tmp);
        table->alerts = g_hash_table_new(g_str_hash, g_str_equal);
        g_hash_table_insert(alert_table, (gpointer) table->domain, table);

        tmp2 = (gchar *)xmlGetProp(root, (const guchar *)"translation-domain");
        if (tmp2) {
            table->translation_domain = g_strdup(tmp2);
            xmlFree(tmp2);

            tmp2 = (gchar *)xmlGetProp(root, (const guchar *)"translation-localedir");
            if (tmp2) {
                bindtextdomain(table->translation_domain, tmp2);
                xmlFree(tmp2);
            }
        }
    } else
        g_warning("Error file '%s', domain '%s' already used, merging", path, tmp);
    xmlFree(tmp);

    for (error = root->children;error;error = error->next) {
        if (!strcmp((gchar *)error->name, "error")) {
            tmp = (gchar *)xmlGetProp(error, (const guchar *)"id");
            if (tmp == NULL)
                continue;

            e = g_malloc0(sizeof(*e));
            e->id = g_strdup(tmp);
            e->scroll = FALSE;

            xmlFree(tmp);
            lastbutton = (struct _e_alert_button *)&e->buttons;

            tmp = (gchar *)xmlGetProp(error, (const guchar *)"modal");
            if (tmp) {
                if (!strcmp(tmp, "true"))
                    e->flags |= GTK_DIALOG_MODAL;
                xmlFree(tmp);
            }

            tmp = (gchar *)xmlGetProp(error, (const guchar *)"type");
            e->type = map_type(tmp);
            if (tmp)
                xmlFree(tmp);

            tmp = (gchar *)xmlGetProp(error, (const guchar *)"default");
            if (tmp) {
                e->default_response = map_response(tmp);
                xmlFree(tmp);
            }

            tmp = (gchar *)xmlGetProp(error, (const guchar *)"scroll");
            if (tmp) {
                if (!strcmp(tmp, "yes"))
                    e->scroll = TRUE;
                xmlFree(tmp);
            }

            for (scan = error->children;scan;scan=scan->next) {
                if (!strcmp((gchar *)scan->name, "primary")) {
                    if ((tmp = (gchar *)xmlNodeGetContent(scan))) {
                        e->primary = g_strdup(dgettext(table->translation_domain, tmp));
                        xmlFree(tmp);
                    }
                } else if (!strcmp((gchar *)scan->name, "secondary")) {
                    if ((tmp = (gchar *)xmlNodeGetContent(scan))) {
                        e->secondary = g_strdup(dgettext(table->translation_domain, tmp));
                        xmlFree(tmp);
                    }
                } else if (!strcmp((gchar *)scan->name, "title")) {
                    if ((tmp = (gchar *)xmlNodeGetContent(scan))) {
                        e->title = g_strdup(dgettext(table->translation_domain, tmp));
                        xmlFree(tmp);
                    }
                } else if (!strcmp((gchar *)scan->name, "help")) {
                    tmp = (gchar *)xmlGetProp(scan, (const guchar *)"uri");
                    if (tmp) {
                        e->help_uri = g_strdup(tmp);
                        xmlFree(tmp);
                    }
                } else if (!strcmp((gchar *)scan->name, "button")) {
                    struct _e_alert_button *b;
                    gchar *label = NULL;
                    gchar *stock = NULL;

                    b = g_malloc0(sizeof(*b));
                    tmp = (gchar *)xmlGetProp(scan, (const guchar *)"stock");
                    if (tmp) {
                        stock = g_strdup(tmp);
                        b->stock = stock;
                        xmlFree(tmp);
                    }
                    tmp = (gchar *)xmlGetProp(scan, (const guchar *)"label");
                    if (tmp) {
                        label = g_strdup(dgettext(table->translation_domain, tmp));
                        b->label = label;
                        xmlFree(tmp);
                    }
                    tmp = (gchar *)xmlGetProp(scan, (const guchar *)"response");
                    if (tmp) {
                        b->response = map_response(tmp);
                        xmlFree(tmp);
                    }

                    if (stock == NULL && label == NULL) {
                        g_warning("Error file '%s': missing button details in error '%s'", path, e->id);
                        g_free(stock);
                        g_free(label);
                        g_free(b);
                    } else {
                        lastbutton->next = b;
                        lastbutton = b;
                    }
                }
            }

            g_hash_table_insert(table->alerts, (gpointer) e->id, e);
        }
    }

    xmlFreeDoc(doc);
}

static void
ee_load_tables(void)
{
    GDir *dir;
    const gchar *d;
    gchar *base;
    struct _e_alert_table *table;
    gint i;

    if (alert_table != NULL)
        return;

    alert_table = g_hash_table_new(g_str_hash, g_str_equal);

    /* setup system alert types */
    table = g_malloc0(sizeof(*table));
    table->domain = "builtin";
    table->alerts = g_hash_table_new(g_str_hash, g_str_equal);
    for (i = 0; i < G_N_ELEMENTS (default_alerts); i++)
        g_hash_table_insert(table->alerts, (gpointer) default_alerts[i].id, &default_alerts[i]);
    g_hash_table_insert(alert_table, (gpointer) table->domain, table);

    /* look for installed alert tables */
    base = g_build_filename (EVOLUTION_PRIVDATADIR, "errors", NULL);
    dir = g_dir_open(base, 0, NULL);
    if (dir == NULL) {
        g_free (base);
        return;
    }

    while ( (d = g_dir_read_name(dir)) ) {
        gchar *path;

        if (d[0] == '.')
            continue;

        path = g_build_filename(base, d, NULL);
        ee_load(path);
        g_free(path);
    }

    g_dir_close(dir);
    g_free (base);
}

/* unfortunately, gmarkup_escape doesn't expose its gstring based api :( */
static void
ee_append_text(GString *out, const gchar *text)
{
    gchar c;

    while ( (c=*text++) ) {
        if (c == '<')
            g_string_append(out, "&lt;");
        else if (c == '>')
            g_string_append(out, "&gt;");
        else if (c == '"')
            g_string_append(out, "&quot;");
        else if (c == '\'')
            g_string_append(out, "&apos;");
        else if (c == '&')
            g_string_append(out, "&amp;");
        else
            g_string_append_c(out, c);
    }
}

static void
ee_build_label(GString *out, const gchar *fmt, GPtrArray *args,
               gboolean escape_args)
{
    const gchar *end, *newstart;
    gint id;

    while (fmt
           && (newstart = strchr(fmt, '{'))
           && (end = strchr(newstart+1, '}'))) {
        g_string_append_len(out, fmt, newstart-fmt);
        id = atoi(newstart+1);
        if (id < args->len) {
            if (escape_args)
                ee_append_text(out, args->pdata[id]);
            else
                g_string_append(out, args->pdata[id]);
        } else
            g_warning("Error references argument %d not supplied by caller", id);
        fmt = end+1;
    }

    g_string_append(out, fmt);
}

static void
ee_response(GtkWidget *w, guint button, struct _e_alert *e)
{
    if (button == GTK_RESPONSE_HELP) {
        g_signal_stop_emission_by_name(w, "response");
        e_display_help (GTK_WINDOW (w), e->help_uri);
    }
}

EAlert *
e_alert_newv(const gchar *tag, const gchar *arg0, va_list ap)
{
    gchar *tmp;
    GPtrArray *args;
    EAlert *err = g_slice_new0 (EAlert);
    err->tag = g_strdup (tag);
    err->args = g_ptr_array_new_with_free_func (g_free);

    tmp = (gchar *)arg0;
    while (tmp) {
        g_ptr_array_add(args, g_strdup (tmp));
        tmp = va_arg(ap, gchar *);
    }

    return err;
}

/**
 * e_alert_new:
 * @tag: alert identifier
 * @arg0: The first argument for the alert formatter.  The list must
 * be NULL terminated.
 *
 * Creates a new EAlert.  The @tag argument is used to determine
 * which alert to use, it is in the format domain:alert-id.  The NULL
 * terminated list of arguments, starting with @arg0 is used to fill
 * out the alert definition.
 **/
EAlert *
e_alert_new(const gchar *tag, const gchar *arg0, ...)
{
    EAlert *e;
    va_list ap;

    va_start(ap, arg0);
    e = e_alert_newv(tag, arg0, ap);
    va_end(ap);

    return e;
}

GtkWidget *
e_alert_new_dialog(GtkWindow *parent, EAlert *alert)
{
    struct _e_alert_table *table;
    struct _e_alert *e;
    struct _e_alert_button *b;
    GtkWidget *hbox, *w, *scroll=NULL;
    GtkWidget *action_area;
    GtkWidget *content_area;
    gchar *tmp, *domain, *id;
    GString *out, *oerr;
    GtkDialog *dialog;
    gchar *str, *perr=NULL, *serr=NULL;

    g_return_val_if_fail (alert != NULL, NULL);

    if (alert_table == NULL)
        ee_load_tables();

    dialog = (GtkDialog *)gtk_dialog_new();
    action_area = gtk_dialog_get_action_area (dialog);
    content_area = gtk_dialog_get_content_area (dialog);

    gtk_dialog_set_has_separator(dialog, FALSE);

    gtk_widget_ensure_style ((GtkWidget *)dialog);
    gtk_container_set_border_width (GTK_CONTAINER (action_area), 12);
    gtk_container_set_border_width (GTK_CONTAINER (content_area), 0);

    if (parent)
        gtk_window_set_transient_for ((GtkWindow *)dialog, parent);
    else
        g_warning (
            "Something called %s() with a NULL parent window.  "
            "This is no longer legal, please fix it.", G_STRFUNC);

    domain = alloca(strlen(alert->tag)+1);
    strcpy(domain, alert->tag);
    id = strchr(domain, ':');
    if (id)
        *id++ = 0;

    if ( id == NULL
         || (table = g_hash_table_lookup(alert_table, domain)) == NULL
         || (e = g_hash_table_lookup(table->alerts, id)) == NULL) {
        /* setup a dummy alert */
        str = g_strdup_printf(_("Internal error, unknown error '%s' requested"), alert->tag);
        tmp = g_strdup_printf("<span weight=\"bold\">%s</span>", str);
        g_free(str);
        w = gtk_label_new(NULL);
        gtk_label_set_selectable((GtkLabel *)w, TRUE);
        gtk_label_set_line_wrap((GtkLabel *)w, TRUE);
        gtk_label_set_markup((GtkLabel *)w, tmp);
        GTK_WIDGET_UNSET_FLAGS (w, GTK_CAN_FOCUS);
        gtk_widget_show(w);
        gtk_box_pack_start (GTK_BOX (content_area), w, TRUE, TRUE, 12);

        return (GtkWidget *)dialog;
    }

    if (e->flags & GTK_DIALOG_MODAL)
        gtk_window_set_modal((GtkWindow *)dialog, TRUE);
    gtk_window_set_destroy_with_parent((GtkWindow *)dialog, TRUE);

    if (e->help_uri) {
        w = gtk_dialog_add_button(dialog, GTK_STOCK_HELP, GTK_RESPONSE_HELP);
        g_signal_connect(dialog, "response", G_CALLBACK(ee_response), e);
    }

    b = e->buttons;
    if (b == NULL) {
        gtk_dialog_add_button(dialog, GTK_STOCK_OK, GTK_RESPONSE_OK);
    } else {
        for (b = e->buttons;b;b=b->next) {
            if (b->stock) {
                if (b->label) {
#if 0
                    /* FIXME: So although this looks like it will work, it wont.
                       Need to do it the hard way ... it also breaks the
                       default_response stuff */
                    w = gtk_button_new_from_stock(b->stock);
                    gtk_button_set_label((GtkButton *)w, b->label);
                    gtk_widget_show(w);
                    gtk_dialog_add_action_widget(dialog, w, b->response);
#endif
                    gtk_dialog_add_button(dialog, b->label, b->response);
                } else
                    gtk_dialog_add_button(dialog, b->stock, b->response);
            } else
                gtk_dialog_add_button(dialog, b->label, b->response);
        }
    }

    if (e->default_response)
        gtk_dialog_set_default_response(dialog, e->default_response);

    hbox = gtk_hbox_new(FALSE, 0);
    gtk_container_set_border_width((GtkContainer *)hbox, 12);

    w = gtk_image_new_from_stock(type_map[e->type].icon, GTK_ICON_SIZE_DIALOG);
    gtk_misc_set_alignment((GtkMisc *)w, 0.0, 0.0);
    gtk_box_pack_start((GtkBox *)hbox, w, FALSE, FALSE, 12);

    out = g_string_new("");

    if (e->title && *e->title) {
        ee_build_label(out, e->title, alert->args, FALSE);
        gtk_window_set_title((GtkWindow *)dialog, out->str);
        g_string_truncate(out, 0);
    } else
        gtk_window_set_title((GtkWindow *)dialog, out->str);

    if (e->primary) {
        g_string_append(out, "<span weight=\"bold\" size=\"larger\">");
        ee_build_label(out, e->primary, alert->args, TRUE);
        g_string_append(out, "</span>\n\n");
        oerr = g_string_new("");
        ee_build_label(oerr, e->primary, alert->args, FALSE);
        perr = g_strdup (oerr->str);
        g_string_free (oerr, TRUE);
    } else
        perr = g_strdup (gtk_window_get_title (GTK_WINDOW (dialog)));

    if (e->secondary) {
        ee_build_label(out, e->secondary, alert->args, TRUE);
        oerr = g_string_new("");
        ee_build_label(oerr, e->secondary, alert->args, TRUE);
        serr = g_strdup (oerr->str);
        g_string_free (oerr, TRUE);
    }

    if (e->scroll) {
        scroll = gtk_scrolled_window_new (NULL, NULL);
        gtk_scrolled_window_set_policy ((GtkScrolledWindow *)scroll, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
    }
    w = gtk_label_new(NULL);
    gtk_label_set_selectable((GtkLabel *)w, TRUE);
    gtk_label_set_line_wrap((GtkLabel *)w, TRUE);
    gtk_label_set_markup((GtkLabel *)w, out->str);
    GTK_WIDGET_UNSET_FLAGS (w, GTK_CAN_FOCUS);
    g_string_free(out, TRUE);
    if (e->scroll) {
        gtk_scrolled_window_add_with_viewport ((GtkScrolledWindow *)scroll, w);
        gtk_box_pack_start((GtkBox *)hbox, scroll, FALSE, FALSE, 0);
        gtk_window_set_default_size ((GtkWindow *)dialog, 360, 180);
    } else
        gtk_box_pack_start((GtkBox *)hbox, w, TRUE, TRUE, 0);

    gtk_widget_show_all(hbox);

    gtk_box_pack_start (GTK_BOX (content_area), hbox, TRUE, TRUE, 0);
    g_object_set_data_full ((GObject *) dialog, "primary", perr, g_free);
    g_object_set_data_full ((GObject *) dialog, "secondary", serr, g_free);

    return (GtkWidget *)dialog;
}

gint
e_alert_run_dialog(GtkWindow *parent, EAlert *alert)
{
    GtkWidget *w;
    gint res;

    w = e_alert_new_dialog(parent, alert);

    res = gtk_dialog_run((GtkDialog *)w);
    gtk_widget_destroy(w);

    return res;
}

/**
 * e_alert_dialog_count_buttons:
 * @dialog: a #GtkDialog
 *
 * Counts the number of buttons in @dialog's action area.
 *
 * Returns: number of action area buttons
 **/
guint
e_alert_dialog_count_buttons (GtkDialog *dialog)
{
    GtkWidget *container;
    GList *children, *iter;
    guint n_buttons = 0;

    g_return_val_if_fail (GTK_DIALOG (dialog), 0);

    container = gtk_dialog_get_action_area (dialog);
    children = gtk_container_get_children (GTK_CONTAINER (container));

    /* Iterate over the children looking for buttons. */
    for (iter = children; iter != NULL; iter = iter->next)
        if (GTK_IS_BUTTON (iter->data))
            n_buttons++;

    g_list_free (children);

    return n_buttons;
}

GtkWidget *
e_alert_new_dialog_for_args (GtkWindow *parent, const gchar *tag, const gchar *arg0, ...)
{
    GtkWidget *w;
    EAlert *e;
    va_list ap;

    va_start(ap, arg0);
    e = e_alert_newv(tag, arg0, ap);
    va_end(ap);

    w = e_alert_new_dialog (parent, e);
    e_alert_free (e);

    return w;
}

gint
e_alert_run_dialog_for_args (GtkWindow *parent, const gchar *tag, const gchar *arg0, ...)
{
    EAlert *e;
    va_list ap;
    gint response;

    va_start(ap, arg0);
    e = e_alert_newv(tag, arg0, ap);
    va_end(ap);

    response = e_alert_run_dialog (parent, e);
    e_alert_free (e);

    return response;
}