Logo Search packages:      
Sourcecode: balsa version File versions

message-window.c

/* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
/* Balsa E-Mail Client
 * Copyright (C) 1997-2000 Stuart Parmenter and others,
 *                         See the file AUTHORS for a list.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option) 
 * any later version.
 *  
 * 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., 59 Temple Place - Suite 330, Boston, MA  
 * 02111-1307, USA.
 */

#include "config.h"

#include <gnome.h>
#include "balsa-app.h"
#include "balsa-message.h"
#include "balsa-icons.h"
#include "balsa-index.h"
#include "main-window.h"
#include "sendmsg-window.h"
#include "message-window.h"
#include "print.h"
#include "toolbar-factory.h"
#include "mailbox-node.h"

#include "libbalsa.h"
#include "i18n.h"

typedef struct _MessageWindow MessageWindow;

/* callbacks */
static void destroy_message_window(GtkWidget * widget, MessageWindow * mw);
static void close_message_window(GtkWidget * widget, gpointer data);

static void replyto_message_cb(GtkWidget * widget, gpointer data);
static void replytoall_message_cb(GtkWidget * widget, gpointer data);
static void replytogroup_message_cb(GtkWidget * widget, gpointer data);
static void forward_message_attached_cb(GtkWidget * widget, gpointer data);
static void forward_message_inline_cb(GtkWidget * widget, gpointer data);
static void forward_message_default_cb(GtkWidget * widget, gpointer data);

static void next_part_cb(GtkWidget * widget, gpointer data);
static void previous_part_cb(GtkWidget * widget, gpointer data);
static void save_current_part_cb(GtkWidget * widget, gpointer data);
static void view_msg_source_cb(GtkWidget * widget, gpointer data);

static void show_no_headers_cb(GtkWidget * widget, gpointer data);
static void show_selected_cb(GtkWidget * widget, gpointer data);
static void show_all_headers_cb(GtkWidget * widget, gpointer data);
static void show_all_headers_tool_cb(GtkWidget * widget, gpointer data);
static void wrap_message_cb(GtkWidget * widget, gpointer data);
static void size_alloc_cb(GtkWidget * window, GtkAllocation * alloc);
static void mw_set_buttons_sensitive(MessageWindow * mw);

static void mw_set_selected(MessageWindow * mw, void (*select_func)(BalsaIndex *));

static void copy_cb(GtkWidget * widget, MessageWindow * mw);
static void select_all_cb(GtkWidget * widget, gpointer);

static void next_message_cb(GtkWidget * widget, gpointer data);
static void previous_message_cb(GtkWidget * widget, gpointer data);
static void next_unread_cb(GtkWidget * widget, gpointer);
static void next_flagged_cb(GtkWidget * widget, gpointer);
static void print_cb(GtkWidget * widget, gpointer);
static void trash_cb(GtkWidget * widget, gpointer);

static void message_window_move_message (MessageWindow * mw,
                               LibBalsaMailbox * mailbox);
static void reset_show_all_headers(MessageWindow *mw);
#ifdef HAVE_GTKHTML
static void mw_zoom_cb(GtkWidget * widget, MessageWindow * mw);
static void mw_select_part_cb(BalsaMessage * bm, MessageWindow * mw);
#endif                          /* HAVE_GTKHTML */

static GnomeUIInfo shown_hdrs_menu[] = {
    GNOMEUIINFO_RADIOITEM(N_("N_o Headers"), NULL,
                    show_no_headers_cb, NULL),
    GNOMEUIINFO_RADIOITEM(N_("_Selected Headers"), NULL,
                    show_selected_cb, NULL),
    GNOMEUIINFO_RADIOITEM(N_("All _Headers"), NULL,
                    show_all_headers_cb, NULL),
    GNOMEUIINFO_END
};

static GnomeUIInfo file_menu[] = {
    GNOMEUIINFO_MENU_PRINT_ITEM(print_cb, NULL),
    GNOMEUIINFO_SEPARATOR,
#define MENU_FILE_CLOSE_POS 2
    GNOMEUIINFO_MENU_CLOSE_ITEM(close_message_window, NULL),
    GNOMEUIINFO_END
};

static GnomeUIInfo edit_menu[] = {
    /* FIXME: Features to hook up... */
    /*  GNOMEUIINFO_MENU_UNDO_ITEM(NULL, NULL); */
    /*  GNOMEUIINFO_MENU_REDO_ITEM(NULL, NULL); */
    /*  GNOMEUIINFO_SEPARATOR, */
#define MENU_EDIT_COPY_POS 0
    GNOMEUIINFO_MENU_COPY_ITEM(copy_cb, NULL),
#define MENU_EDIT_SELECT_ALL_POS 1
    GNOMEUIINFO_MENU_SELECT_ALL_ITEM(select_all_cb, NULL),
    /*  GNOMEUINFO_SEPARATOR, */
    /*  GNOMEUIINFO_MENU_FIND_ITEM(NULL, NULL); */
    /*  GNOMEUIINFO_MENU_FIND_AGAIN_ITEM(NULL, NULL); */
    /*  GNOMEUIINFO_MENU_REPLACE_ITEM(NULL, NULL); */
    GNOMEUIINFO_END
};

static GnomeUIInfo view_menu[] = {
#define MENU_VIEW_WRAP_POS 0
    GNOMEUIINFO_TOGGLEITEM(N_("_Wrap"), NULL, wrap_message_cb, NULL),
    GNOMEUIINFO_SEPARATOR,
    GNOMEUIINFO_RADIOLIST(shown_hdrs_menu),
#ifdef HAVE_GTKHTML
    GNOMEUIINFO_SEPARATOR,
#define MENU_VIEW_ZOOM_IN MENU_VIEW_WRAP_POS + 4
    { GNOME_APP_UI_ITEM, N_("Zoom _In"), N_("Increase magnification"),
      mw_zoom_cb, GINT_TO_POINTER(1), NULL, GNOME_APP_PIXMAP_STOCK,
      GTK_STOCK_ZOOM_IN, '+', GDK_CONTROL_MASK, NULL},
#define MENU_VIEW_ZOOM_OUT MENU_VIEW_ZOOM_IN + 1
    { GNOME_APP_UI_ITEM, N_("Zoom _Out"), N_("Decrease magnification"),
      mw_zoom_cb, GINT_TO_POINTER(-1), NULL, GNOME_APP_PIXMAP_STOCK,
      GTK_STOCK_ZOOM_OUT, '-', GDK_CONTROL_MASK, NULL},
#define MENU_VIEW_ZOOM_100 MENU_VIEW_ZOOM_OUT + 1
      /* To warn msgfmt that the % sign isn't a
       * format specifier: */
      /* xgettext:no-c-format */
    { GNOME_APP_UI_ITEM, N_("Zoom _100%"), N_("No magnification"),
      mw_zoom_cb, GINT_TO_POINTER(0), NULL, GNOME_APP_PIXMAP_STOCK,
      GTK_STOCK_ZOOM_100, 0, 0, NULL},
#endif                          /* HAVE_GTKHTML */
    GNOMEUIINFO_END
};

static GnomeUIInfo message_menu[] = {
    /* R */
    {
     GNOME_APP_UI_ITEM, N_("_Reply..."), N_("Reply to this message"),
     replyto_message_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     BALSA_PIXMAP_REPLY, 'R', 0, NULL},
    /* A */
    {
     GNOME_APP_UI_ITEM, N_("Reply to _All..."),
     N_("Reply to all recipients of this message"),
     replytoall_message_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     BALSA_PIXMAP_REPLY_ALL, 'A', 0, NULL},
    /* G */
    {
     GNOME_APP_UI_ITEM, N_("Reply to _Group..."),
     N_("Reply to mailing list"),
     replytogroup_message_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     BALSA_PIXMAP_REPLY_GROUP, 'G', 0, NULL},
    /* F */
    {
     GNOME_APP_UI_ITEM, N_("_Forward attached..."),
     N_("Forward this message as attachment"),
     forward_message_attached_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     BALSA_PIXMAP_FORWARD, 'F', 0, NULL},
    {
     GNOME_APP_UI_ITEM, N_("Forward inline..."), 
     N_("Forward this message inline"),
     forward_message_inline_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     BALSA_PIXMAP_FORWARD, 'F', GDK_CONTROL_MASK, NULL},
    GNOMEUIINFO_SEPARATOR,
#define MENU_MESSAGE_NEXT_PART_POS 6
    {
     GNOME_APP_UI_ITEM, N_("Next Part"), N_("Next part in message"),
     next_part_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     BALSA_PIXMAP_NEXT_PART, '.', GDK_CONTROL_MASK, NULL},
#define MENU_MESSAGE_PREVIOUS_PART_POS 7
    {
     GNOME_APP_UI_ITEM, N_("Previous Part"),
     N_("Previous part in message"),
     previous_part_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     BALSA_PIXMAP_PREVIOUS_PART, ',', GDK_CONTROL_MASK, NULL},
    {
     GNOME_APP_UI_ITEM, N_("Save Current Part..."),
     N_("Save current part in message"),
     save_current_part_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     GTK_STOCK_SAVE, 's', GDK_CONTROL_MASK, NULL},
    {
     GNOME_APP_UI_ITEM, N_("_View Source..."),
     N_("View source form of the message"),
     view_msg_source_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     BALSA_PIXMAP_BOOK_OPEN, 'v', GDK_CONTROL_MASK, NULL},
     GNOMEUIINFO_SEPARATOR,
    /* N */
#define MENU_MESSAGE_NEXT_POS 11
    {
     GNOME_APP_UI_ITEM, N_("_Next Message"), N_("Next message"),
     next_message_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     BALSA_PIXMAP_NEXT, 'N', 0, NULL},
    /* P */
#define MENU_MESSAGE_PREVIOUS_POS 12
    {
     GNOME_APP_UI_ITEM, N_("_Previous Message"),
     N_("Previous Message"),
     previous_message_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     BALSA_PIXMAP_PREVIOUS, 'P', 0, NULL},
    /* Ctrl + N */
#define MENU_MESSAGE_NEXT_UNREAD_POS 13
    {
     GNOME_APP_UI_ITEM, N_("Next Unread Message"),
     N_("Next Unread Message"), next_unread_cb, NULL, NULL,
     GNOME_APP_PIXMAP_STOCK, BALSA_PIXMAP_NEXT_UNREAD, 'N',
     GDK_CONTROL_MASK, NULL},
    /* Ctrl + Alt + F */
#define MENU_MESSAGE_NEXT_FLAGGED_POS 14
    {
     GNOME_APP_UI_ITEM, N_("Next Flagged Message"),
     N_("Next Flagged Message"), next_flagged_cb, NULL, NULL,
     GNOME_APP_PIXMAP_STOCK, BALSA_PIXMAP_NEXT_FLAGGED, 'F',
     GDK_MOD1_MASK|GDK_CONTROL_MASK, NULL},
     GNOMEUIINFO_SEPARATOR,
     /* D */
#define MENU_MESSAGE_TRASH_POS 16
    {
     GNOME_APP_UI_ITEM, N_("_Move to Trash"),
     N_("Move the message to Trash mailbox"),
     trash_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK,
     GTK_STOCK_DELETE, 'D', 0, NULL},
    GNOMEUIINFO_END
};

static GnomeUIInfo move_menu[]={
    GNOMEUIINFO_END
};

static GnomeUIInfo main_menu[] = {
    GNOMEUIINFO_MENU_FILE_TREE(file_menu),
    GNOMEUIINFO_MENU_EDIT_TREE(edit_menu),
    GNOMEUIINFO_MENU_VIEW_TREE(view_menu),
#define MAIN_MENU_MOVE_POS 3
    GNOMEUIINFO_SUBTREE(N_("M_ove"), move_menu),
    GNOMEUIINFO_SUBTREE(N_("_Message"), message_menu),
    GNOMEUIINFO_END
};

struct _MessageWindow {
    GtkWidget *window;

    GtkWidget *bmessage;

    LibBalsaMessage *message;
    BalsaIndex *bindex;
    int headers_shown;
    int show_all_headers;
    guint idle_handler_id;

    /* Pointers to our copies of widgets. */
    GtkWidget *next;
    GtkWidget *previous;
    GtkWidget *next_unread;
    GtkWidget *next_flagged;
    GtkWidget *next_part;
    GtkWidget *previous_part;
    GtkWidget *trash;
#ifdef HAVE_GTKHTML
    GtkWidget *zoom_in;
    GtkWidget *zoom_out;
    GtkWidget *zoom_100;
#endif /* HAVE_GTKHTML */
};

static void
mru_menu_cb(gchar * url, gpointer data)
{
    LibBalsaMailbox *mailbox = balsa_find_mailbox_by_url(url);
    MessageWindow *mw = data;

    message_window_move_message(mw, mailbox);
}

static void
message_window_move_message(MessageWindow * mw, LibBalsaMailbox * mailbox)
{
    GArray *messages;
    LibBalsaMessage *original = mw->bindex->current_message;

    g_return_if_fail(mailbox != NULL);

   /*Transferring to same mailbox? */
    if (mw->message->mailbox == mailbox)
      return;

    messages = g_array_new(FALSE, FALSE, sizeof(guint));
    g_array_append_val(messages, mw->message->msgno);
    balsa_index_transfer(mw->bindex, messages, mailbox, FALSE);
    g_array_free(messages, TRUE);

    if ( balsa_app.mw_action_after_move == NEXT_UNREAD )
    {
        /* Try selecting the next unread message.
           If there are no more, close the window anyways. */
        mw_set_selected( mw, balsa_index_select_next_unread );

        if ( mw->bindex->current_message == original )
            close_message_window(NULL, (gpointer) mw);
    }
    else if ( balsa_app.mw_action_after_move == NEXT )
    {
        mw_set_selected( mw, balsa_index_select_next );

        if ( mw->bindex->current_message == original )
            close_message_window(NULL, (gpointer) mw);
    }
    else
    {
        close_message_window(NULL, (gpointer) mw);
    }
}

static void
mw_set_part_buttons_sensitive(MessageWindow * mw)
{
    BalsaMessage *msg = BALSA_MESSAGE(mw->bmessage);
    GtkWidget *toolbar;
    gboolean enable;

    if (!msg || !msg->treeview)
      return;

    toolbar = balsa_toolbar_get_from_gnome_app(GNOME_APP(mw->window));

    enable = balsa_message_has_next_part(msg);
    balsa_toolbar_set_button_sensitive(toolbar, BALSA_PIXMAP_NEXT_PART,
                                       enable);
    gtk_widget_set_sensitive(mw->next_part, enable);

    enable = balsa_message_has_previous_part(msg);
    balsa_toolbar_set_button_sensitive(toolbar, BALSA_PIXMAP_PREVIOUS_PART,
                                       enable);
    gtk_widget_set_sensitive(mw->previous_part, enable);
}

static gboolean
message_window_idle_handler(MessageWindow* mw)
{
    BalsaMessage *msg = BALSA_MESSAGE(mw->bmessage);
    LibBalsaMessage *message = mw->message;
    gchar *title;
    gchar *from;

    gdk_threads_enter();

    mw->idle_handler_id = 0;

    if (!message->mailbox) {
      gtk_widget_destroy(mw->window);
      gdk_threads_leave();
      return FALSE;
    }

    /* set window title */
    from = internet_address_list_to_string(message->headers->from, FALSE);
    title = g_strdup_printf(_("Message from %s: %s"), from,
                            LIBBALSA_MESSAGE_GET_SUBJECT(message));
    g_free(from);
    gtk_window_set_title(GTK_WINDOW(mw->window), title);
    g_free(title);

    if (!balsa_message_set(msg, message)) {
      gtk_widget_destroy(mw->window);
      gdk_threads_leave();
      return FALSE;
    }
    balsa_message_grab_focus(BALSA_MESSAGE(mw->bmessage));

    balsa_message_set_close(msg, TRUE);
    mw_set_part_buttons_sensitive(mw);

    /* Update the style and message counts in the mailbox list */
    balsa_mblist_update_mailbox(balsa_app.mblist_tree_store,
                                message->mailbox);

    gdk_threads_leave();
    return FALSE;
}

/* Toolbar buttons and their callbacks. */
static const struct callback_item {
    const char* icon_id;
    void (*callback)(GtkWidget *, gpointer);
} callback_table[] = {
    { BALSA_PIXMAP_REPLY,        replyto_message_cb },
    { BALSA_PIXMAP_REPLY_ALL,    replytoall_message_cb },
    { BALSA_PIXMAP_REPLY_GROUP,  replytogroup_message_cb },
    { BALSA_PIXMAP_FORWARD,      forward_message_default_cb },
    { BALSA_PIXMAP_PREVIOUS,     previous_message_cb },
    { BALSA_PIXMAP_PREVIOUS_PART,previous_part_cb },
    { BALSA_PIXMAP_NEXT,         next_message_cb },
    { BALSA_PIXMAP_NEXT_PART,    next_part_cb },
    { BALSA_PIXMAP_NEXT_UNREAD,  next_unread_cb },
    { BALSA_PIXMAP_NEXT_FLAGGED, next_flagged_cb },
    { GTK_STOCK_DELETE,           trash_cb },
    { GTK_STOCK_PRINT,           print_cb },
    { GTK_STOCK_SAVE,            save_current_part_cb },
    { GTK_STOCK_CLOSE,           close_message_window },
    { BALSA_PIXMAP_SHOW_HEADERS, show_all_headers_tool_cb }
};

/* Standard buttons; "" means a separator. */
static const gchar* message_toolbar[] = {
#if defined(ENABLE_TOUCH_UI)
    BALSA_PIXMAP_NEXT_UNREAD,
    "",
    BALSA_PIXMAP_REPLY,
    BALSA_PIXMAP_REPLY_ALL,
    BALSA_PIXMAP_FORWARD,
    "",
    GTK_STOCK_PRINT,
    "",
    GTK_STOCK_DELETE,
    "",
    GTK_STOCK_CLOSE
#else /* ENABLE_TOUCH_UI */
    BALSA_PIXMAP_NEXT_UNREAD,
    "",
    BALSA_PIXMAP_REPLY,
    BALSA_PIXMAP_REPLY_ALL,
    BALSA_PIXMAP_REPLY_GROUP,
    BALSA_PIXMAP_FORWARD,
    "",
    BALSA_PIXMAP_PREVIOUS_PART,
    BALSA_PIXMAP_NEXT_PART,
    GTK_STOCK_SAVE,
    "",
    GTK_STOCK_PRINT,
    "",
    GTK_STOCK_DELETE
#endif /* ENEBLE_TOUCH_UI */
};

/* Create the toolbar model for the message window's toolbar.
 */
BalsaToolbarModel *
message_window_get_toolbar_model(void)
{
    static BalsaToolbarModel *model = NULL;
    GSList *legal;
    GSList *standard;
    GSList **current;
    guint i;

    if (model)
        return model;

    legal = NULL;
    for (i = 0; i < ELEMENTS(callback_table); i++)
        legal = g_slist_append(legal, g_strdup(callback_table[i].icon_id));

    standard = NULL;
    for (i = 0; i < ELEMENTS(message_toolbar); i++)
        standard = g_slist_append(standard, g_strdup(message_toolbar[i]));

    current = &balsa_app.message_window_toolbar_current;

    model = balsa_toolbar_model_new(legal, standard, current);

    return model;
}

#define BALSA_MESSAGE_WINDOW_KEY "balsa-message-window"

static void
mw_set_message(MessageWindow *mw, LibBalsaMessage * message)
{
    mw->message = message;
    g_object_set_data(G_OBJECT(message), BALSA_MESSAGE_WINDOW_KEY, mw);

    g_object_ref(message); /* protect from destroying */
    mw->idle_handler_id =
        g_idle_add((GSourceFunc) message_window_idle_handler, mw);

    mw_set_buttons_sensitive(mw);
}

static void
bindex_closed_cb(gpointer data, GObject *bindex)
{
    MessageWindow *mw = data;
    mw->bindex = NULL;
    gtk_widget_destroy(mw->window);
}

static void
mw_disable_trash(MessageWindow * mw, GtkWidget * toolbar)
{
    balsa_toolbar_set_button_sensitive(toolbar, GTK_STOCK_DELETE, FALSE);
    gtk_widget_set_sensitive(mw->trash, FALSE);
}

void
message_window_new(LibBalsaMessage * message)
{
    MessageWindow *mw;
    BalsaToolbarModel *model;
    GtkWidget *toolbar;
    guint i;
    GtkWidget *move_menu, *submenu;

    if (!message)
      return;

    /*
     * Check to see if this message is already displayed
     */
    mw = g_object_get_data(G_OBJECT(message), BALSA_MESSAGE_WINDOW_KEY);
    if (mw != NULL) {
        /*
         * The message is already displayed in a window, so just use
         * that one.
         */
        gdk_window_raise(mw->window->window);
        return;
    }

    mw = g_malloc0(sizeof(MessageWindow));

    mw->window = gnome_app_new("balsa", NULL);

    mw->headers_shown=balsa_app.shown_headers;
    mw->show_all_headers = FALSE;

    model = message_window_get_toolbar_model();
    toolbar = balsa_toolbar_new(model);
    for (i = 0; i < ELEMENTS(callback_table); i++)
        balsa_toolbar_set_callback(toolbar, callback_table[i].icon_id,
                                   G_CALLBACK(callback_table[i].callback),
                                   mw);
    gnome_app_set_toolbar(GNOME_APP(mw->window), GTK_TOOLBAR(toolbar));

    balsa_toolbar_set_button_sensitive(toolbar, BALSA_PIXMAP_PREVIOUS_PART, FALSE);
    balsa_toolbar_set_button_sensitive(toolbar, BALSA_PIXMAP_NEXT_PART, FALSE);

    gtk_window_set_wmclass(GTK_WINDOW(mw->window), "message", "Balsa");

    g_signal_connect(G_OBJECT(mw->window), "destroy",
                 G_CALLBACK(destroy_message_window), mw);
    g_signal_connect(G_OBJECT(mw->window), "size_allocate",
                     G_CALLBACK(size_alloc_cb), NULL);
    
    mw->bindex = balsa_find_index_by_mailbox(message->mailbox);
    g_object_weak_ref(G_OBJECT(mw->bindex), bindex_closed_cb, mw);
    g_signal_connect_swapped(G_OBJECT(mw->bindex), "index-changed",
                       G_CALLBACK(mw_set_buttons_sensitive), mw);

    gnome_app_create_menus_with_data(GNOME_APP(mw->window), main_menu, mw);

    /* Save the widgets that we need to change--they'll be overwritten
     * if another message window is opened. */
    mw->next          = message_menu[MENU_MESSAGE_NEXT_POS].widget;
    mw->previous      = message_menu[MENU_MESSAGE_PREVIOUS_POS].widget;
    mw->next_unread   = message_menu[MENU_MESSAGE_NEXT_UNREAD_POS].widget;
    mw->next_flagged  = message_menu[MENU_MESSAGE_NEXT_FLAGGED_POS].widget;
    mw->next_part     = message_menu[MENU_MESSAGE_NEXT_PART_POS].widget;
    mw->previous_part = message_menu[MENU_MESSAGE_PREVIOUS_PART_POS].widget;
    mw->trash =         message_menu[MENU_MESSAGE_TRASH_POS].widget;
#ifdef HAVE_GTKHTML
    mw->zoom_in  = view_menu[MENU_VIEW_ZOOM_IN].widget;
    mw->zoom_out = view_menu[MENU_VIEW_ZOOM_OUT].widget;
    mw->zoom_100 = view_menu[MENU_VIEW_ZOOM_100].widget;
    /* Use Ctrl+= as an alternative accelerator for zoom-in, because
     * Ctrl++ is a 3-key combination. */
    gtk_widget_add_accelerator(view_menu[MENU_VIEW_ZOOM_IN].widget,
                         "activate",
                         GNOME_APP(mw->window)->accel_group,
                         '=', GDK_CONTROL_MASK, (GtkAccelFlags) 0);
#endif                          /* HAVE_GTKHTML */

    submenu = balsa_mblist_mru_menu(GTK_WINDOW(mw->window),
                                    &balsa_app.folder_mru,
                                    G_CALLBACK(mru_menu_cb), mw);
    move_menu = main_menu[MAIN_MENU_MOVE_POS].widget;
    gtk_menu_item_set_submenu(GTK_MENU_ITEM(move_menu), submenu);
    if(message->mailbox->readonly) {
      gtk_widget_set_sensitive(move_menu, FALSE);
      mw_disable_trash(mw, toolbar);
    }
    if (message->mailbox == balsa_app.trash)
      mw_disable_trash(mw, toolbar);
    mw->bmessage = balsa_message_new();
    
    gnome_app_set_contents(GNOME_APP(mw->window), mw->bmessage);

#ifdef HAVE_GTKHTML
    g_signal_connect(mw->bmessage, "select-part",
                 G_CALLBACK(mw_select_part_cb), mw);
#endif                        /* HAVE_GTKHTML */

    if (balsa_app.shown_headers >= HEADERS_NONE &&
      balsa_app.shown_headers <= HEADERS_ALL)
      gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM
                               (shown_hdrs_menu
                              [balsa_app.shown_headers].widget),
                               TRUE);

    gtk_check_menu_item_set_active
      (GTK_CHECK_MENU_ITEM(view_menu[MENU_VIEW_WRAP_POS].widget),
       balsa_app.browse_wrap);

    gtk_window_set_default_size(GTK_WINDOW(mw->window),
                                balsa_app.message_window_width, 
                                balsa_app.message_window_height);

    gtk_widget_show_all(mw->window);
    mw_set_message(mw, message);
    gtk_widget_add_accelerator(file_menu[MENU_FILE_CLOSE_POS].widget,
                         "activate",
                         GNOME_APP(mw->window)->accel_group,
                         GDK_Escape, (GdkModifierType)0, 
                               (GtkAccelFlags) 0);
    GTK_WIDGET_UNSET_FLAGS(toolbar, GTK_CAN_FOCUS);
}

static void
mw_clear_message(MessageWindow * mw)
{
    if (mw->idle_handler_id) {
      g_source_remove(mw->idle_handler_id);
      mw->idle_handler_id = 0;
    } 
    if (mw->message) {
      g_object_set_data(G_OBJECT(mw->message), BALSA_MESSAGE_WINDOW_KEY,
                    NULL);
      g_object_unref(mw->message);
      mw->message = NULL;
    }
}

/* Handler for the "destroy" signal for mw->window. */
static void
destroy_message_window(GtkWidget * widget, MessageWindow * mw)
{
    if (mw->bindex) { /* BalsaIndex still exists */
        g_object_weak_unref(G_OBJECT(mw->bindex), bindex_closed_cb, mw);
        g_signal_handlers_disconnect_matched(G_OBJECT(mw->bindex),
                                             G_SIGNAL_MATCH_DATA, 0, 0,
                                             NULL, NULL, mw);
    }

    mw_clear_message(mw);

    g_free(mw);
}

static void
replyto_message_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    g_return_if_fail(widget != NULL);
    g_return_if_fail(mw != NULL);

    sendmsg_window_new(widget, mw->message, SEND_REPLY);
}

static void
replytoall_message_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    g_return_if_fail(widget != NULL);
    g_return_if_fail(mw != NULL);

    sendmsg_window_new(widget, mw->message, SEND_REPLY_ALL);
}

static void
replytogroup_message_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    g_return_if_fail(widget != NULL);
    g_return_if_fail(mw != NULL);

    sendmsg_window_new(widget, mw->message, SEND_REPLY_GROUP);
}

static void
forward_message_attached_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    g_return_if_fail(widget != NULL);
    g_return_if_fail(mw != NULL);

    sendmsg_window_new(widget, mw->message, SEND_FORWARD_ATTACH);
}

static void
forward_message_inline_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    g_return_if_fail(widget != NULL);
    g_return_if_fail(mw != NULL);

    sendmsg_window_new(widget, mw->message, SEND_FORWARD_INLINE);
}

static void
forward_message_default_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    g_return_if_fail(widget != NULL);
    g_return_if_fail(mw != NULL);

    sendmsg_window_new(widget, mw->message, balsa_app.forward_attached 
                   ? SEND_FORWARD_ATTACH : SEND_FORWARD_INLINE);
}

static void
next_part_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    balsa_message_next_part(BALSA_MESSAGE(mw->bmessage));
    mw_set_part_buttons_sensitive(mw);
}

static void
previous_part_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    balsa_message_previous_part(BALSA_MESSAGE(mw->bmessage));
    mw_set_part_buttons_sensitive(mw);
}

static void
save_current_part_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    balsa_message_save_current_part(BALSA_MESSAGE(mw->bmessage));
}

static void
view_msg_source_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;
    libbalsa_show_message_source(mw->message, balsa_app.message_font,
                                 &balsa_app.source_escape_specials);
}

static void
close_message_window(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;
    gtk_widget_destroy(mw->window);
}

static void
show_no_headers_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

      mw->headers_shown=HEADERS_NONE;

    reset_show_all_headers(mw);
    balsa_message_set_displayed_headers(BALSA_MESSAGE(mw->bmessage),
                              HEADERS_NONE);
}

static void
show_selected_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    mw->headers_shown=HEADERS_SELECTED;

    reset_show_all_headers(mw);
    balsa_message_set_displayed_headers(BALSA_MESSAGE(mw->bmessage),
                              HEADERS_SELECTED);
}

static void
show_all_headers_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

      mw->headers_shown=HEADERS_ALL;

    reset_show_all_headers(mw);
    balsa_message_set_displayed_headers(BALSA_MESSAGE(mw->bmessage),
                              HEADERS_ALL);
}

static void
wrap_message_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) data;

    balsa_message_set_wrap(BALSA_MESSAGE(mw->bmessage),
                     GTK_CHECK_MENU_ITEM(widget)->active);
}

static void
size_alloc_cb(GtkWidget * window, GtkAllocation * alloc)
{
    balsa_app.message_window_height = alloc->height;
    balsa_app.message_window_width = alloc->width;
}

static void
mw_set_buttons_sensitive(MessageWindow * mw)
{
    GtkWidget *toolbar =
        balsa_toolbar_get_from_gnome_app(GNOME_APP(mw->window));
    LibBalsaMailbox *mailbox = mw->message->mailbox;
    BalsaIndex *index = mw->bindex;
    guint current_msgno = mw->message->msgno;
    gboolean enable;

    if (!mailbox) {
        gtk_widget_destroy(mw->window);
        return;
    }

    enable = index && balsa_index_next_msgno(index, current_msgno) > 0;
    balsa_toolbar_set_button_sensitive(toolbar, BALSA_PIXMAP_NEXT, enable);
    gtk_widget_set_sensitive(mw->next, enable);

    enable = index && balsa_index_previous_msgno(index, current_msgno) > 0;
    balsa_toolbar_set_button_sensitive(toolbar, BALSA_PIXMAP_PREVIOUS,
                                       enable);
    gtk_widget_set_sensitive(mw->previous, enable);

    enable = index && index->mailbox_node->mailbox->unread_messages > 0;
    balsa_toolbar_set_button_sensitive(toolbar, BALSA_PIXMAP_NEXT_UNREAD,
                                       enable);
    gtk_widget_set_sensitive(mw->next_unread, enable);

    enable = index
        && libbalsa_mailbox_total_messages(index->mailbox_node->mailbox) > 0;
    balsa_toolbar_set_button_sensitive(toolbar, BALSA_PIXMAP_NEXT_FLAGGED,
                                       enable);
    gtk_widget_set_sensitive(mw->next_flagged, enable);
}

static void
copy_cb(GtkWidget * widget, MessageWindow * mw)
{
    guint signal_id;
    GtkWidget *focus_widget = gtk_window_get_focus(GTK_WINDOW(mw->window));

    signal_id = g_signal_lookup("copy-clipboard",
                                G_TYPE_FROM_INSTANCE(focus_widget));
    if (signal_id)
        g_signal_emit(focus_widget, signal_id, (GQuark) 0);
}

static void
select_all_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) (data);

    balsa_window_select_all(GTK_WINDOW(mw->window));
}

static void
mw_set_selected(MessageWindow * mw, void (*select_func)(BalsaIndex *))
{
    LibBalsaMessage *message;
    MessageWindow *tmp;

    balsa_index_select(mw->bindex, mw->message);
    select_func(mw->bindex);

    message = mw->bindex->current_message;
    g_object_ref(message);
    tmp = g_object_get_data(G_OBJECT(message), BALSA_MESSAGE_WINDOW_KEY);
    if (tmp) {
        /*
         * The message is already displayed in a window, so just use
         * that one.
         */
        g_object_unref(message);
        gdk_window_raise(tmp->window->window);
        return;
    }

    /* Temporarily tell the BalsaMessage not to close when its message
     * is finalized, so we can safely unref it in mw_clear_message.
     * We'll restore the usual close-with-message behavior after setting
     * the new message. */
    balsa_message_set_close(BALSA_MESSAGE(mw->bmessage), FALSE);
    mw_clear_message(mw);
    mw_set_message(mw, message);
    g_object_unref(message);
}

static void
next_message_cb(GtkWidget * widget, gpointer data)
{
    mw_set_selected((MessageWindow *) data, balsa_index_select_next);
}

static void
previous_message_cb(GtkWidget * widget, gpointer data)
{
    mw_set_selected((MessageWindow *) data, balsa_index_select_previous);
}

static void
next_unread_cb(GtkWidget * widget, gpointer data)
{
    mw_set_selected((MessageWindow *) data, balsa_index_select_next_unread);
}

static void
next_flagged_cb(GtkWidget * widget, gpointer data)
{
    mw_set_selected((MessageWindow *) data, balsa_index_select_next_flagged);
}


static void print_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) (data);
    
    message_print(mw->message, GTK_WINDOW(mw->window));
}

static void trash_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) (data);
    message_window_move_message(mw, balsa_app.trash);
}

static void
show_all_headers_tool_cb(GtkWidget * widget, gpointer data)
{
    MessageWindow *mw = (MessageWindow *) (data);
    GtkWidget *toolbar =
        balsa_toolbar_get_from_gnome_app(GNOME_APP(mw->window));

    if (balsa_toolbar_get_button_active(toolbar,
                                        BALSA_PIXMAP_SHOW_HEADERS)) {
        mw->show_all_headers = TRUE;
      balsa_message_set_displayed_headers(BALSA_MESSAGE(mw->bmessage),
                                  HEADERS_ALL);
    } else {
        mw->show_all_headers = FALSE;
      balsa_message_set_displayed_headers(BALSA_MESSAGE(mw->bmessage),
                                  mw->headers_shown);
    }
}

static void
reset_show_all_headers(MessageWindow *mw)
{
    GtkWidget *toolbar =
        balsa_toolbar_get_from_gnome_app(GNOME_APP(mw->window));

    mw->show_all_headers = FALSE;
    balsa_toolbar_set_button_active(toolbar, BALSA_PIXMAP_SHOW_HEADERS, FALSE);
}

#ifdef HAVE_GTKHTML
static void
mw_zoom_cb(GtkWidget * widget, MessageWindow * mw)
{
    GtkWidget *bm = mw->bmessage;
    gint in_out =
      GPOINTER_TO_INT(g_object_get_data
                  (G_OBJECT(widget), GNOMEUIINFO_KEY_UIDATA));
    balsa_message_zoom(BALSA_MESSAGE(bm), in_out);
}

static void
mw_select_part_cb(BalsaMessage * bm, MessageWindow * mw)
{
    gboolean enable = bm && balsa_message_can_zoom(bm);
    gtk_widget_set_sensitive(mw->zoom_in,  enable);
    gtk_widget_set_sensitive(mw->zoom_out, enable);
    gtk_widget_set_sensitive(mw->zoom_100, enable);
}
#endif                        /* HAVE_GTKHTML */

Generated by  Doxygen 1.6.0   Back to index