aboutsummaryrefslogblamecommitdiffstats
path: root/shell/e-shell-window-actions.c
blob: 9146b548c41f3bb08504b17e239b8d785d262f98 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  

                           










                                                                             


                                                        
  

   



                    
                                   

                             
                                                                    
                                                           


                          
                                                                     



                                                                     
                                                                    

                                 



                                              
                                                         

                                     



                                     
                        


            







                                                                     

                                   
                                            










                                                                   
                                          



                                                 
                                       




                                                         
                                                    


                      








                                                                         

                                   
                                            
 

                          

                        


                                                

                                                       
                                                  


                                     

 







                                                                 
           
                                      
                                               
 
                 

                                                                   
                               
 
                                       

                                                            


                                                                
                                                         
      


           


                                                  
                          
                               





                                                                  
                                                                             

                                                             
                                                   
 
                                                      

 
   
                                         

                            
                                                                       
  
                                                              
    
           

                                                      

                               
                                       
                               

                           
 
                                                                  
                                                                             










                                                                            
 
                                                                           
 
                                                             

 








                                                                      
           




                                               


                               
                                                                  
                                                                             
                                                                    
                                                       

 







                                                              













                                                                             








                                                                  
           
                                    
                                             
 
                             
 
                                                                       
 




                                                                         
                                    

                                                       
                                
                                      

                                                       
                                    

 







                                                      

                                        
                                                 
 
                      
                               
 
                                                        


                                                                  

 







                                                                       

                                        
                                                 
 
                                                                  

 
   






















                                                                
                                                       











                                                                            






                                                                        

                                         
                                                  
 
                      
                                      

                                     

                                                
 

                                                                    
                                                                               
 





                                                

                                                             





                                                                             



                                                                  

 








                                                                       

                                             
                                                      

                                            
                                      

                                                 
                                                          




















                                                                       

                                                                          














                                                                 







                                                            

                                  
                                           
 

                      
                                                        
                                                  

 







                                                             
           


                                                      




                                                                  
                                                                             



                                                                    

 







                                                                   




                                                   

                               
                                                                  
                                                                             
 
                                               

 







                                                                       




                                                  
                                     

                               
                                                                  
                                                                             
                                                                    
 

                                                                 

 


































                                                                                                      
   





                                                               
           
                                            

                                                     



                                          
                              

                                                                  
                                                                             

                                                               
                                                       









                                                                                          

 
   




















                                                                             






                                                                 



                                                  




                                                                  
                                                                             



                                                                    

 
   






                                                               
 
   
                                       

                            
                                                                        
  
                                                              
    
 
   
                                      

                            
                                                               
  
                                                    
    
 







                                                               
 








                                                               

                                        
                                                 



                                  
                                                       




                                                          

                                                        


                                                            




                                     









                                                                        

                                             
                                                      











                                                                       



































                                                                       
           

                                                  
                                                     
 
                                 

                              
                                                                   






                                                            
                                                                     


                              
                                                                

                              

 
   






                                                                    

                                          
                                                   
 
                      
                            
 
                                                        
 
                                          
 




                                                                           

 







                                                                   

                                         
                                                  
 
                      
                            
 
                                                        
 
                                         
 




                                                                           

 





























                                            


                                         

                       




                                                 
                         




                                         
                              

                         



                                         
                         
                         




                                         
                     
                         
                          
               


                                              
                           

                      
                       



                                                 

                     
                       



                                                 

                        



                                                 













                                                         
                            

                       
                       


                                                 






                                              
                        

                               











                                                   

                             
                       


                                        







                                                   

                       










                                                    
                           

                      
                       

                                                     
 
                         
                      
                          
               


                                                      






                                                   
                       

                            



                                                 

                       
                                      



                                                    




































                                                






                        
                     
                         
                     
               









                        






                                     














                        


















                                                  

                                                      


                               
               
                                  
               

                 




                                          








                                    

                 

                         
                               
               

                                  


                












                                                                






                                                             
                              





                                                      
                             





                                                           
                                   





                                                                         
              

  

                                                  
                            
               
                                    
               
                                              
                                                   





                                         
                                                        




















                                                             


                                                              

                                




                                                                  
           
                                                         










                                                                      
                                                                     







                                                                       
          



                                                                    
                                          
 

                                                           
 
                                                             

                                 



                                                                       













                                                                          
    
                                                        

                                     
                                     
                                 
                    
 
                                                            
 
                                                                  

                                                                        
 
                           
                                            

                                            
                                                            


                                                    

                                                   
                                                                   

                                                           
                                                            
                                                       
                                                                     






                                                                     
 
                              
                                               



                                                                   

                                          
                                                           



                                                                  
 














                                                                        

                          

                                                                
                                
                                                


                                                
 
                                
                                                 


                                                 
 
                                
                                                


                                                
 
                                
                                                


                                                
 
                                
                                                

                                                    
 
                                
                                                

                                                          
 
                                
                                                

                                                           
 
                                
                                                

                                                          
 
                                
                                                

                                                          
 
                                
                                                

                                                    





                                                                    

 
           
                                                           









                                                                      
                                               


                                                             
                                                          
 
                                                 


                                                             
                                                          



                                                                      
                                                        

                                      
                                                          













                                                                        




                                                                                
 




                                                                                    




















                                                                          
                  




                                                              


                          






                                              
 


                                                   







                                                                 
    
                                                                   
 
                             


                                       

                                 

                           
                       
                     
 
                                                            
 

                                                   


                                                                   
                                                        
                                                  
 
                                                                         

                                                                       
                         
 


                                                                
 
                                                            
                                                          
                                                  
                                       
                                    
                                
                                       
                                   

                                     

                               
                                                             


                                                                          
 
                                                                  

                                                             
                                                        



                                                                 
                                                     
 
                                           





                                                             

                                                                            

                                                            
 



                                                                       
                                             




                                                               

                                                              
 
                                                                        

                                                                          



                                                        
                                                                            
 
                                     

                                       
                                             
                                                           
                                                     
                                                    


                                                  








                                                                              

                                                                       

                                                                   
 
                                       



                                           
 

    
                                                            

                               
                                          

                                     
                                           

                                     

                            
                          

                               

                                        



                                                                  
                                                                  
                                                                             

                                              



                                                               
 
                                               



                                                         
                                                         
                                                  
 

                                                                
                                                                  
 





                                                  









                                                                   
                                       
 
                                                                               


                                                         

                                                                        



                                                                     
                                                   






                                                                        
                                                                         
                                                                              



                                                             
 


                                                                   


                                                       


                                     
                               






                                                                          


                                                  


                                                 





                                                        
 



                                                              

                                          

                              

                                     





                               

                                                            

                                                                  
                                                                             

                                                                   
                                                                          


                                                                      
                                                               
                                                   
 
                                          
 
                                                          
                                                               



                                                                      
                                                   



                                                            
                                                         
                                                  
 
                                                                



































                                                                          
                                                                        

         
/*
 * e-shell-window-actions.c
 *
 * 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.
 *
 * 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 General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "e-shell-window-private.h"

#define EVOLUTION_COPYRIGHT \
    "Copyright \xC2\xA9 1999 - 2008 Novell, Inc. and Others\n" \
    "Copyright \xC2\xA9 2008 - 2014 The Evolution Team"

/* Authors and Documenters
 *
 * The names below must be in UTF-8.  The breaking of escaped strings
 * is so the hexadecimal sequences don't swallow too many characters.
 *
 * SO THAT MEANS, FOR 8-BIT CHARACTERS USE \xXX HEX ENCODING ONLY!
 *
 * Not all environments are UTF-8 and not all editors can handle it.
 */
static const gchar *authors[] = {
    "The Evolution Team",
    "",
    "Matthew Barnes <mbarnes@redhat.com>",
    "Milan Crha <mcrha@redhat.com>",
    "Fabiano Fid\xC3\xAAncio <fabiano@fidencio.org>",
    "",
    "and many past contributers",
    NULL
};

static const gchar *documenters[] = {
    "Andre Klapper",
    NULL
};

/**
 * E_SHELL_WINDOW_ACTION_ABOUT:
 * @window: an #EShellWindow
 *
 * Activation of this action displays the application's About dialog.
 *
 * Main menu item: Help -> About
 **/
static void
action_about_cb (GtkAction *action,
                 EShellWindow *shell_window)
{
    gchar *translator_credits;

    /* The translator-credits string is for translators to list
     * per-language credits for translation, displayed in the
     * about dialog. */
    translator_credits = _("translator-credits");
    if (strcmp (translator_credits, "translator-credits") == 0)
        translator_credits = NULL;

    gtk_show_about_dialog (
        GTK_WINDOW (shell_window),
        "program-name", "Evolution",
        "version", VERSION,
        "copyright", EVOLUTION_COPYRIGHT,
        "comments", _("Groupware Suite"),
        "website", PACKAGE_URL,
        "website-label", _("Evolution Website"),
        "authors", authors,
        "documenters", documenters,
        "translator-credits", translator_credits,
        "logo-icon-name", "evolution",
        "license-type", GTK_LICENSE_GPL_2_0,
        NULL);
}

/**
 * E_SHELL_WINDOW_ACTION_CLOSE:
 * @window: an #EShellWindow
 *
 * Activation of this action closes @window.  If this is the last window,
 * the application initiates shutdown.
 *
 * Main menu item: File -> Close
 **/
static void
action_close_cb (GtkAction *action,
                 EShellWindow *shell_window)
{
    GtkWidget *widget;
    GdkWindow *window;
    GdkEvent *event;

    widget = GTK_WIDGET (shell_window);
    window = gtk_widget_get_window (widget);

    /* Synthesize a delete_event on this window. */
    event = gdk_event_new (GDK_DELETE);
    event->any.window = g_object_ref (window);
    event->any.send_event = TRUE;
    gtk_main_do_event (event);
    gdk_event_free (event);
}

/**
 * E_SHELL_WINDOW_ACTION_CONTENTS:
 * @window: an #EShellWindow
 *
 * Activation of this action opens the application's user manual.
 *
 * Main menu item: Help -> Contents
 **/
static void
action_contents_cb (GtkAction *action,
                    EShellWindow *shell_window)
{
#ifdef G_OS_WIN32
    /* On Windows, link to online help instead.
     * See https://bugzilla.gnome.org/show_bug.cgi?id=576478 */
    gchar *online_help_url;

    online_help_url = g_strconcat (
        "http://library.gnome.org/users/evolution/",
        BASE_VERSION, NULL);
    e_show_uri (GTK_WINDOW (shell_window), online_help_url);
    g_free (online_help_url);
#else
    e_display_help (GTK_WINDOW (shell_window), NULL);
#endif
}

static void
action_custom_rule_cb (GtkAction *action,
                       EShellWindow *shell_window)
{
    EFilterRule *rule;
    EShellView *shell_view;
    const gchar *view_name;

    rule = g_object_get_data (G_OBJECT (action), "rule");
    g_return_if_fail (rule != NULL);

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);

    rule = g_object_get_data (G_OBJECT (action), "rule");
    g_return_if_fail (E_IS_FILTER_RULE (rule));

    e_shell_view_custom_search (shell_view, rule);
}

/**
 * E_SHELL_WINDOW_ACTION_GAL_DELETE_VIEW:
 * @window: an #EShellWindow
 *
 * Activation of this action deletes the current user-created GAL view.
 *
 * Main menu item: View -> Current View -> Delete Current View
 **/
static void
action_gal_delete_view_cb (GtkAction *action,
                           EShellWindow *shell_window)
{
    EShellView *shell_view;
    GalViewInstance *view_instance;
    const gchar *view_name;
    gchar *gal_view_id;
    gint index = -1;

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);
    view_instance = e_shell_view_get_view_instance (shell_view);
    g_return_if_fail (view_instance != NULL);

    /* XXX This is kinda cumbersome.  The view collection API
     *     should be using only view ID's, not index numbers. */
    gal_view_id = gal_view_instance_get_current_view_id (view_instance);
    if (gal_view_id != NULL) {
        index = gal_view_collection_get_view_index_by_id (
            view_instance->collection, gal_view_id);
        g_free (gal_view_id);
    }

    gal_view_collection_delete_view (view_instance->collection, index);

    gal_view_collection_save (view_instance->collection);
}

/**
 * E_SHELL_WINDOW_ACTION_GAL_CUSTOM_VIEW:
 * @window: an #EShellWindow
 *
 * This radio action is selected when using a custom GAL view that has
 * not been saved.
 *
 * Main menu item: View -> Current View -> Custom View
 **/
static void
action_gal_view_cb (GtkRadioAction *action,
                    GtkRadioAction *current,
                    EShellWindow *shell_window)
{
    EShellView *shell_view;
    const gchar *view_name;
    const gchar *view_id;

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);
    view_id = g_object_get_data (G_OBJECT (current), "view-id");
    e_shell_view_set_view_id (shell_view, view_id);
}

/**
 * E_SHELL_WINDOW_ACTION_GAL_SAVE_CUSTOM_VIEW:
 * @window: an #EShellWindow
 *
 * Activation of this action saves a custom GAL view.
 *
 * Main menu item: View -> Current View -> Save Custom View...
 **/
static void
action_gal_save_custom_view_cb (GtkAction *action,
                                EShellWindow *shell_window)
{
    EShellView *shell_view;
    GalViewInstance *view_instance;
    const gchar *view_name;

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);
    view_instance = e_shell_view_get_view_instance (shell_view);

    gal_view_instance_save_as (view_instance);
}

/**
 * E_SHELL_WINDOW_ACTION_IMPORT:
 * @window: an #EShellWindow
 *
 * Activation of this action opens the Evolution Import Assistant.
 *
 * Main menu item: File -> Import...
 **/
static void
action_import_cb (GtkAction *action,
                  EShellWindow *shell_window)
{
    GtkWidget *assistant;

    assistant = e_import_assistant_new (GTK_WINDOW (shell_window));

    /* These are "Run Last" signals, so use g_signal_connect_after()
     * to give the default handlers a chance to run before we destroy
     * the window. */

    g_signal_connect_after (
        assistant, "cancel",
        G_CALLBACK (gtk_widget_destroy), NULL);

    g_signal_connect_after (
        assistant, "finished",
        G_CALLBACK (gtk_widget_destroy), NULL);

    gtk_widget_show (assistant);
}

/**
 * E_SHELL_WINDOW_ACTION_NEW_WINDOW:
 * @window: an #EShellWindow
 *
 * Activation of this action opens a new shell window.
 *
 * Main menu item: File -> New Window
 **/
static void
action_new_window_cb (GtkAction *action,
                      EShellWindow *shell_window)
{
    EShell *shell;
    const gchar *view_name;

    shell = e_shell_window_get_shell (shell_window);
    view_name = e_shell_window_get_active_view (shell_window);

    e_shell_create_shell_window (shell, view_name);
}

/**
 * E_SHELL_WINDOW_ACTION_PAGE_SETUP:
 * @window: an #EShellWindow
 *
 * Activation of this action opens the application's Page Setup dialog.
 *
 * Main menu item: File -> Page Setup...
 **/
static void
action_page_setup_cb (GtkAction *action,
                      EShellWindow *shell_window)
{
    e_print_run_page_setup_dialog (GTK_WINDOW (shell_window));
}

/**
 * E_SHELL_WINDOW_ACTION_CATEGORIES
 * @window: and #EShellWindow
 *
 * Activation of this action opens the Categories Editor dialog.
 *
 * Main menu item: Edit -> Available categories
 **/
static void
action_categories_cb (GtkAction *action,
                      EShellWindow *shell_window)
{
    GtkWidget *content_area;
    GtkWidget *dialog;
    GtkWidget *editor;

    editor = e_categories_editor_new ();
    e_categories_editor_set_entry_visible (
        E_CATEGORIES_EDITOR (editor), FALSE);

    dialog = gtk_dialog_new_with_buttons (
        _("Categories Editor"),
        GTK_WINDOW (shell_window),
        GTK_DIALOG_DESTROY_WITH_PARENT,
        _("_Close"), GTK_RESPONSE_CLOSE, NULL);
    gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
    content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
    gtk_box_pack_start (
        GTK_BOX (content_area), GTK_WIDGET (editor), TRUE, TRUE, 6);
    gtk_box_set_spacing (GTK_BOX (content_area), 12);

    gtk_dialog_run (GTK_DIALOG (dialog));

    gtk_widget_destroy (dialog);
}

/**
 * E_SHELL_WINDOW_ACTION_PREFERENCES:
 * @window: an #EShellWindow
 *
 * Activation of this action opens the application's Preferences window.
 *
 * Main menu item: Edit -> Preferences
 **/
static void
action_preferences_cb (GtkAction *action,
                       EShellWindow *shell_window)
{
    EShell *shell;
    GtkWidget *preferences_window;
    EShellView *shell_view;
    EShellBackend *shell_backend;
    EShellBackendClass *shell_backend_class;
    const gchar *view_name;

    shell = e_shell_window_get_shell (shell_window);
    preferences_window = e_shell_get_preferences_window (shell);
    e_preferences_window_setup (E_PREFERENCES_WINDOW (preferences_window));

    gtk_window_set_transient_for (
        GTK_WINDOW (preferences_window),
        GTK_WINDOW (shell_window));
    gtk_window_set_position (
        GTK_WINDOW (preferences_window),
        GTK_WIN_POS_CENTER_ON_PARENT);
    gtk_window_present (GTK_WINDOW (preferences_window));

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);

    shell_backend = e_shell_view_get_shell_backend (shell_view);
    shell_backend_class = E_SHELL_BACKEND_GET_CLASS (shell_backend);

    if (shell_backend_class->preferences_page != NULL)
        e_preferences_window_show_page (
            E_PREFERENCES_WINDOW (preferences_window),
            shell_backend_class->preferences_page);
}

/**
 * E_SHELL_WINDOW_ACTION_QUICK_REFERENCE:
 * @window: an #EShellWindow
 *
 * Activation of this action opens a printable table of useful shortcut
 * keys for this application.
 *
 * Main menu item: Help -> Quick Reference
 **/
static void
action_quick_reference_cb (GtkAction *action,
                           EShellWindow *shell_window)
{
    const gchar * const *language_names;
    gboolean app_launched = FALSE;

    language_names = g_get_language_names ();
    while (*language_names != NULL && !app_launched) {
        const gchar *language = *language_names++;
        gchar *filename;

        /* This must be a valid language AND a language with
         * no encoding suffix.  The next language should have
         * no encoding suffix. */
        if (language == NULL || strchr (language, '.') != NULL)
            continue;

        filename = g_build_filename (
            EVOLUTION_HELPDIR, "quickref",
            language, "quickref.pdf", NULL);

        if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
            GFile *file;
            gchar *uri;
            GError *error = NULL;

            file = g_file_new_for_path (filename);
            uri = g_file_get_uri (file);

            app_launched = g_app_info_launch_default_for_uri (
                uri, NULL, &error);

            if (error != NULL) {
                /* FIXME Show an error dialog. */
                g_warning ("%s", error->message);
                g_error_free (error);
            }

            g_object_unref (file);
            g_free (uri);
        }

        g_free (filename);
    }
}

/**
 * E_SHELL_WINDOW_ACTION_QUIT:
 * @window: an #EShellWindow
 *
 * Activation of this action initiates application shutdown.
 *
 * Main menu item: File -> Quit
 **/
static void
action_quit_cb (GtkAction *action,
                EShellWindow *shell_window)
{
    EShell *shell;

    shell = e_shell_window_get_shell (shell_window);
    e_shell_quit (shell, E_SHELL_QUIT_ACTION);
}

/**
 * E_SHELL_WINDOW_ACTION_SEARCH_ADVANCED:
 * @window: an #EShellWindow
 *
 * Activation of this action opens an Advanced Search dialog.
 *
 * Main menu item: Search -> Advanced Search...
 **/
static void
action_search_advanced_cb (GtkAction *action,
                           EShellWindow *shell_window)
{
    EShellView *shell_view;
    EShellContent *shell_content;
    const gchar *view_name;

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);
    shell_content = e_shell_view_get_shell_content (shell_view);

    e_shell_content_run_advanced_search_dialog (shell_content);
    e_shell_window_update_search_menu (shell_window);
}

/**
 * E_SHELL_WINDOW_ACTION_SEARCH_CLEAR:
 * @window: an #EShellWindow
 *
 * Activation of this action clears the most recent search results.
 *
 * Main menu item: Search -> Clear
 **/
static void
action_search_clear_cb (GtkAction *action,
                        EShellWindow *shell_window)
{
    EShellView *shell_view;
    const gchar *view_name;

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);

    e_shell_view_clear_search (shell_view);
}

/**
 * E_SHELL_WINDOW_ACTION_SEARCH_EDIT:
 * @window: an #EShellWindow
 *
 * Activation of this action opens a dialog for editing saved searches.
 *
 * Main menu item: Search -> Edit Saved Searches...
 **/
static void
action_search_edit_cb (GtkAction *action,
                       EShellWindow *shell_window)
{
    EShellView *shell_view;
    EShellContent *shell_content;
    const gchar *view_name;

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);
    shell_content = e_shell_view_get_shell_content (shell_view);

    e_shell_content_run_edit_searches_dialog (shell_content);
    e_shell_window_update_search_menu (shell_window);
}

static void
search_options_selection_cancel_cb (GtkMenuShell *menu,
                    EShellWindow *shell_window);

static void
search_options_selection_done_cb (GtkMenuShell *menu,
                  EShellWindow *shell_window)
{
    EShellView *shell_view;
    EShellSearchbar *search_bar;
    const gchar *view_name;

    /* disconnect first */
    g_signal_handlers_disconnect_by_func (menu, search_options_selection_done_cb, shell_window);
    g_signal_handlers_disconnect_by_func (menu, search_options_selection_cancel_cb, shell_window);

    g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);
    g_return_if_fail (shell_view != NULL);

    search_bar = E_SHELL_SEARCHBAR (e_shell_view_get_searchbar (shell_view));
    e_shell_searchbar_search_entry_grab_focus (search_bar);
}

static void
search_options_selection_cancel_cb (GtkMenuShell *menu,
                    EShellWindow *shell_window)
{
    /* only disconnect both functions, thus the selection-done is not called */
    g_signal_handlers_disconnect_by_func (menu, search_options_selection_done_cb, shell_window);
    g_signal_handlers_disconnect_by_func (menu, search_options_selection_cancel_cb, shell_window);
}

/**
 * E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS:
 * @window: an #EShellWindow
 *
 * Activation of this action displays a menu of search options.
 * This appears as a "find" icon in the window's search entry.
 **/
static void
action_search_options_cb (GtkAction *action,
                          EShellWindow *shell_window)
{
    EShellView *shell_view;
    EShellViewClass *shell_view_class;
    const gchar *view_name;
    const gchar *widget_path;
    GtkWidget *popup_menu;

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);
    shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);

    widget_path = shell_view_class->search_options;
    popup_menu = e_shell_view_show_popup_menu (shell_view, widget_path, NULL);

    if (popup_menu) {
        g_return_if_fail (GTK_IS_MENU_SHELL (popup_menu));

        g_signal_connect_object (popup_menu, "selection-done",
            G_CALLBACK (search_options_selection_done_cb), shell_window, 0);
        g_signal_connect_object (popup_menu, "cancel",
            G_CALLBACK (search_options_selection_cancel_cb), shell_window, 0);
    }
}

/**
 * E_SHELL_WINDOW_ACTION_SEARCH_QUICK:
 * @window: an #EShellWindow
 *
 * Activation of this action executes the current search conditions.
 *
 * Main menu item: Search -> Find Now
 **/
static void
action_search_quick_cb (GtkAction *action,
                        EShellWindow *shell_window)
{
    EShellView *shell_view;
    const gchar *view_name;

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);

    e_shell_view_execute_search (shell_view);
}

/**
 * E_SHELL_WINDOW_ACTION_SEARCH_SAVE:
 * @window: an #EShellWindow
 *
 * Activation of this action saves the current search conditions.
 *
 * Main menu item: Search -> Save Search...
 **/
static void
action_search_save_cb (GtkAction *action,
                       EShellWindow *shell_window)
{
    EShellView *shell_view;
    EShellContent *shell_content;
    const gchar *view_name;

    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);
    shell_content = e_shell_view_get_shell_content (shell_view);

    e_shell_content_run_save_search_dialog (shell_content);
    e_shell_window_update_search_menu (shell_window);
}

/**
 * E_SHELL_WINDOW_ACTION_SHOW_SIDEBAR:
 * @window: an #EShellWindow
 *
 * This toggle action controls whether the side bar is visible.
 *
 * Main menu item: View -> Layout -> Show Side Bar
 **/

/**
 * E_SHELL_WINDOW_ACTION_SHOW_SWITCHER:
 * @window: an #EShellWindow
 *
 * This toggle action controls whether the switcher buttons are visible.
 *
 * Main menu item: View -> Switcher Appearance -> Show Buttons
 **/

/**
 * E_SHELL_WINDOW_ACTION_SHOW_TASKBAR:
 * @window: an #EShellWindow
 *
 * This toggle action controls whether the task bar is visible.
 *
 * Main menu item: View -> Layout -> Show Status Bar
 **/

/**
 * E_SHELL_WINDOW_ACTION_SHOW_TOOLBAR:
 * @window: an #EShellWindow
 *
 * This toggle action controls whether the tool bar is visible.
 *
 * Main menu item: View -> Layout -> Show Tool Bar
 **/

/**
 * E_SHELL_WINDOW_ACTION_SUBMIT_BUG:
 * @window: an #EShellWindow
 *
 * Activation of this action allows users to report a bug using
 * Bug Buddy.
 *
 * Main menu item: Help -> Submit Bug Report
 **/
static void
action_submit_bug_cb (GtkAction *action,
                      EShellWindow *shell_window)
{
    const gchar *command_line;
    GError *error = NULL;

    command_line = "bug-buddy --package=Evolution";

    g_debug ("Spawning: %s", command_line);
    g_spawn_command_line_async (command_line, &error);

    if (error != NULL) {
        e_notice (
            shell_window, GTK_MESSAGE_ERROR,
            error->code == G_SPAWN_ERROR_NOENT ?
            _("Bug Buddy is not installed.") :
            _("Bug Buddy could not be run."));
        g_error_free (error);
    }
}

static void
action_switcher_cb (GtkRadioAction *action,
                    GtkRadioAction *current,
                    EShellWindow *shell_window)
{
    const gchar *view_name;

    view_name = g_object_get_data (G_OBJECT (current), "view-name");
    e_shell_window_switch_to_view (shell_window, view_name);
}

static void
action_new_view_window_cb (GtkAction *action,
                           EShellWindow *shell_window)
{
    EShell *shell;
    const gchar *view_name;

    shell = e_shell_window_get_shell (shell_window);
    view_name = g_object_get_data (G_OBJECT (action), "view-name");

    fprintf (stderr, "create new window: %s\n", view_name);

    e_shell_create_shell_window (shell, view_name);
}

/**
 * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_BOTH:
 * @window: an #EShellWindow
 *
 * This radio action displays switcher buttons with icons and text.
 *
 * Main menu item: View -> Switcher Appearance -> Icons and Text
 **/

/**
 * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_ICONS:
 * @window: an #EShellWindow
 *
 * This radio action displays switcher buttons with icons only.
 *
 * Main menu item: View -> Switcher Appearance -> Icons Only
 **/

/**
 * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_TEXT:
 * @window: an #EShellWindow
 *
 * This radio action displays switcher buttons with text only.
 *
 * Main menu item: View -> Switcher Appearance -> Text Only
 **/

/**
 * E_SHELL_WINDOW_ACTION_SWITCHER_STYLE_USER:
 * @window: an #EShellWindow
 *
 * This radio action displays switcher buttons according to the desktop
 * toolbar setting.
 *
 * Main menu item: View -> Switcher Appearance -> Toolbar Style
 **/
static void
action_switcher_style_cb (GtkRadioAction *action,
                          GtkRadioAction *current,
                          EShellWindow *shell_window)
{
    EShellSwitcher *switcher;
    GtkToolbarStyle style;

    switcher = E_SHELL_SWITCHER (shell_window->priv->switcher);
    style = gtk_radio_action_get_current_value (action);

    switch (style) {
        case GTK_TOOLBAR_ICONS:
        case GTK_TOOLBAR_TEXT:
        case GTK_TOOLBAR_BOTH:
        case GTK_TOOLBAR_BOTH_HORIZ:
            e_shell_switcher_set_style (switcher, style);
            break;

        default:
            e_shell_switcher_unset_style (switcher);
            break;
    }
}

/**
 * E_SHELL_WINDOW_ACTION_WORK_OFFLINE:
 * @window: an #EShellWindow
 *
 * Activation of this action puts the application into offline mode.
 *
 * Main menu item: File -> Work Offline
 **/
static void
action_work_offline_cb (GtkAction *action,
                        EShellWindow *shell_window)
{
    EShell *shell;
    GSettings *settings;

    shell = e_shell_window_get_shell (shell_window);

    e_shell_set_online (shell, FALSE);

    /* XXX The boolean sense of the setting is backwards.  Would
     *     be more intuitive and less error-prone as "start-online". */
    settings = g_settings_new ("org.gnome.evolution.shell");
    g_settings_set_boolean (settings, "start-offline", TRUE);
    g_object_unref (settings);
}

/**
 * E_SHELL_WINDOW_ACTION_WORK_ONLINE:
 * @window: an #EShellWindow
 *
 * Activation of this action puts the application into online mode.
 *
 * Main menu item: File -> Work Online
 **/
static void
action_work_online_cb (GtkAction *action,
                       EShellWindow *shell_window)
{
    EShell *shell;
    GSettings *settings;

    shell = e_shell_window_get_shell (shell_window);

    e_shell_set_online (shell, TRUE);

    /* XXX The boolean sense of the setting is backwards.  Would
     *     be more intuitive and less error-prone as "start-online". */
    settings = g_settings_new ("org.gnome.evolution.shell");
    g_settings_set_boolean (settings, "start-offline", FALSE);
    g_object_unref (settings);
}

/**
 * E_SHELL_WINDOW_ACTION_GROUP_CUSTOM_RULES:
 * @window: an #EShellWindow
 **/

/**
 * E_SHELL_WINDOW_ACTION_GROUP_GAL_VIEW:
 * @window: an #EShellWindow
 **/

/**
 * E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM:
 * @window: an #EShellWindow
 **/

/**
 * E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE:
 * @window: an #EShellWindow
 **/

/**
 * E_SHELL_WINDOW_ACTION_GROUP_SHELL:
 * @window: an #EShellWindow
 **/

/**
 * E_SHELL_WINDOW_ACTION_GROUP_SWITCHER:
 * @window: an #EShellWindow
 **/

static GtkActionEntry shell_entries[] = {

    { "about",
      "help-about",
      N_("_About"),
      NULL,
      N_("Show information about Evolution"),
      G_CALLBACK (action_about_cb) },

    { "close",
      "window-close",
      N_("_Close Window"),
      "<Control>w",
      N_("Close this window"),
      G_CALLBACK (action_close_cb) },

    { "close-window-menu",
      "window-close",
      N_("_Close"),
      "<Control>w",
      N_("Close this window"),
      G_CALLBACK (action_close_cb) },

    { "close-window",
      "window-close",
      N_("_Close Window"),
      "<Control>w",
      N_("Close this window"),
      G_CALLBACK (action_close_cb) },

    { "contents",
      "help-browser",
      N_("_Contents"),
      "F1",
      N_("Open the Evolution User Guide"),
      G_CALLBACK (action_contents_cb) },

    { "copy-clipboard",
      "edit-copy",
      N_("_Copy"),
      "<Control>c",
      N_("Copy the selection"),
      NULL },  /* Handled by EFocusTracker */

    { "cut-clipboard",
      "edit-cut",
      N_("Cu_t"),
      "<Control>x",
      N_("Cut the selection"),
      NULL },  /* Handled by EFocusTracker */

    { "delete-selection",
      "edit-delete",
      N_("_Delete"),
      NULL,
      N_("Delete the selection"),
      NULL },  /* Handled by EFocusTracker */

    { "import",
      "stock_mail-import",
      N_("I_mport..."),
      NULL,
      N_("Import data from other programs"),
      G_CALLBACK (action_import_cb) },

    { "new-window",
      "window-new",
      N_("New _Window"),
      "<Control><Shift>w",
      N_("Create a new window displaying this view"),
      G_CALLBACK (action_new_window_cb) },

    { "paste-clipboard",
      "edit-paste",
      N_("_Paste"),
      "<Control>v",
      N_("Paste the clipboard"),
      NULL },  /* Handled by EFocusTracker */

    { "categories",
      NULL,
      N_("Available Cate_gories"),
      NULL,
      N_("Manage available categories"),
      G_CALLBACK (action_categories_cb) },

    { "preferences",
      "preferences-system",
      N_("_Preferences"),
      "<Control><Shift>s",
      N_("Configure Evolution"),
      G_CALLBACK (action_preferences_cb) },

    { "quick-reference",
      NULL,
      N_("_Quick Reference"),
      NULL,
      N_("Show Evolution's shortcut keys"),
      G_CALLBACK (action_quick_reference_cb) },

    { "quit",
      "application-exit",
      N_("_Quit"),
      "<Control>q",
      N_("Exit the program"),
      G_CALLBACK (action_quit_cb) },

    { "search-advanced",
      NULL,
      N_("_Advanced Search..."),
      NULL,
      N_("Construct a more advanced search"),
      G_CALLBACK (action_search_advanced_cb) },

    { "search-clear",
      "edit-clear",
      N_("_Clear"),
      "<Control><Shift>q",
      N_("Clear the current search parameters"),
      G_CALLBACK (action_search_clear_cb) },

    { "search-edit",
      NULL,
      N_("_Edit Saved Searches..."),
      NULL,
      N_("Manage your saved searches"),
      G_CALLBACK (action_search_edit_cb) },

    { "search-options",
      "edit-find",
      N_("_Find"),
      "<Control>f",
      N_("Click here to change the search type"),
      G_CALLBACK (action_search_options_cb) },

    { "search-quick",
      "edit-find",
      N_("_Find Now"),
      NULL,
      N_("Execute the current search parameters"),
      G_CALLBACK (action_search_quick_cb) },

    { "search-save",
      NULL,
      N_("_Save Search..."),
      NULL,
      N_("Save the current search parameters"),
      G_CALLBACK (action_search_save_cb) },

    { "select-all",
      "edit-select-all",
      N_("Select _All"),
      "<Control>a",
      N_("Select all text"),
      NULL },  /* Handled by EFocusTracker */

    { "submit-bug",
      NULL,
      N_("Submit _Bug Report..."),
      NULL,
      N_("Submit a bug report using Bug Buddy"),
      G_CALLBACK (action_submit_bug_cb) },

    { "work-offline",
      "stock_disconnect",
      N_("_Work Offline"),
      NULL,
      N_("Put Evolution into offline mode"),
      G_CALLBACK (action_work_offline_cb) },

    { "work-online",
      "stock_connect",
      N_("_Work Online"),
      NULL,
      N_("Put Evolution into online mode"),
      G_CALLBACK (action_work_online_cb) },

    /*** Menus ***/

    { "edit-menu",
      NULL,
      N_("_Edit"),
      NULL,
      NULL,
      NULL },

    { "file-menu",
      NULL,
      N_("_File"),
      NULL,
      NULL,
      NULL },

    { "help-menu",
      NULL,
      N_("_Help"),
      NULL,
      NULL,
      NULL },

    { "layout-menu",
      NULL,
      N_("Lay_out"),
      NULL,
      NULL,
      NULL },

    { "new-menu",
      "document-new",
      N_("_New"),
      NULL,
      NULL,
      NULL },

    { "search-menu",
      NULL,
      N_("_Search"),
      NULL,
      NULL,
      NULL },

    { "switcher-menu",
      NULL,
      N_("_Switcher Appearance"),
      NULL,
      NULL,
      NULL },

    { "view-menu",
      NULL,
      N_("_View"),
      NULL,
      NULL,
      NULL },

    { "window-menu",
      NULL,
      N_("_Window"),
      NULL,
      NULL,
      NULL }
};

static EPopupActionEntry shell_popup_entries[] = {

    { "popup-copy-clipboard",
      NULL,
      "copy-clipboard" },

    { "popup-cut-clipboard",
      NULL,
      "cut-clipboard" },

    { "popup-delete-selection",
      NULL,
      "delete-selection" },

    { "popup-paste-clipboard",
      NULL,
      "paste-clipboard" }
};

static GtkToggleActionEntry shell_toggle_entries[] = {

    { "show-sidebar",
      NULL,
      N_("Show Side _Bar"),
      "F9",
      N_("Show the side bar"),
      NULL,
      TRUE },

    { "show-switcher",
      NULL,
      N_("Show _Buttons"),
      NULL,
      N_("Show the switcher buttons"),
      NULL,
      TRUE },

    { "show-taskbar",
      NULL,
      N_("Show _Status Bar"),
      NULL,
      N_("Show the status bar"),
      NULL,
      TRUE },

    { "show-toolbar",
      NULL,
      N_("Show _Tool Bar"),
      NULL,
      N_("Show the tool bar"),
      NULL,
      TRUE }
};

static GtkRadioActionEntry shell_switcher_entries[] = {

    /* This action represents the initial active shell view.
     * It should not be visible in the UI, nor should it be
     * possible to switch to it from another shell view. */
    { "switcher-initial",
      NULL,
      NULL,
      NULL,
      NULL,
      -1 }
};

static GtkRadioActionEntry shell_switcher_style_entries[] = {

    { "switcher-style-icons",
      NULL,
      N_("_Icons Only"),
      NULL,
      N_("Display window buttons with icons only"),
      GTK_TOOLBAR_ICONS },

    { "switcher-style-text",
      NULL,
      N_("_Text Only"),
      NULL,
      N_("Display window buttons with text only"),
      GTK_TOOLBAR_TEXT },

    { "switcher-style-both",
      NULL,
      N_("Icons _and Text"),
      NULL,
      N_("Display window buttons with icons and text"),
      GTK_TOOLBAR_BOTH_HORIZ },

    { "switcher-style-user",
      NULL,
      N_("Tool_bar Style"),
      NULL,
      N_("Display window buttons using the desktop toolbar setting"),
      -1 }
};

static GtkActionEntry shell_gal_view_entries[] = {

    { "gal-delete-view",
      NULL,
      N_("Delete Current View"),
      NULL,
      NULL,  /* Set in update_view_menu */
      G_CALLBACK (action_gal_delete_view_cb) },

    { "gal-save-custom-view",
      NULL,
      N_("Save Custom View..."),
      NULL,
      N_("Save current custom view"),
      G_CALLBACK (action_gal_save_custom_view_cb) },

    /*** Menus ***/

    { "gal-view-menu",
      NULL,
      N_("C_urrent View"),
      NULL,
      NULL,
      NULL }
};

static GtkRadioActionEntry shell_gal_view_radio_entries[] = {

    { "gal-custom-view",
      NULL,
      N_("Custom View"),
      NULL,
      N_("Current view is a customized view"),
      -1 }
};

static GtkActionEntry shell_lockdown_print_setup_entries[] = {

    { "page-setup",
      "document-page-setup",
      N_("Page Set_up..."),
      NULL,
      N_("Change the page settings for your current printer"),
      G_CALLBACK (action_page_setup_cb) }
};

static void
shell_window_extract_actions (EShellWindow *shell_window,
                              GList **source_list,
                              GList **destination_list)
{
    const gchar *current_view;
    GList *match_list = NULL;
    GList *iter;

    /* Pick out the actions from the source list that are tagged
     * as belonging to the current EShellView and move them to the
     * destination list. */

    current_view = e_shell_window_get_active_view (shell_window);

    /* Example: Suppose [A] and [C] are tagged for this EShellView.
     *
     *        source_list = [A] -> [B] -> [C]
     *                       ^             ^
     *                       |             |
     *         match_list = [ ] --------> [ ]
     *
     *
     *   destination_list = [1] -> [2]  (other actions)
     */
    for (iter = *source_list; iter != NULL; iter = iter->next) {
        GtkAction *action = iter->data;
        const gchar *backend_name;

        backend_name = g_object_get_data (
            G_OBJECT (action), "backend-name");

        if (strcmp (backend_name, current_view) != 0)
            continue;

        if (g_object_get_data (G_OBJECT (action), "primary"))
            match_list = g_list_prepend (match_list, iter);
        else
            match_list = g_list_append (match_list, iter);
    }

    /* source_list = [B]   match_list = [A] -> [C] */
    for (iter = match_list; iter != NULL; iter = iter->next) {
        GList *link = iter->data;

        iter->data = link->data;
        *source_list = g_list_delete_link (*source_list, link);
    }

    /* destination_list = [1] -> [2] -> [A] -> [C] */
    *destination_list = g_list_concat (*destination_list, match_list);
}

void
e_shell_window_actions_init (EShellWindow *shell_window)
{
    GtkActionGroup *action_group;
    EFocusTracker *focus_tracker;
    GtkUIManager *ui_manager;
    gchar *path;

    g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));

    ui_manager = e_shell_window_get_ui_manager (shell_window);

    e_load_ui_manager_definition (ui_manager, "evolution-shell.ui");

    /* Shell Actions */
    action_group = ACTION_GROUP (SHELL);
    gtk_action_group_add_actions (
        action_group, shell_entries,
        G_N_ELEMENTS (shell_entries), shell_window);
    e_action_group_add_popup_actions (
        action_group, shell_popup_entries,
        G_N_ELEMENTS (shell_popup_entries));
    gtk_action_group_add_toggle_actions (
        action_group, shell_toggle_entries,
        G_N_ELEMENTS (shell_toggle_entries), shell_window);
    gtk_action_group_add_radio_actions (
        action_group, shell_switcher_style_entries,
        G_N_ELEMENTS (shell_switcher_style_entries),
        E_SHELL_SWITCHER_DEFAULT_TOOLBAR_STYLE,
        G_CALLBACK (action_switcher_style_cb), shell_window);
    gtk_action_group_add_actions (
        action_group, shell_gal_view_entries,
        G_N_ELEMENTS (shell_gal_view_entries), shell_window);
    gtk_action_group_add_radio_actions (
        action_group, shell_gal_view_radio_entries,
        G_N_ELEMENTS (shell_gal_view_radio_entries),
        0, G_CALLBACK (action_gal_view_cb), shell_window);

    /* Switcher Actions */
    action_group = ACTION_GROUP (SWITCHER);
    gtk_action_group_add_radio_actions (
        action_group, shell_switcher_entries,
        G_N_ELEMENTS (shell_switcher_entries),
        -1, G_CALLBACK (action_switcher_cb), shell_window);

    /* Lockdown Print Setup Actions */
    action_group = ACTION_GROUP (LOCKDOWN_PRINT_SETUP);
    gtk_action_group_add_actions (
        action_group, shell_lockdown_print_setup_entries,
        G_N_ELEMENTS (shell_lockdown_print_setup_entries),
        shell_window);

    /* Configure an EFocusTracker to manage selection actions. */

    focus_tracker = e_focus_tracker_new (GTK_WINDOW (shell_window));
    e_focus_tracker_set_cut_clipboard_action (
        focus_tracker, ACTION (CUT_CLIPBOARD));
    e_focus_tracker_set_copy_clipboard_action (
        focus_tracker, ACTION (COPY_CLIPBOARD));
    e_focus_tracker_set_paste_clipboard_action (
        focus_tracker, ACTION (PASTE_CLIPBOARD));
    e_focus_tracker_set_delete_selection_action (
        focus_tracker, ACTION (DELETE_SELECTION));
    e_focus_tracker_set_select_all_action (
        focus_tracker, ACTION (SELECT_ALL));
    shell_window->priv->focus_tracker = focus_tracker;

    /* Fine tuning. */

    gtk_action_set_sensitive (ACTION (SEARCH_QUICK), FALSE);

    g_object_bind_property (
        shell_window, "sidebar-visible",
        ACTION (SHOW_SIDEBAR), "active",
        G_BINDING_BIDIRECTIONAL |
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        shell_window, "switcher-visible",
        ACTION (SHOW_SWITCHER), "active",
        G_BINDING_BIDIRECTIONAL |
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        shell_window, "taskbar-visible",
        ACTION (SHOW_TASKBAR), "active",
        G_BINDING_BIDIRECTIONAL |
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        shell_window, "toolbar-visible",
        ACTION (SHOW_TOOLBAR), "active",
        G_BINDING_BIDIRECTIONAL |
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        ACTION (SHOW_SIDEBAR), "active",
        ACTION (SHOW_SWITCHER), "sensitive",
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        ACTION (SHOW_SIDEBAR), "active",
        ACTION (SWITCHER_STYLE_BOTH), "sensitive",
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        ACTION (SHOW_SIDEBAR), "active",
        ACTION (SWITCHER_STYLE_ICONS), "sensitive",
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        ACTION (SHOW_SIDEBAR), "active",
        ACTION (SWITCHER_STYLE_TEXT), "sensitive",
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        ACTION (SHOW_SIDEBAR), "active",
        ACTION (SWITCHER_STYLE_USER), "sensitive",
        G_BINDING_SYNC_CREATE);

    g_object_bind_property (
        ACTION (SHOW_SIDEBAR), "active",
        ACTION (SWITCHER_MENU), "sensitive",
        G_BINDING_SYNC_CREATE);

    /* Submitting bug reports requires bug-buddy. */
    path = g_find_program_in_path ("bug-buddy");
    if (path == NULL)
        gtk_action_set_visible (ACTION (SUBMIT_BUG), FALSE);
    g_free (path);
}

GtkWidget *
e_shell_window_create_new_menu (EShellWindow *shell_window)
{
    GtkActionGroup *action_group;
    GList *new_item_actions;
    GList *new_source_actions;
    GList *iter, *list = NULL;
    GtkWidget *menu;
    GtkWidget *separator;

    /* Get sorted lists of "new item" and "new source" actions. */

    action_group = ACTION_GROUP (NEW_ITEM);

    new_item_actions = g_list_sort (
        gtk_action_group_list_actions (action_group),
        (GCompareFunc) e_action_compare_by_label);

    action_group = ACTION_GROUP (NEW_SOURCE);

    new_source_actions = g_list_sort (
        gtk_action_group_list_actions (action_group),
        (GCompareFunc) e_action_compare_by_label);

    /* Give priority to actions that belong to this shell view. */

    shell_window_extract_actions (
        shell_window, &new_item_actions, &list);

    shell_window_extract_actions (
        shell_window, &new_source_actions, &list);

    /* Convert the actions to menu item proxy widgets. */

    for (iter = list; iter != NULL; iter = iter->next)
        iter->data = gtk_action_create_menu_item (iter->data);

    for (iter = new_item_actions; iter != NULL; iter = iter->next)
        iter->data = gtk_action_create_menu_item (iter->data);

    for (iter = new_source_actions; iter != NULL; iter = iter->next)
        iter->data = gtk_action_create_menu_item (iter->data);

    /* Add menu separators. */

    if (new_item_actions != NULL) {
        separator = gtk_separator_menu_item_new ();
        new_item_actions = g_list_prepend (new_item_actions, separator);
        gtk_widget_show (GTK_WIDGET (separator));
    }

    if (new_source_actions != NULL) {
        separator = gtk_separator_menu_item_new ();
        new_source_actions = g_list_prepend (new_source_actions, separator);
        gtk_widget_show (GTK_WIDGET (separator));
    }

    /* Merge everything into one list, reflecting the menu layout. */

    list = g_list_concat (list, new_item_actions);
    new_item_actions = NULL;    /* just for clarity */

    list = g_list_concat (list, new_source_actions);
    new_source_actions = NULL;  /* just for clarity */

    /* And finally, build the menu. */

    menu = gtk_menu_new ();

    for (iter = list; iter != NULL; iter = iter->next)
        gtk_menu_shell_append (GTK_MENU_SHELL (menu), iter->data);

    g_list_free (list);

    return menu;
}

static GtkAction *
e_shell_window_create_switcher_action (GType type,
                                       EShellViewClass *class,
                                       const gchar *name,
                                       const gchar *tooltip,
                                       const gchar *view_name)
{
    GtkAction *action;

    action = g_object_new (
        type,
        "name", name,
        "label", class->label,
        "tooltip", tooltip,
        "icon-name", class->icon_name,
        NULL);

    g_object_set_data (
        G_OBJECT (action),
        "view-name", (gpointer) view_name);

    return action;
}

/*
 * Create both the actions to switch the current window, and also
 * to create each view in a new window.
 */
void
e_shell_window_create_switcher_actions (EShellWindow *shell_window)
{
    GSList *group = NULL;
    GtkRadioAction *s_action;
    GtkActionGroup *s_action_group;
    GtkActionGroup *n_action_group;
    GtkUIManager *ui_manager;
    EShellSwitcher *switcher;
    EShell *shell;
    GList *list, *iter;
    guint merge_id;
    guint ii = 0;

    g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));

    s_action_group = ACTION_GROUP (SWITCHER);
    n_action_group = ACTION_GROUP (NEW_WINDOW);
    switcher = E_SHELL_SWITCHER (shell_window->priv->switcher);
    ui_manager = e_shell_window_get_ui_manager (shell_window);
    merge_id = gtk_ui_manager_new_merge_id (ui_manager);
    shell = e_shell_window_get_shell (shell_window);
    list = e_shell_get_shell_backends (shell);

    /* Construct a group of radio actions from the various EShellView
     * subclasses and register them with the EShellSwitcher.  These
     * actions are manifested as switcher buttons and View->Window
     * menu items. */

    s_action = GTK_RADIO_ACTION (ACTION (SWITCHER_INITIAL));
    gtk_radio_action_set_group (s_action, group);
    group = gtk_radio_action_get_group (s_action);

    for (iter = list; iter != NULL; iter = iter->next) {
        EShellBackend *shell_backend = iter->data;
        EShellBackendClass *backend_class;
        EShellViewClass *class;
        GtkAction *n_action;
        GType view_type;
        const gchar *view_name;
        gchar *accelerator;
        gchar *s_action_name;
        gchar *n_action_name;
        gchar *tooltip;

        /* The backend name is also the view name. */
        backend_class = E_SHELL_BACKEND_GET_CLASS (shell_backend);
        view_type = backend_class->shell_view_type;
        view_name = backend_class->name;

        if (!g_type_is_a (view_type, E_TYPE_SHELL_VIEW)) {
            g_critical (
                "%s is not a subclass of %s",
                g_type_name (view_type),
                g_type_name (E_TYPE_SHELL_VIEW));
            continue;
        }

        class = g_type_class_ref (view_type);

        if (class->label == NULL) {
            g_critical (
                "Label member not set on %s",
                G_OBJECT_CLASS_NAME (class));
            continue;
        }

        tooltip = g_strdup_printf (_("Switch to %s"), class->label);

        s_action_name = g_strdup_printf (
            E_SHELL_SWITCHER_FORMAT, view_name);

        /* Note, we have to set "icon-name" separately because
         * gtk_radio_action_new() expects a "stock-id".  Sadly,
         * GTK+ still distinguishes between the two. */

        s_action = GTK_RADIO_ACTION (
            e_shell_window_create_switcher_action (
                GTK_TYPE_RADIO_ACTION,
                class, s_action_name,
                tooltip, view_name));
        g_object_set (s_action, "value", ii++, NULL);
        gtk_radio_action_set_group (s_action, group);
        group = gtk_radio_action_get_group (s_action);

        /* The first nine views have accelerators Ctrl+(1-9). */
        if (ii < 10)
            accelerator = g_strdup_printf ("<Control>%d", ii);
        else
            accelerator = g_strdup ("");

        gtk_action_group_add_action_with_accel (
            s_action_group, GTK_ACTION (s_action), accelerator);

        g_free (accelerator);

        gtk_ui_manager_add_ui (
            ui_manager, merge_id,
            "/main-menu/view-menu/window-menu",
            s_action_name, s_action_name,
            GTK_UI_MANAGER_AUTO, FALSE);
        g_free (s_action_name);

        /* Create in new window actions */
        n_action_name = g_strdup_printf (
            E_SHELL_NEW_WINDOW_FORMAT, view_name);
        n_action = e_shell_window_create_switcher_action (
            GTK_TYPE_ACTION,
            class, n_action_name,
            tooltip, view_name);
        g_signal_connect (
            n_action, "activate",
            G_CALLBACK (action_new_view_window_cb), shell_window);
        gtk_action_group_add_action (n_action_group, n_action);

        e_shell_switcher_add_action (
            switcher, GTK_ACTION (s_action), n_action);

        g_free (n_action_name);
        g_free (tooltip);

        g_type_class_unref (class);
    }
}

void
e_shell_window_update_view_menu (EShellWindow *shell_window)
{
    EShellView *shell_view;
    EShellViewClass *shell_view_class;
    GtkUIManager *ui_manager;
    GtkActionGroup *action_group;
    GalViewCollection *view_collection;
    GtkRadioAction *radio_action;
    GtkAction *action;
    GSList *radio_group;
    gboolean visible;
    const gchar *path;
    const gchar *view_id;
    const gchar *view_name;
    gchar *delete_tooltip = NULL;
    gboolean delete_visible = FALSE;
    guint merge_id;
    gint count, ii;

    ui_manager = e_shell_window_get_ui_manager (shell_window);
    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);
    g_return_if_fail (shell_view != NULL);

    shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
    view_collection = shell_view_class->view_collection;
    view_id = e_shell_view_get_view_id (shell_view);
    g_return_if_fail (view_collection != NULL);

    action_group = ACTION_GROUP (GAL_VIEW);
    merge_id = shell_window->priv->gal_view_merge_id;

    /* Unmerge the previous menu. */
    gtk_ui_manager_remove_ui (ui_manager, merge_id);
    e_action_group_remove_all_actions (action_group);
    gtk_ui_manager_ensure_update (ui_manager);

    /* We have a view ID, so forge ahead. */
    count = gal_view_collection_get_count (view_collection);
    path = "/main-menu/view-menu/gal-view-menu/gal-view-list";

    /* Prevent spurious activations. */
    action = ACTION (GAL_CUSTOM_VIEW);
    g_signal_handlers_block_matched (
        action, G_SIGNAL_MATCH_FUNC, 0, 0,
        NULL, action_gal_view_cb, NULL);

    /* Default to "Custom View", unless we find our view ID. */
    radio_action = GTK_RADIO_ACTION (ACTION (GAL_CUSTOM_VIEW));
    gtk_radio_action_set_group (radio_action, NULL);
    radio_group = gtk_radio_action_get_group (radio_action);
    gtk_radio_action_set_current_value (radio_action, -1);

    /* Add a menu item for each view collection item. */
    for (ii = 0; ii < count; ii++) {
        GalViewCollectionItem *item;
        gchar *action_name;
        gchar *tooltip, *title;

        item = gal_view_collection_get_view_item (view_collection, ii);

        action_name = g_strdup_printf (
            "gal-view-%s-%d", view_name, ii);
        title = e_str_without_underscores (item->title);
        tooltip = g_strdup_printf (_("Select view: %s"), title);

        radio_action = gtk_radio_action_new (
            action_name, item->title, tooltip, NULL, ii);

        action = GTK_ACTION (radio_action);
        gtk_radio_action_set_group (radio_action, radio_group);
        radio_group = gtk_radio_action_get_group (radio_action);

        g_object_set_data_full (
            G_OBJECT (radio_action), "view-id",
            g_strdup (item->id), (GDestroyNotify) g_free);

        if (view_id != NULL && strcmp (item->id, view_id) == 0) {
            gtk_radio_action_set_current_value (radio_action, ii);
            delete_visible = (!item->built_in);
            delete_tooltip = g_strdup_printf (
                _("Delete view: %s"), title);
        }

        gtk_action_group_add_action (action_group, action);

        gtk_ui_manager_add_ui (
            ui_manager, merge_id,
            path, action_name, action_name,
            GTK_UI_MANAGER_AUTO, FALSE);

        g_free (action_name);
        g_free (tooltip);
        g_free (title);
    }

    /* Doesn't matter which radio action we check. */
    visible = (gtk_radio_action_get_current_value (radio_action) < 0);

    action = ACTION (GAL_CUSTOM_VIEW);
    gtk_action_set_visible (action, visible);
    g_signal_handlers_unblock_matched (
        action, G_SIGNAL_MATCH_FUNC, 0, 0,
        NULL, action_gal_view_cb, NULL);

    action = ACTION (GAL_SAVE_CUSTOM_VIEW);
    gtk_action_set_visible (action, visible);

    action = ACTION (GAL_DELETE_VIEW);
    gtk_action_set_tooltip (action, delete_tooltip);
    gtk_action_set_visible (action, delete_visible);

    g_free (delete_tooltip);
}

void
e_shell_window_update_search_menu (EShellWindow *shell_window)
{
    EShellView *shell_view;
    EShellViewClass *shell_view_class;
    ERuleContext *context;
    EFilterRule *rule;
    GtkUIManager *ui_manager;
    GtkActionGroup *action_group;
    const gchar *source;
    const gchar *view_name;
    gboolean sensitive;
    guint merge_id;
    gint ii = 0;

    g_return_if_fail (E_IS_SHELL_WINDOW (shell_window));

    ui_manager = e_shell_window_get_ui_manager (shell_window);
    view_name = e_shell_window_get_active_view (shell_window);
    shell_view = e_shell_window_get_shell_view (shell_window, view_name);

    /* Check for a NULL shell view before proceeding.  This can
     * happen if the initial view name from GSettings is unrecognized.
     * Without this we would crash at E_SHELL_VIEW_GET_CLASS(). */
    g_return_if_fail (shell_view != NULL);

    shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
    context = shell_view_class->search_context;

    source = E_FILTER_SOURCE_INCOMING;

    /* Update sensitivity of search_options action. */
    sensitive = (shell_view_class->search_options != NULL);
    gtk_action_set_sensitive (ACTION (SEARCH_OPTIONS), sensitive);

    /* Add custom rules to the Search menu. */

    action_group = ACTION_GROUP (CUSTOM_RULES);
    merge_id = shell_window->priv->custom_rule_merge_id;

    /* Unmerge the previous menu. */
    gtk_ui_manager_remove_ui (ui_manager, merge_id);
    e_action_group_remove_all_actions (action_group);
    gtk_ui_manager_ensure_update (ui_manager);

    rule = e_rule_context_next_rule (context, NULL, source);
    while (rule != NULL) {
        GtkAction *action;
        gchar *action_name;
        gchar *action_label;

        action_name = g_strdup_printf ("custom-rule-%d", ii++);
        if (ii < 10)
            action_label = g_strdup_printf (
                "_%d. %s", ii, rule->name);
        else
            action_label = g_strdup (rule->name);

        action = gtk_action_new (
            action_name, action_label,
            _("Execute these search parameters"), NULL);

        g_object_set_data_full (
            G_OBJECT (action),
            "rule", g_object_ref (rule),
            (GDestroyNotify) g_object_unref);

        g_signal_connect (
            action, "activate",
            G_CALLBACK (action_custom_rule_cb), shell_window);

        gtk_action_group_add_action (action_group, action);

        gtk_ui_manager_add_ui (
            ui_manager, merge_id,
            "/main-menu/search-menu/custom-rules",
            action_name, action_name,
            GTK_UI_MANAGER_AUTO, FALSE);

        g_free (action_name);
        g_free (action_label);

        rule = e_rule_context_next_rule (context, rule, source);
    }
}