]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-new-message-dialog.c
new-message-dialog: inherit from GtkDialog (#604097)
[empathy.git] / libempathy-gtk / empathy-new-message-dialog.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007-2008 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library 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  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include <config.h>
23
24 #include <string.h>
25 #include <stdlib.h>
26
27 #include <gtk/gtk.h>
28 #include <glib/gi18n-lib.h>
29
30 #include <libempathy/empathy-call-factory.h>
31 #include <libempathy/empathy-tp-contact-factory.h>
32 #include <libempathy/empathy-contact-manager.h>
33 #include <libempathy/empathy-dispatcher.h>
34 #include <libempathy/empathy-utils.h>
35
36 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
37 #include <libempathy/empathy-debug.h>
38
39 #include <libempathy-gtk/empathy-ui-utils.h>
40 #include <libempathy-gtk/empathy-images.h>
41
42 #include "empathy-new-message-dialog.h"
43 #include "empathy-account-chooser.h"
44
45 static EmpathyNewMessageDialog *dialog_singleton = NULL;
46
47 G_DEFINE_TYPE(EmpathyNewMessageDialog, empathy_new_message_dialog,
48                                        GTK_TYPE_DIALOG)
49
50 /**
51  * SECTION:empathy-new-message-dialog
52  * @title: EmpathyNewMessageDialog
53  * @short_description: A dialog to show a new message
54  * @include: libempathy-gtk/empathy-new-message-dialog.h
55  *
56  * #EmpathyNewMessageDialog is a dialog which allows a text chat or
57  * call to be started with any contact on any enabled account.
58  */
59
60 typedef struct _EmpathyNewMessageDialogPriv EmpathyNewMessageDialogPriv;
61
62 struct _EmpathyNewMessageDialogPriv {
63         GtkWidget *dialog;
64         GtkWidget *table_contact;
65         GtkWidget *account_chooser;
66         GtkWidget *entry_id;
67         GtkWidget *button_chat;
68         GtkWidget *button_call;
69         EmpathyContactManager *contact_manager;
70 };
71
72 #define GET_PRIV(o) \
73   (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_NEW_MESSAGE_DIALOG, \
74     EmpathyNewMessageDialogPriv))
75
76 enum {
77         COMPLETION_COL_TEXT,
78         COMPLETION_COL_ID,
79         COMPLETION_COL_NAME,
80 } CompletionCol;
81
82 static void
83 new_message_dialog_account_changed_cb (GtkWidget               *widget,
84                                        EmpathyNewMessageDialog *dialog)
85 {
86         EmpathyNewMessageDialogPriv *priv = GET_PRIV (dialog);
87         EmpathyAccountChooser *chooser;
88         TpConnection          *connection;
89         EmpathyTpContactList *contact_list;
90         GList                *members;
91         GtkListStore         *store;
92         GtkEntryCompletion   *completion;
93         GtkTreeIter           iter;
94         gchar                *tmpstr;
95
96         /* Remove completions */
97         completion = gtk_entry_get_completion (GTK_ENTRY (priv->entry_id));
98         store = GTK_LIST_STORE (gtk_entry_completion_get_model (completion));
99         gtk_list_store_clear (store);
100
101         /* Get members of the new account */
102         chooser = EMPATHY_ACCOUNT_CHOOSER (priv->account_chooser);
103         connection = empathy_account_chooser_get_connection (chooser);
104         if (!connection) {
105                 return;
106         }
107         contact_list = empathy_contact_manager_get_list (priv->contact_manager,
108                                                          connection);
109         members = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (contact_list));
110
111         /* Add members to the completion */
112         while (members) {
113                 EmpathyContact *contact = members->data;
114
115                 DEBUG ("Adding contact ID %s, Name %s",
116                        empathy_contact_get_id (contact),
117                        empathy_contact_get_name (contact));
118
119                 tmpstr = g_strdup_printf ("%s (%s)",
120                         empathy_contact_get_name (contact),
121                         empathy_contact_get_id (contact));
122
123                 gtk_list_store_insert_with_values (store, &iter, -1,
124                         COMPLETION_COL_TEXT, tmpstr,
125                         COMPLETION_COL_ID, empathy_contact_get_id (contact),
126                         COMPLETION_COL_NAME, empathy_contact_get_name (contact),
127                         -1);
128
129                 g_free (tmpstr);
130
131                 g_object_unref (contact);
132                 members = g_list_delete_link (members, members);
133         }
134 }
135
136 static gboolean
137 new_message_dialog_match_selected_cb (GtkEntryCompletion *widget,
138                                       GtkTreeModel       *model,
139                                       GtkTreeIter        *iter,
140                                       EmpathyNewMessageDialog *dialog)
141 {
142         EmpathyNewMessageDialogPriv *priv = GET_PRIV (dialog);
143         gchar *id;
144
145         if (!iter || !model) {
146                 return FALSE;
147         }
148
149         gtk_tree_model_get (model, iter, COMPLETION_COL_ID, &id, -1);
150         gtk_entry_set_text (GTK_ENTRY (priv->entry_id), id);
151
152         DEBUG ("Got selected match **%s**", id);
153
154         g_free (id);
155
156         return TRUE;
157 }
158
159 static gboolean
160 new_message_dialog_match_func (GtkEntryCompletion *completion,
161                                const gchar        *key,
162                                GtkTreeIter        *iter,
163                                gpointer            user_data)
164 {
165         GtkTreeModel *model;
166         gchar        *id;
167         gchar        *name;
168
169         model = gtk_entry_completion_get_model (completion);
170         if (!model || !iter) {
171                 return FALSE;
172         }
173
174         gtk_tree_model_get (model, iter, COMPLETION_COL_NAME, &name, -1);
175         if (strstr (name, key)) {
176                 DEBUG ("Key %s is matching name **%s**", key, name);
177                 g_free (name);
178                 return TRUE;
179         }
180         g_free (name);
181
182         gtk_tree_model_get (model, iter, COMPLETION_COL_ID, &id, -1);
183         if (strstr (id, key)) {
184                 DEBUG ("Key %s is matching ID **%s**", key, id);
185                 g_free (id);
186                 return TRUE;
187         }
188         g_free (id);
189
190         return FALSE;
191 }
192
193 static void
194 new_message_dialog_call_got_contact_cb (EmpathyTpContactFactory *factory,
195                                         EmpathyContact          *contact,
196                                         const GError            *error,
197                                         gpointer                 user_data,
198                                         GObject                 *weak_object)
199 {
200         EmpathyCallFactory *call_factory;
201
202         if (error != NULL) {
203                 DEBUG ("Error: %s", error->message);
204                 return;
205         }
206
207         call_factory = empathy_call_factory_get ();
208         empathy_call_factory_new_call (call_factory, contact);
209 }
210
211 static void
212 new_message_dialog_response_cb (GtkWidget               *widget,
213                                 gint                    response,
214                                 EmpathyNewMessageDialog *dialog)
215 {
216         EmpathyNewMessageDialogPriv *priv = GET_PRIV (dialog);
217         TpConnection *connection;
218         const gchar *id;
219
220         connection = empathy_account_chooser_get_connection (
221                 EMPATHY_ACCOUNT_CHOOSER (priv->account_chooser));
222         id = gtk_entry_get_text (GTK_ENTRY (priv->entry_id));
223         if (!connection || EMP_STR_EMPTY (id)) {
224                 gtk_widget_destroy (widget);
225                 return;
226         }
227
228         if (response == 1) {
229                 EmpathyTpContactFactory *factory;
230
231                 factory = empathy_tp_contact_factory_dup_singleton (connection);
232                 empathy_tp_contact_factory_get_from_id (factory, id,
233                         new_message_dialog_call_got_contact_cb,
234                         NULL, NULL, NULL);
235                 g_object_unref (factory);
236         } else if (response == 2) {
237                 empathy_dispatcher_chat_with_contact_id (connection, id, NULL, NULL);
238         }
239
240         gtk_widget_destroy (widget);
241 }
242
243 static void
244 new_message_change_state_button_cb  (GtkEditable             *editable,
245                                      EmpathyNewMessageDialog *dialog)
246 {
247         EmpathyNewMessageDialogPriv *priv = GET_PRIV (dialog);
248         const gchar *id;
249         gboolean     sensitive;
250
251         id = gtk_entry_get_text (GTK_ENTRY (editable));
252         sensitive = !EMP_STR_EMPTY (id);
253
254         gtk_widget_set_sensitive (priv->button_chat, sensitive);
255         gtk_widget_set_sensitive (priv->button_call, sensitive);
256 }
257
258 static GObject *
259 empathy_new_message_dialog_constructor (GType type,
260                                         guint n_props,
261                                         GObjectConstructParam *props)
262 {
263         GObject *retval;
264
265         if (dialog_singleton) {
266                 retval = G_OBJECT (dialog_singleton);
267                 g_object_ref (retval);
268         }
269         else {
270                 retval = G_OBJECT_CLASS (
271                 empathy_new_message_dialog_parent_class)->constructor (type,
272                         n_props, props);
273
274                 dialog_singleton = EMPATHY_NEW_MESSAGE_DIALOG (retval);
275                 g_object_add_weak_pointer (retval, (gpointer) &dialog_singleton);
276         }
277
278         return retval;
279 }
280
281 static void
282 empathy_new_message_dialog_init (EmpathyNewMessageDialog *dialog)
283 {
284         EmpathyNewMessageDialogPriv *priv = GET_PRIV (dialog);
285         GtkBuilder                     *gui;
286         gchar                          *filename;
287         GtkEntryCompletion             *completion;
288         GtkListStore                   *model;
289         GtkWidget                      *content_area;
290         GtkWidget                      *image;
291
292         /* create a contact manager */
293         priv->contact_manager = empathy_contact_manager_dup_singleton ();
294
295         filename = empathy_file_lookup ("empathy-new-message-dialog.ui",
296                                         "libempathy-gtk");
297         gui = empathy_builder_get_file (filename,
298                                         "table_contact", &priv->table_contact,
299                                         "entry_id", &priv->entry_id,
300                                         NULL);
301         g_free (filename);
302
303         content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
304         gtk_container_add (GTK_CONTAINER (content_area), priv->table_contact);
305
306         /* add buttons */
307         gtk_dialog_add_button (GTK_DIALOG (dialog),
308                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
309
310         priv->button_call = gtk_button_new_with_mnemonic (_("C_all"));
311         image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_VOIP,
312                 GTK_ICON_SIZE_BUTTON);
313         gtk_button_set_image (GTK_BUTTON (priv->button_call), image);
314
315         gtk_dialog_add_action_widget (GTK_DIALOG (dialog), priv->button_call, 1);
316         gtk_widget_show (priv->button_call);
317
318         priv->button_chat = gtk_button_new_with_mnemonic (_("C_hat"));
319         image = gtk_image_new_from_icon_name (EMPATHY_IMAGE_NEW_MESSAGE,
320                 GTK_ICON_SIZE_BUTTON);
321         gtk_button_set_image (GTK_BUTTON (priv->button_chat), image);
322
323         gtk_dialog_add_action_widget (GTK_DIALOG (dialog), priv->button_chat, 2);
324         gtk_widget_show (priv->button_chat);
325
326         /* Tweak the dialog */
327         gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
328
329         gtk_window_set_title (GTK_WINDOW (dialog), _("New Conversation"));
330         gtk_window_set_role (GTK_WINDOW (dialog), "new_message");
331         gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
332         gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ON_PARENT);
333         gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
334
335         /* text completion */
336         completion = gtk_entry_completion_new ();
337         model = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
338         gtk_entry_completion_set_text_column (completion, COMPLETION_COL_TEXT);
339         gtk_entry_completion_set_match_func (completion,
340                                              new_message_dialog_match_func,
341                                              NULL, NULL);
342         gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (model));
343         gtk_entry_set_completion (GTK_ENTRY (priv->entry_id), completion);
344         g_signal_connect (completion, "match-selected",
345                           G_CALLBACK (new_message_dialog_match_selected_cb),
346                           dialog);
347         g_object_unref (completion);
348         g_object_unref (model);
349
350         g_signal_connect (dialog, "response",
351                     G_CALLBACK (new_message_dialog_response_cb), dialog);
352
353         empathy_builder_connect (gui, dialog,
354                                "entry_id", "changed", new_message_change_state_button_cb,
355                                NULL);
356
357         g_object_unref (gui);
358
359         /* Create account chooser */
360         priv->account_chooser = empathy_account_chooser_new ();
361         gtk_table_attach_defaults (GTK_TABLE (priv->table_contact),
362                                    priv->account_chooser,
363                                    1, 2, 0, 1);
364         empathy_account_chooser_set_filter (EMPATHY_ACCOUNT_CHOOSER (priv->account_chooser),
365                                             empathy_account_chooser_filter_is_connected,
366                                             NULL);
367         gtk_widget_show (priv->account_chooser);
368
369         new_message_dialog_account_changed_cb (priv->account_chooser, dialog);
370         g_signal_connect (priv->account_chooser, "changed",
371                           G_CALLBACK (new_message_dialog_account_changed_cb),
372                           dialog);
373
374         gtk_widget_set_sensitive (priv->button_chat, FALSE);
375         gtk_widget_set_sensitive (priv->button_call, FALSE);
376 }
377
378 static void
379 empathy_new_message_dialog_dispose (GObject *object)
380 {
381         EmpathyNewMessageDialogPriv *priv = GET_PRIV (object);
382
383         if (priv->contact_manager != NULL) {
384                 g_object_unref (priv->contact_manager);
385                 priv->contact_manager = NULL;
386         }
387
388         if (G_OBJECT_CLASS (empathy_new_message_dialog_parent_class)->dispose)
389                 G_OBJECT_CLASS (empathy_new_message_dialog_parent_class)->dispose (object);
390 }
391
392 static void
393 empathy_new_message_dialog_class_init (
394   EmpathyNewMessageDialogClass *class)
395 {
396         GObjectClass *object_class = G_OBJECT_CLASS (class);
397
398         g_type_class_add_private (class, sizeof (EmpathyNewMessageDialogPriv));
399
400         object_class->constructor = empathy_new_message_dialog_constructor;
401
402         object_class->dispose = empathy_new_message_dialog_dispose;
403 }
404
405 /**
406  * empathy_new_message_dialog_new:
407  * @parent: parent #GtkWindow of the dialog
408  *
409  * Create a new #EmpathyNewMessageDialog it.
410  *
411  * Return value: the new #EmpathyNewMessageDialog
412  */
413 GtkWidget *
414 empathy_new_message_dialog_show (GtkWindow *parent)
415 {
416         GtkWidget *dialog;
417
418         dialog = g_object_new (EMPATHY_TYPE_NEW_MESSAGE_DIALOG, NULL);
419
420         if (parent) {
421                 gtk_window_set_transient_for (GTK_WINDOW (dialog),
422                                               GTK_WINDOW (parent));
423         }
424
425         gtk_widget_show (dialog);
426         return dialog;
427 }