aboutsummaryrefslogblamecommitdiffstats
path: root/shell/e-shell-view.c
blob: 1187c17ee48e3d6e04256181070047db576bcf9d (plain) (tree)
1
2
3
4
5


                                                                        
                                                        
  










                                                                    

                                                                   

   
                         
 
                       
 
                           
                                   
 


                                                      

                           







                                            

  

                             































































































                                                                          
           
                                              
                                         
 


                                                  
 

                                                              


           



                                             
 














                                                                       

 





















                                                                       
 

                                    
 
                                
 
                                                 
 




                                                                
 

                                                        


           
                                     
 
                                
 
                                                 
 
                             
 

                                                         

 









































































                                                                            
           
                                              
 
                                   
 








                                                                     

                                                            




















                                                                        


           
                                        
 
                                                                 

 

                            
 






















                                                               
 












                                                                  
 

                                                   
 
                                                         

 
           







                                                                  












                                                                    
                                                        
 







                                                                       

 

                                                        
 


                                                                  
 

                                                                       
 
                                                      

 





                                                                  
 




                                                                      



































                                                                        
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
 * e-shell-view.c
 *
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU 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 General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "e-shell-view.h"

#include <glib/gi18n.h>

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

#define E_SHELL_VIEW_GET_PRIVATE(obj) \
    (G_TYPE_INSTANCE_GET_PRIVATE \
    ((obj), E_TYPE_SHELL_VIEW, EShellViewPrivate))

struct _EShellViewPrivate {
    gchar *title;
    gpointer window;  /* weak pointer */
};

enum {
    PROP_0,
    PROP_TITLE,
    PROP_WINDOW
};

static gpointer parent_class;

static gint
shell_view_compare_actions (GtkAction *action1,
                            GtkAction *action2)
{
    gchar *label1, *label2;
    gint result;

    /* XXX This is really inefficient, but we're only sorting
     *     a small number of actions (repeatedly, though). */

    g_object_get (action1, "label", &label1, NULL);
    g_object_get (action2, "label", &label2, NULL);

    result = g_utf8_collate (label1, label2);

    g_free (label1);
    g_free (label2);

    return result;
}

static void
shell_view_extract_actions (EShellView *shell_view,
                            GList **source_list,
                GList **destination_list)
{
    GList *match_list = NULL;
    GList *iter;

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

    /* 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;
        EShellView *action_shell_view;

        action_shell_view = g_object_get_data (
            G_OBJECT (action), "shell-view");

        if (action_shell_view != shell_view)
            continue;

        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);
}

static void
shell_view_register_new_actions (EShellView *shell_view,
                                 GtkActionGroup *action_group,
                                 const GtkActionEntry *entries,
                                 guint n_entries)
{
    guint ii;

    gtk_action_group_add_actions (
        action_group, entries, n_entries, shell_view);

    /* Tag each action with the shell view that registered it.
     * This is used to help sort items in the "New" menu. */

    for (ii = 0; ii < n_entries; ii++) {
        const gchar *action_name;
        GtkAction *action;

        action_name = entries[ii].name;

        action = gtk_action_group_get_action (
            action_group, action_name);

        g_object_set_data (
            G_OBJECT (action), "shell-view", shell_view);
    }
}

static void
shell_view_set_window (EShellView *shell_view,
                       GtkWidget *window)
{
    g_return_if_fail (GTK_IS_WINDOW (window));

    shell_view->priv->window = window;

    g_object_add_weak_pointer (
        G_OBJECT (window), &shell_view->priv->window);
}

static void
shell_view_set_property (GObject *object,
                         guint property_id,
                         const GValue *value,
                         GParamSpec *pspec)
{
    switch (property_id) {
        case PROP_TITLE:
            e_shell_view_set_title (
                E_SHELL_VIEW (object),
                g_value_get_string (value));
            return;

        case PROP_WINDOW:
            shell_view_set_window (
                E_SHELL_VIEW (object),
                g_value_get_object (value));
            return;
    }

    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}

static void
shell_view_get_property (GObject *object,
                         guint property_id,
                         GValue *value,
                         GParamSpec *pspec)
{
    switch (property_id) {
        case PROP_TITLE:
            g_value_set_string (
                value, e_shell_view_get_title (
                E_SHELL_VIEW (object)));
            return;

        case PROP_WINDOW:
            g_value_set_object (
                value, e_shell_view_get_window (
                E_SHELL_VIEW (object)));
            return;
    }

    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}

static void
shell_view_dispose (GObject *object)
{
    EShellViewPrivate *priv;

    priv = E_SHELL_VIEW_GET_PRIVATE (object);

    if (priv->window != NULL) {
        g_object_remove_weak_pointer (
            G_OBJECT (priv->window), &priv->window);
        priv->window = NULL;
    }

    /* Chain up to parent's dispose() method. */
    G_OBJECT_CLASS (parent_class)->dispose (object);
}

static void
shell_view_finalize (GObject *object)
{
    EShellViewPrivate *priv;

    priv = E_SHELL_VIEW_GET_PRIVATE (object);

    g_free (priv->title);

    /* Chain up to parent's finalize() method. */
    G_OBJECT_CLASS (parent_class)->finalize (object);
}

static GtkWidget *
shell_view_create_new_menu (EShellView *shell_view)
{
    GtkActionGroup *action_group;
    GList *new_item_actions;
    GList *new_source_actions;
    GList *iter, *list = NULL;
    GtkWidget *menu;
    GtkWidget *separator;
    GtkWidget *window;

    window = e_shell_view_get_window (shell_view);

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

    action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM (window);

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

    action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE (window);

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

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

    shell_view_extract_actions (
        shell_view, &new_item_actions, &list);

    shell_view_extract_actions (
        shell_view, &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. */

    separator = gtk_separator_menu_item_new ();
    new_item_actions = g_list_prepend (new_item_actions, separator);

    separator = gtk_separator_menu_item_new ();
    new_source_actions = g_list_prepend (new_source_actions, 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 void
shell_view_class_init (EShellViewClass *class)
{
    GObjectClass *object_class;

    parent_class = g_type_class_peek_parent (class);
    g_type_class_add_private (class, sizeof (EShellViewPrivate));

    object_class = G_OBJECT_CLASS (class);
    object_class->set_property = shell_view_set_property;
    object_class->get_property = shell_view_get_property;
    object_class->dispose = shell_view_dispose;
    object_class->finalize = shell_view_finalize;

    class->create_new_menu = shell_view_create_new_menu;

    g_object_class_install_property (
        object_class,
        PROP_TITLE,
        g_param_spec_string (
            "title",
            _("Title"),
            _("The title of the shell view"),
            NULL,
            G_PARAM_READWRITE |
            G_PARAM_CONSTRUCT));

    g_object_class_install_property (
        object_class,
        PROP_WINDOW,
        g_param_spec_object (
            "window",
            _("Window"),
            _("The window to which the shell view belongs"),
            GTK_TYPE_WINDOW,
            G_PARAM_READWRITE |
            G_PARAM_CONSTRUCT_ONLY));
}

static void
shell_view_init (EShellView *shell_view)
{
    shell_view->priv = E_SHELL_VIEW_GET_PRIVATE (shell_view);
}

GType
e_shell_view_get_type (void)
{
    static GType type = 0;

    if (G_UNLIKELY (type == 0)) {
        const GTypeInfo type_info = {
            sizeof (EShellViewClass),
            (GBaseInitFunc) NULL,
            (GBaseFinalizeFunc) NULL,
            (GClassInitFunc) shell_view_class_init,
            (GClassFinalizeFunc) NULL,
            NULL,  /* class_data */
            sizeof (EShellView),
            0,     /* n_preallocs */
            (GInstanceInitFunc) shell_view_init,
            NULL   /* value_table */
        };

        type = g_type_register_static (
            G_TYPE_OBJECT, "EShellView",
            &type_info, G_TYPE_FLAG_ABSTRACT);
    }

    return type;
}

const gchar *
e_shell_view_get_title (EShellView *shell_view)
{
    g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);

    return shell_view->priv->title;
}

void
e_shell_view_set_title (EShellView *shell_view,
                        const gchar *title)
{
    g_return_if_fail (E_IS_SHELL_VIEW (shell_view));

    g_free (shell_view->priv->title);
    shell_view->priv->title = g_strdup (title);

    g_object_notify (G_OBJECT (shell_view), "title");
}

GtkWidget *
e_shell_view_get_window (EShellView *shell_view)
{
    g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);

    return shell_view->priv->window;
}

GtkWidget *
e_shell_view_create_new_menu (EShellView *shell_view)
{
    EShellViewClass *class;

    g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);

    class = E_SHELL_VIEW_CLASS (shell_view);
    g_return_val_if_fail (class->create_new_menu != NULL, NULL);

    return class->create_new_menu (shell_view);
}

GtkWidget *
e_shell_view_get_content_widget (EShellView *shell_view)
{
    EShellViewClass *class;

    g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);

    class = E_SHELL_VIEW_CLASS (shell_view);
    g_return_val_if_fail (class->get_content_widget != NULL, NULL);

    return class->get_content_widget (shell_view);
}

GtkWidget *
e_shell_view_get_sidebar_widget (EShellView *shell_view)
{
    EShellViewClass *class;

    g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);

    class = E_SHELL_VIEW_CLASS (shell_view);
    g_return_val_if_fail (class->get_sidebar_widget != NULL, NULL);

    return class->get_sidebar_widget (shell_view);
}

GtkWidget *
e_shell_view_get_status_widget (EShellView *shell_view)
{
    EShellViewClass *class;

    g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);

    class = E_SHELL_VIEW_CLASS (shell_view);
    g_return_val_if_fail (class->get_status_widget != NULL, NULL);

    return class->get_status_widget (shell_view);
}

void
e_shell_view_register_new_item_actions (EShellView *shell_view,
                                        const GtkActionEntry *entries,
                                        guint n_entries)
{
    GtkWidget *window;
    GtkActionGroup *action_group;

    g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
    g_return_if_fail (entries != NULL);

    window = e_shell_view_get_window (shell_view);
    action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_ITEM (window);

    shell_view_register_new_actions (
        shell_view, action_group, entries, n_entries);
}

void
e_shell_view_register_new_source_actions (EShellView *shell_view,
                                          const GtkActionEntry *entries,
                      guint n_entries)
{
    GtkWidget *window;
    GtkActionGroup *action_group;

    g_return_if_fail (E_IS_SHELL_VIEW (shell_view));
    g_return_if_fail (entries != NULL);

    window = e_shell_view_get_window (shell_view);
    action_group = E_SHELL_WINDOW_ACTION_GROUP_NEW_SOURCE (window);

    shell_view_register_new_actions (
        shell_view, action_group, entries, n_entries);
}