1 /* Copyright (c) 2006, Nokia Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Nokia Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <glib/gi18n.h>
32 #include <gtk/gtkaboutdialog.h>
33 #include <gtk/gtktreeviewcolumn.h>
35 #include <modest-widget-memory.h>
36 #include <modest-icon-factory.h>
38 #include <widgets/modest-toolbar.h>
40 #include "modest-main-window.h"
41 #include "modest-account-view-window.h"
42 #include "modest-account-mgr.h"
43 #include "modest-conf.h"
44 #include "modest-edit-msg-window.h"
45 #include "modest-icon-names.h"
46 #include "modest-tny-platform-factory.h"
47 #include "modest-tny-msg-actions.h"
48 #include "modest-mail-operation.h"
50 /* 'private'/'protected' functions */
51 static void modest_main_window_class_init (ModestMainWindowClass *klass);
52 static void modest_main_window_init (ModestMainWindow *obj);
53 static void modest_main_window_finalize (GObject *obj);
55 static void restore_sizes (ModestMainWindow *self);
56 static void save_sizes (ModestMainWindow *self);
65 typedef struct _ModestMainWindowPrivate ModestMainWindowPrivate;
66 struct _ModestMainWindowPrivate {
68 GtkUIManager *ui_manager;
73 //GtkWidget *folder_paned;
75 GtkWidget *main_paned;
77 ModestWidgetFactory *widget_factory;
78 TnyPlatformFactory *factory;
80 ModestHeaderView *header_view;
81 ModestFolderView *folder_view;
82 ModestMsgView *msg_preview;
86 #define MODEST_MAIN_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \
87 MODEST_TYPE_MAIN_WINDOW, \
88 ModestMainWindowPrivate))
90 static GtkWindowClass *parent_class = NULL;
92 /* uncomment the following if you have defined any signals */
93 /* static guint signals[LAST_SIGNAL] = {0}; */
96 modest_main_window_get_type (void)
98 static GType my_type = 0;
100 static const GTypeInfo my_info = {
101 sizeof(ModestMainWindowClass),
102 NULL, /* base init */
103 NULL, /* base finalize */
104 (GClassInitFunc) modest_main_window_class_init,
105 NULL, /* class finalize */
106 NULL, /* class data */
107 sizeof(ModestMainWindow),
109 (GInstanceInitFunc) modest_main_window_init,
112 my_type = g_type_register_static (HILDON_TYPE_WINDOW,
120 modest_main_window_class_init (ModestMainWindowClass *klass)
122 GObjectClass *gobject_class;
123 gobject_class = (GObjectClass*) klass;
125 parent_class = g_type_class_peek_parent (klass);
126 gobject_class->finalize = modest_main_window_finalize;
128 g_type_class_add_private (gobject_class, sizeof(ModestMainWindowPrivate));
130 /* signal definitions go here, e.g.: */
131 /* signals[MY_SIGNAL_1] = */
132 /* g_signal_new ("my_signal_1",....); */
133 /* signals[MY_SIGNAL_2] = */
134 /* g_signal_new ("my_signal_2",....); */
139 modest_main_window_init (ModestMainWindow *obj)
141 ModestMainWindowPrivate *priv;
143 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
145 priv->factory = modest_tny_platform_factory_get_instance ();
149 modest_main_window_finalize (GObject *obj)
151 ModestMainWindowPrivate *priv;
152 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
153 if (priv->widget_factory) {
154 g_object_unref (G_OBJECT(priv->widget_factory));
155 priv->widget_factory = NULL;
158 G_OBJECT_CLASS(parent_class)->finalize (obj);
163 on_menu_about (GtkWidget *widget, gpointer data)
166 const gchar *authors[] = {
167 "Dirk-Jan C. Binnema <dirk-jan.binnema@nokia.com>",
170 about = gtk_about_dialog_new ();
171 gtk_about_dialog_set_name (GTK_ABOUT_DIALOG(about), PACKAGE_NAME);
172 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG(about),PACKAGE_VERSION);
173 gtk_about_dialog_set_copyright (
174 GTK_ABOUT_DIALOG(about),
175 _("Copyright (c) 2006, Nokia Corporation\n"
176 "All rights reserved."));
177 gtk_about_dialog_set_comments ( GTK_ABOUT_DIALOG(about),
178 _("a modest e-mail client\n\n"
179 "design and implementation: Dirk-Jan C. Binnema\n"
180 "contributions from the fine people at KernelConcepts\n\n"
181 "uses the tinymail email framework written by Philip van Hoof"));
182 gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG(about), authors);
183 gtk_about_dialog_set_website (GTK_ABOUT_DIALOG(about), "http://modest.garage.maemo.org");
185 gtk_dialog_run (GTK_DIALOG (about));
186 gtk_widget_destroy(about);
191 on_menu_accounts (ModestMainWindow *self, guint action, GtkWidget *widget)
193 GtkWidget *account_win;
194 ModestMainWindowPrivate *priv;
196 g_return_if_fail (widget);
197 g_return_if_fail (self);
199 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
200 account_win = modest_account_view_window_new (priv->widget_factory);
202 gtk_window_set_transient_for (GTK_WINDOW(account_win),
205 gtk_widget_show (account_win);
210 on_menu_new_message (ModestMainWindow *self, guint action, GtkWidget *widget)
213 ModestMainWindowPrivate *priv;
215 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
217 msg_win = modest_edit_msg_window_new (priv->widget_factory,
218 MODEST_EDIT_TYPE_NEW,
220 gtk_widget_show (msg_win);
224 get_msg_cb (TnyFolder *folder, TnyMsg *msg, GError **err, gpointer user_data)
227 TnyHeader *new_header;
229 ModestMainWindowPrivate *priv;
230 ModestEditType edit_type = -2;
231 GetMsgAsyncHelper *helper;
233 helper = (GetMsgAsyncHelper *) (user_data);
234 priv = helper->main_window_private;
236 /* FIXME: select proper action */
238 switch (helper->action) {
241 modest_mail_operation_create_reply_mail (msg, helper->from, helper->reply_type,
242 MODEST_MAIL_OPERATION_REPLY_MODE_SENDER);
243 edit_type = MODEST_EDIT_TYPE_REPLY;
247 modest_mail_operation_create_reply_mail (msg, helper->from, helper->reply_type,
248 MODEST_MAIL_OPERATION_REPLY_MODE_ALL);
249 edit_type = MODEST_EDIT_TYPE_REPLY;
253 modest_mail_operation_create_forward_mail (msg, helper->from, helper->forward_type);
254 edit_type = MODEST_EDIT_TYPE_FORWARD;
257 g_warning ("unexpected action type: %d", helper->action);
262 new_header = tny_msg_get_header (new_msg);
263 tny_header_set_from (new_header, helper->from);
265 /* Show edit window */
266 msg_win = modest_edit_msg_window_new (priv->widget_factory,
269 gtk_widget_show (msg_win);
271 /* Clean and go on */
272 g_object_unref (new_msg);
277 on_menu_reply_forward (ModestMainWindow *self, guint action, GtkWidget *widget)
279 ModestMainWindowPrivate *priv;
280 ModestHeaderView *header_view;
281 TnyList *header_list;
283 gchar *reply_key, *forward_key;
284 ModestMailOperationReplyType reply_type;
285 ModestMailOperationForwardType forward_type;
288 GetMsgAsyncHelper *helper;
290 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
291 conf = modest_tny_platform_factory_get_modest_conf_instance (priv->factory);
293 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
294 header_list = modest_header_view_get_selected_headers (header_view);
296 /* Get reply and forward types */
298 reply_key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE, MODEST_CONF_REPLY_TYPE);
299 reply_type = modest_conf_get_int (conf, reply_key, &error);
300 if (error || reply_type == 0) {
301 g_warning ("key %s not defined", reply_key);
302 reply_type = MODEST_MAIL_OPERATION_REPLY_TYPE_CITE;
304 g_error_free (error);
310 forward_key = g_strdup_printf ("%s/%s", MODEST_CONF_NAMESPACE, MODEST_CONF_FORWARD_TYPE);
311 forward_type = modest_conf_get_int (conf, forward_key, &error);
312 if (error || forward_type == 0) {
313 g_warning ("key %s not defined", forward_key);
314 forward_type = MODEST_MAIL_OPERATION_FORWARD_TYPE_INLINE;
316 g_error_free (error);
320 g_free (forward_key);
325 gchar *from, *email_key;
326 const gchar *account_name;
328 /* We assume that we can only select messages of the
329 same folder and that we reply all of them from the
330 same account. In fact the interface currently only
331 allows single selection */
332 account_name = modest_folder_view_get_selected_account (priv->folder_view);
333 email_key = g_strdup_printf ("%s/%s/%s", MODEST_ACCOUNT_NAMESPACE,
334 account_name, MODEST_ACCOUNT_EMAIL);
335 from = modest_conf_get_string (conf, email_key, NULL);
338 iter = tny_list_create_iterator (header_list);
339 header = TNY_HEADER (tny_iterator_get_current (iter));
340 folder = tny_header_get_folder (header);
343 /* Since it's not an object, we need to create
344 it each time due to it's not a GObject and
345 we can not do a g_object_ref. No need to
346 free it, tinymail will do it for us. */
347 helper = g_slice_new0 (GetMsgAsyncHelper);
348 helper->main_window_private = priv;
349 helper->reply_type = reply_type;
350 helper->forward_type = forward_type;
351 helper->action = action;
354 /* Get msg from header */
355 header = TNY_HEADER (tny_iterator_get_current (iter));
356 tny_folder_get_msg_async (folder, header, get_msg_cb, helper);
357 tny_iterator_next (iter);
359 } while (!tny_iterator_is_done (iter));
363 g_object_unref (G_OBJECT (iter));
364 g_object_unref (G_OBJECT (folder));
369 on_menu_quit (ModestMainWindow *self, guint action, GtkWidget *widget)
372 gtk_widget_destroy (GTK_WIDGET(self));
376 on_menu_delete (ModestMainWindow *self, guint action, GtkWidget *widget)
378 ModestMainWindowPrivate *priv;
379 ModestHeaderView *header_view;
380 TnyList *header_list;
384 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
386 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
387 header_list = modest_header_view_get_selected_headers (header_view);
390 iter = tny_list_create_iterator (header_list);
391 model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
392 if (GTK_IS_TREE_MODEL_SORT (model))
393 model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (model));
396 ModestMailOperation *mail_op;
398 header = TNY_HEADER (tny_iterator_get_current (iter));
399 /* TODO: thick grain mail operation involving
400 a list of objects. Composite pattern ??? */
401 mail_op = modest_mail_operation_new ();
404 modest_mail_operation_remove_msg (mail_op, header, TRUE);
406 /* Remove from tree model */
407 tny_list_remove (TNY_LIST (model), G_OBJECT (header));
409 g_object_unref (G_OBJECT (mail_op));
410 g_object_unref (header);
411 tny_iterator_next (iter);
413 } while (!tny_iterator_is_done (iter));
418 /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
419 static const gchar* UI_DEF=
420 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
423 " <menu name=\"Message\" \"MenuMessage\">"
424 " <menuitem name=\"New\" action=\"on_menu_new_message\" />"
426 // " <menu name=\"JustifyMenu\" action=\"JustifyMenuAction\">"
427 // " <menuitem name=\"Left\" action=\"justify-left\"/>"
428 // " <menuitem name=\"Centre\" action=\"justify-center\"/>"
429 // " <menuitem name=\"Right\" action=\"justify-right\"/>"
430 // " <menuitem name=\"Fill\" action=\"justify-fill\"/>"
436 get_menu (ModestMainWindow *self)
441 ModestMainWindowPrivate *priv;
442 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
444 priv->ui_manager = gtk_ui_manager_new ();
446 gtk_ui_manager_add_ui_from_string (priv->ui_manager,
447 UI_DEF, strlen(UI_DEF),
450 w = gtk_ui_manager_get_widget (priv->ui_manager, "/popup");
451 g_warning ("==> GtkMenu? ==> %s", GTK_IS_MENU(w) ? "yes" : "no");
458 static ModestHeaderView*
459 header_view_new (ModestMainWindow *self)
462 GList *columns = NULL;
463 ModestHeaderView *header_view;
464 ModestMainWindowPrivate *priv;
465 ModestHeaderViewColumn cols[] = {
466 MODEST_HEADER_VIEW_COLUMN_MSGTYPE,
467 MODEST_HEADER_VIEW_COLUMN_ATTACH,
468 MODEST_HEADER_VIEW_COLUMN_COMPACT_HEADER
469 // MODEST_HEADER_VIEW_COLUMN_FROM,
470 // MODEST_HEADER_VIEW_COLUMN_SUBJECT,
471 // MODEST_HEADER_VIEW_COLUMN_RECEIVED_DATE
473 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
475 for (i = 0 ; i != sizeof(cols) / sizeof(ModestHeaderViewColumn); ++i)
476 columns = g_list_append (columns, GINT_TO_POINTER(cols[i]));
478 header_view = modest_widget_factory_get_header_view (priv->widget_factory);
479 modest_header_view_set_columns (header_view, columns);
480 g_list_free (columns);
487 on_toolbar_button_clicked (ModestToolbar *toolbar, ModestToolbarButton button_id,
488 ModestMainWindow *self)
490 GtkTreeSelection *sel;
493 ModestMainWindowPrivate *priv;
495 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
498 case MODEST_TOOLBAR_BUTTON_NEW_MAIL:
499 on_menu_new_message (self, 0, NULL);
501 case MODEST_TOOLBAR_BUTTON_REPLY:
502 on_menu_reply_forward (self, 1, NULL);
504 case MODEST_TOOLBAR_BUTTON_REPLY_ALL:
505 on_menu_reply_forward (self, 2, NULL);
507 case MODEST_TOOLBAR_BUTTON_FORWARD:
508 on_menu_reply_forward (self, 3, NULL);
510 case MODEST_TOOLBAR_BUTTON_SEND_RECEIVE:
513 case MODEST_TOOLBAR_BUTTON_NEXT:
514 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->header_view));
516 gtk_tree_selection_get_selected (sel, &model, &iter);
517 gtk_tree_model_iter_next (model, &iter);
518 gtk_tree_selection_select_iter (sel, &iter);
521 case MODEST_TOOLBAR_BUTTON_PREV:
523 /* gtk_tree_selection_get_selected (sel, &model, &iter); */
524 /* gtk_tree_model_iter_prev (model, &iter); */
525 /* gtk_tree_selection_select_iter (sel, &iter); */
529 case MODEST_TOOLBAR_BUTTON_DELETE:
530 on_menu_delete (self, 0, GTK_WIDGET (toolbar));
534 g_printerr ("modest: key %d pressed\n", button_id);
538 static ModestToolbar*
539 toolbar_new (ModestMainWindow *self)
542 ModestToolbar *toolbar;
543 GSList *buttons = NULL;
544 ModestMainWindowPrivate *priv;
546 ModestToolbarButton button_ids[] = {
547 MODEST_TOOLBAR_BUTTON_NEW_MAIL,
548 MODEST_TOOLBAR_BUTTON_REPLY,
549 MODEST_TOOLBAR_BUTTON_REPLY_ALL,
550 MODEST_TOOLBAR_BUTTON_FORWARD,
551 MODEST_TOOLBAR_SEPARATOR,
552 MODEST_TOOLBAR_BUTTON_SEND_RECEIVE,
553 MODEST_TOOLBAR_SEPARATOR,
554 MODEST_TOOLBAR_BUTTON_PREV,
555 MODEST_TOOLBAR_BUTTON_NEXT,
556 MODEST_TOOLBAR_SEPARATOR,
557 MODEST_TOOLBAR_BUTTON_DELETE
560 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
562 for (i = 0 ; i != sizeof(button_ids) / sizeof(ModestToolbarButton); ++i)
563 buttons = g_slist_append (buttons, GINT_TO_POINTER(button_ids[i]));
565 toolbar = modest_widget_factory_get_main_toolbar (priv->widget_factory, buttons);
566 g_slist_free (buttons);
568 g_signal_connect (G_OBJECT(toolbar), "button_clicked",
569 G_CALLBACK(on_toolbar_button_clicked), self);
577 restore_sizes (ModestMainWindow *self)
580 ModestMainWindowPrivate *priv;
582 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
583 conf = modest_tny_platform_factory_get_modest_conf_instance (priv->factory);
585 modest_widget_memory_restore_settings (conf,GTK_WIDGET(self),
586 "modest-main-window");
587 modest_widget_memory_restore_settings (conf, GTK_WIDGET(priv->msg_paned),
589 modest_widget_memory_restore_settings (conf, GTK_WIDGET(priv->main_paned),
590 "modest-main-paned");
595 save_sizes (ModestMainWindow *self)
597 ModestMainWindowPrivate *priv;
600 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(self);
601 conf = modest_tny_platform_factory_get_modest_conf_instance (priv->factory);
603 modest_widget_memory_save_settings (conf,GTK_WIDGET(self),
604 "modest-main-window");
605 modest_widget_memory_save_settings (conf, GTK_WIDGET(priv->msg_paned),
607 modest_widget_memory_save_settings (conf, GTK_WIDGET(priv->main_paned),
608 "modest-main-paned");
612 wrapped_in_scrolled_window (GtkWidget *widget, gboolean needs_viewport)
616 win = gtk_scrolled_window_new (NULL, NULL);
617 gtk_scrolled_window_set_policy
618 (GTK_SCROLLED_WINDOW (win),GTK_POLICY_NEVER,
619 GTK_POLICY_AUTOMATIC);
622 gtk_scrolled_window_add_with_viewport
623 (GTK_SCROLLED_WINDOW(win), widget);
625 gtk_container_add (GTK_CONTAINER(win),
633 on_delete_event (GtkWidget *widget, GdkEvent *event, ModestMainWindow *self)
641 modest_main_window_new (ModestWidgetFactory *widget_factory)
644 ModestMainWindowPrivate *priv;
646 GtkWidget *main_vbox;
647 GtkWidget *status_hbox;
648 GtkWidget *header_win, *folder_win, *favorites_win;
650 g_return_val_if_fail (widget_factory, NULL);
652 obj = g_object_new(MODEST_TYPE_MAIN_WINDOW, NULL);
653 priv = MODEST_MAIN_WINDOW_GET_PRIVATE(obj);
655 g_object_ref (widget_factory);
656 priv->widget_factory = widget_factory;
658 /* widgets from factory */
659 priv->folder_view = modest_widget_factory_get_folder_view (widget_factory);
660 priv->header_view = header_view_new (MODEST_MAIN_WINDOW(obj));
661 priv->msg_preview = modest_widget_factory_get_msg_preview (widget_factory);
663 folder_win = wrapped_in_scrolled_window (GTK_WIDGET(priv->folder_view),
665 header_win = wrapped_in_scrolled_window (GTK_WIDGET(priv->header_view),
668 priv->menu = get_menu (MODEST_MAIN_WINDOW(obj));
669 hildon_window_set_menu (HILDON_WINDOW(obj), GTK_MENU(priv->menu));
671 priv->toolbar = GTK_WIDGET(toolbar_new (MODEST_MAIN_WINDOW(obj)));
674 priv->msg_paned = gtk_vpaned_new ();
675 priv->main_paned = gtk_hpaned_new ();
677 gtk_paned_add1 (GTK_PANED(priv->main_paned), folder_win);
678 gtk_paned_add2 (GTK_PANED(priv->main_paned), priv->msg_paned);
680 gtk_paned_add1 (GTK_PANED(priv->msg_paned), header_win);
681 gtk_paned_add2 (GTK_PANED(priv->msg_paned), GTK_WIDGET(priv->msg_preview));
683 gtk_widget_show (GTK_WIDGET(priv->header_view));
684 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(priv->header_view));
686 /* status bar / progress */
687 status_hbox = gtk_hbox_new (FALSE, 0);
688 gtk_box_pack_start (GTK_BOX(status_hbox),
689 modest_widget_factory_get_folder_info_label (widget_factory),
691 gtk_box_pack_start (GTK_BOX(status_hbox),
692 modest_widget_factory_get_status_bar(widget_factory),
694 gtk_box_pack_start (GTK_BOX(status_hbox),
695 modest_widget_factory_get_progress_bar(widget_factory),
697 gtk_box_pack_start (GTK_BOX(status_hbox),
698 modest_widget_factory_get_online_toggle(widget_factory),
701 /* putting it all together... */
702 main_vbox = gtk_vbox_new (FALSE, 6);
703 gtk_box_pack_start (GTK_BOX(main_vbox), priv->main_paned, TRUE, TRUE,0);
704 gtk_box_pack_start (GTK_BOX(main_vbox), priv->toolbar, FALSE, FALSE, 0);
705 gtk_box_pack_start (GTK_BOX(main_vbox), status_hbox, FALSE, FALSE, 0);
707 gtk_container_add (GTK_CONTAINER(obj), main_vbox);
708 restore_sizes (MODEST_MAIN_WINDOW(obj));
710 gtk_window_set_title (GTK_WINDOW(obj), "Modest");
711 gtk_window_set_icon (GTK_WINDOW(obj),
712 modest_icon_factory_get_icon (MODEST_APP_ICON));
714 gtk_widget_show_all (main_vbox);
716 g_signal_connect (G_OBJECT(obj), "delete-event",
717 G_CALLBACK(on_delete_event), obj);
719 return GTK_WIDGET(obj);