]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-presence-chooser.c
Reenable warning flags.. clean up mess
[empathy.git] / libempathy-gtk / empathy-presence-chooser.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2005-2007 Imendio AB
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Authors: Richard Hult <richard@imendio.com>
21  *          Martyn Russell <martyn@imendio.com>
22  *          Xavier Claessens <xclaesse@gmail.com>
23  */
24
25 #include "config.h"
26
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include <glib/gi18n-lib.h>
31 #include <gtk/gtk.h>
32 #include <glade/glade.h>
33
34 #include <telepathy-glib/util.h>
35 #include <libmissioncontrol/mc-enum-types.h>
36
37 #include <libempathy/empathy-idle.h>
38 #include <libempathy/empathy-utils.h>
39 #include <libempathy/empathy-status-presets.h>
40
41 #include "empathy-ui-utils.h"
42 #include "empathy-images.h"
43 #include "empathy-presence-chooser.h"
44
45 /* Flashing delay for icons (milliseconds). */
46 #define FLASH_TIMEOUT 500
47
48 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyPresenceChooser)
49 typedef struct {
50         EmpathyIdle *idle;
51
52         int          block_set_editing;
53
54         McPresence   state;
55
56         McPresence   flash_state_1;
57         McPresence   flash_state_2;
58         guint        flash_timeout_id;
59 } EmpathyPresenceChooserPriv;
60
61 typedef struct {
62         GtkWidget    *dialog;
63         GtkWidget    *checkbutton_save;
64         GtkWidget    *comboboxentry_message;
65         GtkWidget    *entry_message;
66         GtkWidget    *combobox_status;
67         GtkTreeModel *model_status;
68 } CustomMessageDialog;
69
70 enum {
71         COL_ICON,
72         COL_LABEL,
73         COL_PRESENCE,
74         COL_COUNT
75 };
76
77 static CustomMessageDialog *message_dialog = NULL;
78 /* States to be listed in the menu.
79  * Each state has a boolean telling if it can have custom message */
80 static guint states[] = {MC_PRESENCE_AVAILABLE, TRUE,
81                          MC_PRESENCE_DO_NOT_DISTURB, TRUE,
82                          MC_PRESENCE_AWAY, TRUE,
83                          MC_PRESENCE_HIDDEN, FALSE,
84                          MC_PRESENCE_OFFLINE, FALSE};
85
86 static void            presence_chooser_finalize               (GObject                    *object);
87 static void            presence_chooser_presence_changed_cb    (EmpathyPresenceChooser      *chooser);
88 static gboolean        presence_chooser_flash_timeout_cb       (EmpathyPresenceChooser      *chooser);
89 static void            presence_chooser_flash_start            (EmpathyPresenceChooser      *chooser,
90                                                                 McPresence                  state_1,
91                                                                 McPresence                  state_2);
92 static void            presence_chooser_flash_stop             (EmpathyPresenceChooser      *chooser,
93                                                                 McPresence                  state);
94 static void            presence_chooser_menu_add_item          (GtkWidget                  *menu,
95                                                                 const gchar                *str,
96                                                                 McPresence                  state);
97 static void            presence_chooser_noncustom_activate_cb  (GtkWidget                  *item,
98                                                                 gpointer                    user_data);
99 static void            presence_chooser_set_state              (McPresence                  state,
100                                                                 const gchar                *status);
101 static void            presence_chooser_custom_activate_cb     (GtkWidget                  *item,
102                                                                 gpointer                    user_data);
103 static void            presence_chooser_dialog_show            (void);
104
105 G_DEFINE_TYPE (EmpathyPresenceChooser, empathy_presence_chooser, GTK_TYPE_COMBO_BOX_ENTRY);
106
107 static void
108 empathy_presence_chooser_class_init (EmpathyPresenceChooserClass *klass)
109 {
110         GObjectClass *object_class = G_OBJECT_CLASS (klass);
111
112         object_class->finalize = presence_chooser_finalize;
113
114         g_type_class_add_private (object_class, sizeof (EmpathyPresenceChooserPriv));
115 }
116
117 enum
118 {
119         COL_STATE_ICON_NAME,
120         COL_STATE,
121         COL_STATUS_TEXT,
122         COL_DISPLAY_MARKUP,
123         COL_TYPE,
124         N_COLUMNS
125 };
126
127 enum
128 {
129         ENTRY_TYPE_BUILTIN,
130         ENTRY_TYPE_SAVED,
131         ENTRY_TYPE_CUSTOM,
132 };
133
134 static GtkTreeModel *
135 create_model (void)
136 {
137         GtkListStore *store = gtk_list_store_new (N_COLUMNS,
138                         G_TYPE_STRING,          /* COL_STATE_ICON_NAME */
139                         MC_TYPE_PRESENCE,       /* COL_STATE */
140                         G_TYPE_STRING,          /* COL_STATUS_TEXT */
141                         G_TYPE_STRING,          /* COL_DISPLAY_MARKUP */
142                         G_TYPE_INT);            /* COL_TYPE */
143         
144         GtkTreeIter iter;
145         
146         int i;
147         for (i = 0; i < G_N_ELEMENTS (states); i += 2) {
148                 GList       *list, *l;
149
150                 const char *status = empathy_presence_get_default_message (states[i]);
151                 const char *icon_name = empathy_icon_name_for_presence (states[i]);
152
153                 gtk_list_store_append (store, &iter);
154                 gtk_list_store_set (store, &iter,
155                                 COL_STATE_ICON_NAME, icon_name,
156                                 COL_STATE, states[i],
157                                 COL_STATUS_TEXT, status,
158                                 COL_DISPLAY_MARKUP, status,
159                                 COL_TYPE, ENTRY_TYPE_BUILTIN,
160                                 -1);
161
162                 if (states[i+1]) {
163                         /* Set custom messages if wanted */
164                         list = empathy_status_presets_get (states[i], 5);
165                         for (l = list; l; l = l->next) {
166                                 gtk_list_store_append (store, &iter);
167                                 gtk_list_store_set (store, &iter,
168                                                 COL_STATE_ICON_NAME, icon_name,
169                                                 COL_STATE, states[i],
170                                                 COL_STATUS_TEXT, l->data,
171                                                 COL_DISPLAY_MARKUP, l->data,
172                                                 COL_TYPE, ENTRY_TYPE_SAVED,
173                                                 -1);
174                         }
175                         g_list_free (list);
176                 
177                         gtk_list_store_append (store, &iter);
178                         gtk_list_store_set (store, &iter,
179                                         COL_STATE_ICON_NAME, icon_name,
180                                         COL_STATE, states[i],
181                                         COL_STATUS_TEXT, "",
182                                         COL_DISPLAY_MARKUP, "<i>Custom Message...</i>",
183                                         COL_TYPE, ENTRY_TYPE_CUSTOM,
184                                         -1);
185                 }
186
187         }
188
189         return GTK_TREE_MODEL (store);
190 }
191
192 static void
193 popup_shown_cb (GObject *self, GParamSpec *pspec, gpointer user_data)
194 {
195         gboolean shown;
196         g_object_get (self, "popup-shown", &shown, NULL);
197
198         if (!shown) return;
199
200         g_print ("popup shown\n");
201
202         GtkTreeModel *model = create_model ();
203
204         gtk_combo_box_set_model (GTK_COMBO_BOX (self), GTK_TREE_MODEL (model));
205         
206         g_object_unref (model);
207 }
208
209 static void
210 set_status_editing (EmpathyPresenceChooser *self, gboolean editing)
211 {
212         EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
213         GtkWidget *entry = gtk_bin_get_child (GTK_BIN (self));
214
215         if (priv->block_set_editing) return;
216
217         if (editing)
218         {
219                 gtk_entry_set_icon_from_stock (GTK_ENTRY (entry),
220                                 GTK_ENTRY_ICON_SECONDARY,
221                                 GTK_STOCK_OK);
222                 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry),
223                                 GTK_ENTRY_ICON_SECONDARY,
224                                 "Set status");
225                 // FIXME - is this nice?
226                 gtk_entry_set_icon_sensitive (GTK_ENTRY (entry),
227                                 GTK_ENTRY_ICON_PRIMARY,
228                                 FALSE);
229         }
230         else
231         {
232                 gtk_entry_set_icon_from_stock (GTK_ENTRY (entry),
233                                 GTK_ENTRY_ICON_SECONDARY,
234                                 NULL);
235                 gtk_entry_set_icon_tooltip_text (GTK_ENTRY (entry),
236                                 GTK_ENTRY_ICON_SECONDARY,
237                                 NULL);
238                 // FIXME - also this
239                 gtk_entry_set_icon_sensitive (GTK_ENTRY (entry),
240                                 GTK_ENTRY_ICON_PRIMARY,
241                                 TRUE);
242
243                 // FIXME - move the focus somewhere
244
245                 /* update the status with MC */
246                 const char *status = gtk_entry_get_text (GTK_ENTRY (entry));
247                 empathy_idle_set_presence (priv->idle, priv->state, status);
248         }
249 }
250
251 static void
252 ui_set_custom_state (EmpathyPresenceChooser *self,
253                            McPresence state,
254                            const char *status)
255 {
256         EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
257         GtkWidget *entry = gtk_bin_get_child (GTK_BIN (self));
258         const char *icon_name;
259
260         priv->block_set_editing++;
261
262         icon_name = empathy_icon_name_for_presence (state);
263         gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
264                         GTK_ENTRY_ICON_PRIMARY,
265                         icon_name);
266         gtk_entry_set_text (GTK_ENTRY (entry), status);
267
268         priv->block_set_editing--;
269 }
270
271 static void
272 entry_icon_release_cb (EmpathyPresenceChooser   *self,
273                        GtkEntryIconPosition      icon_pos,
274                        GdkEvent         *event,
275                        GtkEntry         *entry)
276 {
277         set_status_editing (self, FALSE);
278 }
279
280 static void
281 entry_activate_cb (EmpathyPresenceChooser       *self,
282                    GtkEntry                     *entry)
283 {
284         g_print ("ACTIVATE! (form of a dragon)\n");
285         
286         set_status_editing (self, FALSE);
287 }
288
289 static void
290 changed_cb (GtkComboBox *self, gpointer user_data)
291 {
292         EmpathyPresenceChooserPriv *priv = GET_PRIV (self);
293         g_print ("Changed\n");
294
295         GtkTreeIter iter;
296         char *icon_name;
297         int type = -1;
298
299         GtkTreeModel *model = gtk_combo_box_get_model (self);
300         if (!gtk_combo_box_get_active_iter (self, &iter))
301         {
302                 /* the combo is being edited to a custom entry */
303                 set_status_editing (EMPATHY_PRESENCE_CHOOSER (self), TRUE);
304                 return;
305         }
306
307         gtk_tree_model_get (model, &iter,
308                         COL_STATE_ICON_NAME, &icon_name,
309                         COL_STATE, &priv->state,
310                         COL_TYPE, &type,
311                         -1);
312
313         GtkWidget *entry = gtk_bin_get_child (GTK_BIN (self));
314         gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
315                         GTK_ENTRY_ICON_PRIMARY,
316                         icon_name);
317
318         if (type == ENTRY_TYPE_CUSTOM)
319         {
320                 /* grab the focus */
321                 gtk_widget_grab_focus (entry);
322                 set_status_editing (EMPATHY_PRESENCE_CHOOSER (self), TRUE);
323         }
324         else
325         {
326                 char *status;
327                 /* just in case we were setting a new status when
328                  * things were changed */
329                 set_status_editing (EMPATHY_PRESENCE_CHOOSER (self), FALSE);
330
331                 gtk_tree_model_get (model, &iter,
332                                 COL_STATUS_TEXT, &status,
333                                 -1);
334
335                 empathy_idle_set_presence (priv->idle, priv->state, status);
336
337                 g_free (status);
338         }
339
340         g_free (icon_name);
341 }
342
343 static void
344 empathy_presence_chooser_init (EmpathyPresenceChooser *chooser)
345 {
346         //GtkWidget                  *arrow;
347         //GtkWidget                  *alignment;
348         EmpathyPresenceChooserPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (chooser,
349                 EMPATHY_TYPE_PRESENCE_CHOOSER, EmpathyPresenceChooserPriv);
350
351
352         chooser->priv = priv;
353         
354         GtkTreeModel *model = create_model ();
355
356         gtk_combo_box_set_model (GTK_COMBO_BOX (chooser), GTK_TREE_MODEL (model));
357         gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (chooser), COL_STATUS_TEXT);
358         
359         GtkWidget *entry = gtk_bin_get_child (GTK_BIN (chooser));
360         gtk_entry_set_icon_activatable (GTK_ENTRY (entry),
361                         GTK_ENTRY_ICON_PRIMARY, FALSE);
362         g_signal_connect_object (entry, "icon-release",
363                         G_CALLBACK (entry_icon_release_cb), chooser,
364                         G_CONNECT_SWAPPED);
365         g_signal_connect_object (entry, "activate",
366                         G_CALLBACK (entry_activate_cb), chooser,
367                         G_CONNECT_SWAPPED);
368
369         GtkCellRenderer *renderer;
370         gtk_cell_layout_clear (GTK_CELL_LAYOUT (chooser));
371
372         renderer = gtk_cell_renderer_pixbuf_new ();
373         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (chooser), renderer, FALSE);
374         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (chooser), renderer,
375                         "icon-name", COL_STATE_ICON_NAME,
376                         NULL);
377         g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL);
378
379         renderer = gtk_cell_renderer_text_new ();
380         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (chooser), renderer, TRUE);
381         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (chooser), renderer,
382                         "markup", COL_DISPLAY_MARKUP,
383                         NULL);
384
385         g_object_unref (model);
386
387         g_signal_connect (chooser, "notify::popup-shown",
388                         G_CALLBACK (popup_shown_cb), NULL);
389         g_signal_connect (chooser, "changed",
390                         G_CALLBACK (changed_cb), NULL);
391
392         priv->idle = empathy_idle_dup_singleton ();
393         presence_chooser_presence_changed_cb (chooser);
394         g_signal_connect_swapped (priv->idle, "notify",
395                                   G_CALLBACK (presence_chooser_presence_changed_cb),
396                                   chooser);
397 }
398
399 static void
400 presence_chooser_finalize (GObject *object)
401 {
402         EmpathyPresenceChooserPriv *priv;
403
404         priv = GET_PRIV (object);
405
406         if (priv->flash_timeout_id) {
407                 g_source_remove (priv->flash_timeout_id);
408         }
409
410         g_signal_handlers_disconnect_by_func (priv->idle,
411                                               presence_chooser_presence_changed_cb,
412                                               object);
413         g_object_unref (priv->idle);
414
415         G_OBJECT_CLASS (empathy_presence_chooser_parent_class)->finalize (object);
416 }
417
418 GtkWidget *
419 empathy_presence_chooser_new (void)
420 {
421         GtkWidget *chooser;
422
423         chooser = g_object_new (EMPATHY_TYPE_PRESENCE_CHOOSER, NULL);
424
425         return chooser;
426 }
427
428 static void
429 presence_chooser_presence_changed_cb (EmpathyPresenceChooser *chooser)
430 {
431         EmpathyPresenceChooserPriv *priv;
432         McPresence                 state;
433         McPresence                 flash_state;
434         const gchar               *status;
435
436         g_print (" > presence_chooser_presence_changed_cb\n");
437
438         priv = GET_PRIV (chooser);
439
440         state = empathy_idle_get_state (priv->idle);
441         status = empathy_idle_get_status (priv->idle);
442         flash_state = empathy_idle_get_flash_state (priv->idle);
443
444         g_print ("status = %s\n", status);
445
446         // FIXME - we need to either find an entry in the model or add one
447         GtkTreeModel *model = gtk_combo_box_get_model (GTK_COMBO_BOX (chooser));
448         GtkTreeIter iter;
449         gboolean valid, match_state = FALSE, match = FALSE;
450         for (valid = gtk_tree_model_get_iter_first (model, &iter);
451              valid;
452              valid = gtk_tree_model_iter_next (model, &iter))
453         {
454                 int m_type;
455                 McPresence m_state;
456                 char *m_status;
457
458                 gtk_tree_model_get (model, &iter,
459                                 COL_STATE, &m_state,
460                                 COL_TYPE, &m_type,
461                                 -1);
462
463                 if (m_type == ENTRY_TYPE_CUSTOM)
464                 {
465                         continue;
466                 }
467                 else if (!match_state && state == m_state)
468                 {
469                         /* we are now in the section that can contain our
470                          * match */
471                         match_state = TRUE;
472                 }
473                 else if (match_state && state != m_state)
474                 {
475                         /* we have passed the section that can contain our
476                          * match */
477                         break;
478                 }
479
480                 gtk_tree_model_get (model, &iter,
481                                 COL_STATUS_TEXT, &m_status,
482                                 -1);
483
484                 match = !strcmp (status, m_status);
485
486                 g_free (m_status);
487
488                 if (match) break;
489
490         }
491
492         if (match)
493         {
494                 g_print ("GOT MATCH\n");
495                 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (chooser), &iter);
496         }
497         else
498         {
499                 g_print ("NO MATCH\n");
500                 // FIXME - do we insert the match into the menu?
501                 ui_set_custom_state (chooser, state, status);
502         }
503
504         if (flash_state != MC_PRESENCE_UNSET) {
505                 presence_chooser_flash_start (chooser, state, flash_state);
506         } else {
507                 presence_chooser_flash_stop (chooser, state);
508         }
509 }
510
511 static gboolean
512 presence_chooser_flash_timeout_cb (EmpathyPresenceChooser *chooser)
513 {
514 #if 0
515         EmpathyPresenceChooserPriv *priv;
516         McPresence                 state;
517         static gboolean            on = FALSE;
518
519         priv = GET_PRIV (chooser);
520
521         if (on) {
522                 state = priv->flash_state_1;
523         } else {
524                 state = priv->flash_state_2;
525         }
526
527         gtk_image_set_from_icon_name (GTK_IMAGE (priv->image),
528                                       empathy_icon_name_for_presence (state),
529                                       GTK_ICON_SIZE_MENU);
530
531         on = !on;
532 #endif
533         return TRUE;
534 }
535
536 static void
537 presence_chooser_flash_start (EmpathyPresenceChooser *chooser,
538                               McPresence             state_1,
539                               McPresence             state_2)
540 {
541         EmpathyPresenceChooserPriv *priv;
542
543         g_return_if_fail (EMPATHY_IS_PRESENCE_CHOOSER (chooser));
544
545         priv = GET_PRIV (chooser);
546
547         priv->flash_state_1 = state_1;
548         priv->flash_state_2 = state_2;
549
550         if (!priv->flash_timeout_id) {
551                 priv->flash_timeout_id = g_timeout_add (FLASH_TIMEOUT,
552                                                         (GSourceFunc) presence_chooser_flash_timeout_cb,
553                                                         chooser);
554         }
555 }
556
557 static void
558 presence_chooser_flash_stop (EmpathyPresenceChooser *chooser,
559                              McPresence             state)
560 {
561         EmpathyPresenceChooserPriv *priv;
562
563         g_return_if_fail (EMPATHY_IS_PRESENCE_CHOOSER (chooser));
564
565         priv = GET_PRIV (chooser);
566
567         if (priv->flash_timeout_id) {
568                 g_source_remove (priv->flash_timeout_id);
569                 priv->flash_timeout_id = 0;
570         }
571
572         /*
573         gtk_image_set_from_icon_name (GTK_IMAGE (priv->image),
574                                       empathy_icon_name_for_presence (state),
575                                       GTK_ICON_SIZE_MENU);
576          */
577
578         // FIXME - what does this do?
579         // priv->last_state = state;
580 }
581
582 GtkWidget *
583 empathy_presence_chooser_create_menu (void)
584 {
585         const gchar *status;
586         GtkWidget   *menu;
587         GtkWidget   *item;
588         GtkWidget   *image;
589         guint        i;
590
591         menu = gtk_menu_new ();
592
593         for (i = 0; i < G_N_ELEMENTS (states); i += 2) {
594                 GList       *list, *l;
595
596                 status = empathy_presence_get_default_message (states[i]);
597                 presence_chooser_menu_add_item (menu,
598                                                 status,
599                                                 states[i]);
600
601                 if (states[i+1]) {
602                         /* Set custom messages if wanted */
603                         list = empathy_status_presets_get (states[i], 5);
604                         for (l = list; l; l = l->next) {
605                                 presence_chooser_menu_add_item (menu,
606                                                                 l->data,
607                                                                 states[i]);
608                         }
609                         g_list_free (list);
610                 }
611
612         }
613
614         /* Separator. */
615         item = gtk_menu_item_new ();
616         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
617         gtk_widget_show (item);
618
619         /* Custom messages */
620         item = gtk_image_menu_item_new_with_label (_("Custom messages..."));
621         image = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU);
622         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
623         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
624         gtk_widget_show (image);
625         gtk_widget_show (item);
626
627         g_signal_connect (item,
628                           "activate",
629                           G_CALLBACK (presence_chooser_custom_activate_cb),
630                           NULL);
631
632         return menu;
633 }
634
635 static void
636 presence_chooser_menu_add_item (GtkWidget   *menu,
637                                 const gchar *str,
638                                 McPresence   state)
639 {
640         GtkWidget   *item;
641         GtkWidget   *image;
642         const gchar *icon_name;
643
644         item = gtk_image_menu_item_new_with_label (str);
645         icon_name = empathy_icon_name_for_presence (state);
646
647         g_signal_connect (item, "activate",
648                           G_CALLBACK (presence_chooser_noncustom_activate_cb),
649                           NULL);
650
651         image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
652         gtk_widget_show (image);
653
654         gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
655         gtk_widget_show (item);
656
657         g_object_set_data_full (G_OBJECT (item),
658                                 "status", g_strdup (str),
659                                 (GDestroyNotify) g_free);
660
661         g_object_set_data (G_OBJECT (item), "state", GINT_TO_POINTER (state));
662
663         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
664 }
665
666 static void
667 presence_chooser_noncustom_activate_cb (GtkWidget *item,
668                                         gpointer   user_data)
669 {
670         McPresence   state;
671         const gchar *status;
672
673         status = g_object_get_data (G_OBJECT (item), "status");
674         state = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "state"));
675
676         presence_chooser_set_state (state, status);
677 }
678
679 static void
680 presence_chooser_set_state (McPresence   state,
681                             const gchar *status)
682 {
683         EmpathyIdle *idle;
684
685         idle = empathy_idle_dup_singleton ();
686         empathy_idle_set_presence (idle, state, status);
687         g_object_unref (idle);
688 }
689
690 static void
691 presence_chooser_custom_activate_cb (GtkWidget *item,
692                                      gpointer   user_data)
693 {
694         presence_chooser_dialog_show ();
695 }
696
697 static McPresence
698 presence_chooser_dialog_get_selected (CustomMessageDialog *dialog)
699 {
700         GtkTreeModel *model;
701         GtkTreeIter   iter;
702         McPresence    presence = LAST_MC_PRESENCE;
703
704         model = gtk_combo_box_get_model (GTK_COMBO_BOX (dialog->combobox_status));
705         if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (dialog->combobox_status), &iter)) {
706                 gtk_tree_model_get (model, &iter,
707                                     COL_PRESENCE, &presence,
708                                     -1);
709         }
710
711         return presence;
712 }
713
714 static void
715 presence_chooser_dialog_status_changed_cb (GtkWidget           *widget,
716                                            CustomMessageDialog *dialog)
717 {
718         GtkListStore *store;
719         GtkTreeIter   iter;
720         McPresence    presence = LAST_MC_PRESENCE;
721         GList        *messages, *l;
722
723         presence = presence_chooser_dialog_get_selected (dialog);
724
725         store = gtk_list_store_new (1, G_TYPE_STRING);
726         messages = empathy_status_presets_get (presence, -1);
727         for (l = messages; l; l = l->next) {
728                 gtk_list_store_append (store, &iter);
729                 gtk_list_store_set (store, &iter, 0, l->data, -1);
730         }
731
732         gtk_entry_set_text (GTK_ENTRY (dialog->entry_message),
733                             messages ? messages->data : "");
734
735         g_list_free (messages);
736
737         gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->comboboxentry_message),
738                                  GTK_TREE_MODEL (store));
739
740         g_object_unref (store);
741 }
742
743 static void
744 presence_chooser_dialog_message_changed_cb (GtkWidget           *widget,
745                                             CustomMessageDialog *dialog)
746 {
747         McPresence   presence;
748         GList       *messages, *l;
749         const gchar *text;
750         gboolean     found = FALSE;
751
752         presence = presence_chooser_dialog_get_selected (dialog);
753         text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message));
754
755         messages = empathy_status_presets_get (presence, -1);
756         for (l = messages; l; l = l->next) {
757                 if (!tp_strdiff (text, l->data)) {
758                         found = TRUE;
759                         break;
760                 }
761         }
762         g_list_free (messages);
763
764         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_save),
765                                       found);
766 }
767
768 static void
769 presence_chooser_dialog_save_toggled_cb (GtkWidget           *widget,
770                                          CustomMessageDialog *dialog)
771 {
772         gboolean     active;
773         McPresence   state;
774         const gchar *text;
775
776         active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->checkbutton_save));
777         state = presence_chooser_dialog_get_selected (dialog);
778         text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message));
779
780         if (active) {
781                 empathy_status_presets_set_last (state, text);
782         } else {
783                 empathy_status_presets_remove (state, text);
784         }
785 }
786
787 static void
788 presence_chooser_dialog_setup (CustomMessageDialog *dialog)
789 {
790         GtkListStore    *store;
791         GtkCellRenderer *renderer;
792         GtkTreeIter      iter;
793         guint            i;
794
795         store = gtk_list_store_new (COL_COUNT,
796                                     G_TYPE_STRING,     /* Icon name */
797                                     G_TYPE_STRING,     /* Label     */
798                                     MC_TYPE_PRESENCE); /* Presence   */
799         gtk_combo_box_set_model (GTK_COMBO_BOX (dialog->combobox_status),
800                                  GTK_TREE_MODEL (store));
801
802         renderer = gtk_cell_renderer_pixbuf_new ();
803         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, FALSE);
804         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combobox_status), renderer,
805                                         "icon-name", COL_ICON,
806                                         NULL);
807         g_object_set (renderer, "stock-size", GTK_ICON_SIZE_BUTTON, NULL);
808
809         renderer = gtk_cell_renderer_text_new ();
810         gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (dialog->combobox_status), renderer, TRUE);
811         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (dialog->combobox_status), renderer,
812                                         "text", COL_LABEL,
813                                         NULL);
814
815         for (i = 0; i < G_N_ELEMENTS (states); i += 2) {
816                 if (!states[i+1]) {
817                         continue;
818                 }
819
820                 gtk_list_store_append (store, &iter);
821                 gtk_list_store_set (store, &iter,
822                                     COL_ICON, empathy_icon_name_for_presence (states[i]),
823                                     COL_LABEL, empathy_presence_get_default_message (states[i]),
824                                     COL_PRESENCE, states[i],
825                                     -1);
826         }
827
828         gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->combobox_status), 0);
829 }
830
831 static void
832 presence_chooser_dialog_response_cb (GtkWidget           *widget,
833                                      gint                 response,
834                                      CustomMessageDialog *dialog)
835 {
836         if (response == GTK_RESPONSE_APPLY) {
837                 McPresence   state;
838                 const gchar *text;
839
840                 state = presence_chooser_dialog_get_selected (dialog);
841                 text = gtk_entry_get_text (GTK_ENTRY (dialog->entry_message));
842
843                 presence_chooser_set_state (state, text);
844         }
845
846         gtk_widget_destroy (widget);
847 }
848
849 static void
850 presence_chooser_dialog_destroy_cb (GtkWidget           *widget,
851                                     CustomMessageDialog *dialog)
852 {
853
854         g_free (dialog);
855         message_dialog = NULL;
856 }
857
858 static void
859 presence_chooser_dialog_show (void)
860 {
861         GladeXML *glade;
862         gchar    *filename;
863
864         if (message_dialog) {
865                 gtk_window_present (GTK_WINDOW (message_dialog->dialog));
866                 return;
867         }
868
869         message_dialog = g_new0 (CustomMessageDialog, 1);
870
871         filename = empathy_file_lookup ("empathy-presence-chooser.glade",
872                                         "libempathy-gtk");
873         glade = empathy_glade_get_file (filename,
874                                        "custom_message_dialog",
875                                        NULL,
876                                        "custom_message_dialog", &message_dialog->dialog,
877                                        "checkbutton_save", &message_dialog->checkbutton_save,
878                                        "comboboxentry_message", &message_dialog->comboboxentry_message,
879                                        "combobox_status", &message_dialog->combobox_status,
880                                        NULL);
881         g_free (filename);
882
883         empathy_glade_connect (glade,
884                                message_dialog,
885                                "custom_message_dialog", "destroy", presence_chooser_dialog_destroy_cb,
886                                "custom_message_dialog", "response", presence_chooser_dialog_response_cb,
887                                "combobox_status", "changed", presence_chooser_dialog_status_changed_cb,
888                                "checkbutton_save", "toggled", presence_chooser_dialog_save_toggled_cb,
889                                NULL);
890
891         g_object_unref (glade);
892
893         /* Setup the message combobox */
894         message_dialog->entry_message = GTK_BIN (message_dialog->comboboxentry_message)->child;
895         gtk_entry_set_activates_default (GTK_ENTRY (message_dialog->entry_message), TRUE);
896         gtk_entry_set_width_chars (GTK_ENTRY (message_dialog->entry_message), 25);
897         g_signal_connect (message_dialog->entry_message, "changed",
898                           G_CALLBACK (presence_chooser_dialog_message_changed_cb),
899                           message_dialog);
900
901         presence_chooser_dialog_setup (message_dialog);
902
903         gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (message_dialog->comboboxentry_message), 0);
904
905         /* FIXME: Set transian for a window ? */
906
907         gtk_widget_show_all (message_dialog->dialog);
908 }
909