]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-contact-search-dialog.c
Merge branch 'gnome-3-6'
[empathy.git] / libempathy-gtk / empathy-contact-search-dialog.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * empathy-contact-search-dialog.c
4  *
5  * Copyright (C) 2010-2011 Collabora Ltd.
6  *
7  * The code contained in this file is free software; you can redistribute
8  * it and/or modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either version
10  * 2.1 of the License, or (at your option) any later version.
11  *
12  * This file is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this code; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  * Authors:
22  *     Danielle Madeley <danielle.madeley@collabora.co.uk>
23  *     Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
24  */
25 #include "config.h"
26
27 #include <glib/gi18n-lib.h>
28
29 #include <telepathy-glib/telepathy-glib.h>
30
31 #include <libempathy/empathy-utils.h>
32 #include <libempathy/empathy-client-factory.h>
33
34 #include <libempathy-gtk/empathy-account-chooser.h>
35 #include <libempathy-gtk/empathy-cell-renderer-text.h>
36 #include <libempathy-gtk/empathy-cell-renderer-activatable.h>
37 #include <libempathy-gtk/empathy-individual-information-dialog.h>
38 #include <libempathy-gtk/empathy-images.h>
39
40 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
41 #include <libempathy/empathy-debug.h>
42
43 #include "empathy-contact-search-dialog.h"
44
45 #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CONTACT_SEARCH_DIALOG, EmpathyContactSearchDialogPrivate))
46
47 G_DEFINE_TYPE (EmpathyContactSearchDialog, empathy_contact_search_dialog, GTK_TYPE_DIALOG);
48
49 enum
50 {
51    NAME_COLUMN,
52    LOGIN_COLUMN,
53    N_COLUMNS
54 };
55
56 enum {
57    PAGE_SEARCH_RESULTS,
58    PAGE_NO_MATCH
59 };
60
61 typedef struct _EmpathyContactSearchDialogPrivate EmpathyContactSearchDialogPrivate;
62 struct _EmpathyContactSearchDialogPrivate
63 {
64   TpContactSearch *searcher;
65   GtkListStore *store;
66
67   GtkWidget *chooser;
68   GtkWidget *notebook;
69   GtkWidget *tree_view;
70   GtkWidget *spinner;
71   GtkWidget *add_button;
72   GtkWidget *find_button;
73   GtkWidget *no_contact_found;
74   GtkWidget *search_entry;
75   /* GtkWidget *server_entry; */
76   GtkWidget *message;
77   GtkWidget *message_window;
78   GtkWidget *message_label;
79 };
80
81 static void
82 empathy_contact_search_dialog_dispose (GObject *self)
83 {
84   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
85
86   tp_clear_object (&priv->searcher);
87
88   G_OBJECT_CLASS (empathy_contact_search_dialog_parent_class)->dispose (self);
89 }
90
91 static void
92 on_searcher_reset (GObject *source_object,
93     GAsyncResult *result,
94     gpointer user_data)
95 {
96   EmpathyContactSearchDialog *self = EMPATHY_CONTACT_SEARCH_DIALOG (user_data);
97   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
98   TpContactSearch *searcher = TP_CONTACT_SEARCH (source_object);
99   GError *error = NULL;
100   GHashTable *search;
101   const gchar *search_criteria;
102
103   tp_contact_search_reset_finish (searcher, result, &error);
104   if (error != NULL)
105     {
106       DEBUG ("Failed to reset the TpContactSearch: %s", error->message);
107       g_error_free (error);
108       return;
109     }
110
111   search = g_hash_table_new (g_str_hash, g_str_equal);
112
113   search_criteria = gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
114
115   if (tp_strv_contains (tp_contact_search_get_search_keys (searcher), ""))
116     g_hash_table_insert (search, "", (gpointer) search_criteria);
117   else
118     g_hash_table_insert (search, "fn", (gpointer) search_criteria);
119
120   gtk_list_store_clear (priv->store);
121   tp_contact_search_start (priv->searcher, search);
122
123   g_hash_table_unref (search);
124 }
125
126 static void
127 empathy_contact_search_dialog_do_search (EmpathyContactSearchDialog *self)
128 {
129   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
130
131   tp_contact_search_reset_async (priv->searcher,
132       NULL, /* gtk_entry_get_text (GTK_ENTRY (priv->server_entry)), */
133       0,
134       on_searcher_reset,
135       self);
136 }
137
138 static void
139 on_get_contact_factory_get_from_id_cb (GObject *source,
140     GAsyncResult *result,
141     gpointer user_data)
142 {
143   gchar *message = user_data;
144   GError *error = NULL;
145   EmpathyContact *contact;
146
147   contact = empathy_client_factory_dup_contact_by_id_finish (
148       EMPATHY_CLIENT_FACTORY (source), result, &error);
149   if (contact == NULL)
150     {
151       g_warning ("Error while getting the contact: %s", error->message);
152       g_error_free (error);
153       goto out;
154     }
155
156   empathy_contact_add_to_contact_list (contact, message);
157   g_object_unref (contact);
158
159 out:
160   g_free (message);
161 }
162
163 static void
164 add_selected_contact (EmpathyContactSearchDialog *self)
165 {
166   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
167   GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
168   TpConnection *conn;
169   GtkTreeIter iter;
170   GtkTreeModel *model;
171   GtkTextBuffer *buffer;
172   GtkTextIter start, end;
173   gchar *message;
174   gboolean sel;
175   gchar *id;
176   EmpathyClientFactory *factory;
177
178   conn = empathy_account_chooser_get_connection (EMPATHY_ACCOUNT_CHOOSER (priv->chooser));
179
180   sel = gtk_tree_selection_get_selected (selection, &model, &iter);
181   g_return_if_fail (sel == TRUE);
182
183   gtk_tree_model_get (model, &iter, LOGIN_COLUMN, &id, -1);
184
185   DEBUG ("Requested to add contact: %s", id);
186
187   buffer = gtk_text_view_get_buffer GTK_TEXT_VIEW (priv->message);
188   gtk_text_buffer_get_start_iter (buffer, &start);
189   gtk_text_buffer_get_end_iter (buffer, &end);
190   message = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
191
192   factory = empathy_client_factory_dup ();
193
194   empathy_client_factory_dup_contact_by_id_async (factory, conn, id,
195       on_get_contact_factory_get_from_id_cb, message);
196
197   g_object_unref (factory);
198
199   /* Close the dialog */
200   gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_CANCEL);
201 }
202
203 static void
204 empathy_contact_search_dialog_response (GtkDialog *self,
205     gint response)
206 {
207   switch (response)
208     {
209       case GTK_RESPONSE_APPLY:
210         add_selected_contact (EMPATHY_CONTACT_SEARCH_DIALOG (self));
211         break;
212       default:
213         gtk_widget_destroy (GTK_WIDGET (self));
214         break;
215     }
216 }
217
218 static void
219 empathy_contact_search_dialog_class_init (
220     EmpathyContactSearchDialogClass *klass)
221 {
222   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
223   GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
224
225   gobject_class->dispose = empathy_contact_search_dialog_dispose;
226
227   dialog_class->response = empathy_contact_search_dialog_response;
228
229   g_type_class_add_private (gobject_class,
230       sizeof (EmpathyContactSearchDialogPrivate));
231 }
232
233 static void
234 _on_search_state_changed_cb (TpContactSearch *searcher,
235     GParamSpec *pspec,
236     gpointer user_data)
237 {
238   EmpathyContactSearchDialog *self = EMPATHY_CONTACT_SEARCH_DIALOG (user_data);
239   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
240   TpChannelContactSearchState state;
241
242   g_object_get (searcher, "state", &state, NULL);
243
244   DEBUG ("new search status: %d", state);
245
246   if (state == TP_CHANNEL_CONTACT_SEARCH_STATE_IN_PROGRESS)
247     {
248       gtk_widget_show (priv->spinner);
249       gtk_spinner_start (GTK_SPINNER (priv->spinner));
250     }
251   else
252     {
253       gtk_widget_hide (priv->spinner);
254       gtk_spinner_stop (GTK_SPINNER (priv->spinner));
255     }
256
257   if (state == TP_CHANNEL_CONTACT_SEARCH_STATE_NOT_STARTED
258       || state == TP_CHANNEL_CONTACT_SEARCH_STATE_IN_PROGRESS)
259     {
260       gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook),
261           PAGE_SEARCH_RESULTS);
262     }
263   else
264     {
265       GtkTreeIter help_iter;
266
267       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->store),
268           &help_iter))
269         {
270           /* No results found, display a helpful message. */
271           gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook),
272               PAGE_NO_MATCH);
273         }
274     }
275 }
276
277 static void
278 _search_results_received (TpContactSearch *searcher,
279     GList *results,
280     EmpathyContactSearchDialog *self)
281 {
282   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
283   const TpContactInfoField *name;
284   GList *l;
285
286   for (l = results; l != NULL; l = l->next)
287     {
288       TpContactSearchResult *result = l->data;
289
290       name = tp_contact_search_result_get_field (result, "fn");
291
292       gtk_list_store_insert_with_values (priv->store, NULL, -1,
293           NAME_COLUMN, name ? name->field_value[0] : NULL,
294           LOGIN_COLUMN, tp_contact_search_result_get_identifier (result),
295           -1);
296     }
297 }
298
299 static void
300 on_searcher_created (GObject *source_object,
301     GAsyncResult *result,
302     gpointer user_data)
303 {
304   EmpathyContactSearchDialog *self;
305   EmpathyContactSearchDialogPrivate *priv;
306   GError *error = NULL;
307
308   if (EMPATHY_IS_CONTACT_SEARCH_DIALOG (user_data) == FALSE)
309     /* This happens if the dialog is closed before the callback is called */
310     return;
311
312   self = EMPATHY_CONTACT_SEARCH_DIALOG (user_data);
313   priv = GET_PRIVATE (self);
314
315   priv->searcher = tp_contact_search_new_finish (result, &error);
316   if (error != NULL)
317     {
318       DEBUG ("Failed to create a TpContactSearch: %s", error->message);
319       g_error_free (error);
320       return;
321     }
322
323   g_signal_connect (priv->searcher, "search-results-received",
324       G_CALLBACK (_search_results_received), self);
325   g_signal_connect (priv->searcher, "notify::state",
326       G_CALLBACK (_on_search_state_changed_cb), self);
327
328   gtk_widget_set_sensitive (priv->find_button, TRUE);
329 }
330
331 static void
332 on_selection_changed (GtkTreeSelection *selection,
333     gpointer user_data)
334 {
335   EmpathyContactSearchDialog *self;
336   EmpathyContactSearchDialogPrivate *priv;
337   gboolean sel;
338
339   self = EMPATHY_CONTACT_SEARCH_DIALOG (user_data);
340   priv = GET_PRIVATE (self);
341   sel = gtk_tree_selection_get_selected (selection, NULL, NULL);
342
343   gtk_widget_set_sensitive (priv->add_button, sel);
344 }
345
346 static void
347 check_request_message_available (EmpathyContactSearchDialog *self,
348     TpConnection *conn)
349 {
350   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
351
352   gtk_widget_set_visible (priv->message_window,
353       tp_connection_get_can_change_contact_list (conn));
354   gtk_widget_set_visible (priv->message_label,
355       tp_connection_get_can_change_contact_list (conn));
356 }
357
358 static void
359 _account_chooser_changed (EmpathyAccountChooser *chooser,
360     EmpathyContactSearchDialog *self)
361 {
362   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
363   TpAccount *account = empathy_account_chooser_get_account (chooser);
364   TpConnection *conn = empathy_account_chooser_get_connection (chooser);
365   TpCapabilities *caps = tp_connection_get_capabilities (conn);
366   gboolean can_cs, can_set_limit, can_set_server;
367
368   can_cs = tp_capabilities_supports_contact_search (caps,
369       &can_set_limit, &can_set_server);
370   DEBUG ("The server supports cs|limit|server: %s|%s|%s",
371       can_cs ? "yes" : "no",
372       can_set_limit ? "yes" : "no",
373       can_set_server ? "yes" : "no");
374
375   /* gtk_widget_set_sensitive (priv->server_entry, can_set_server); */
376   gtk_widget_set_sensitive (priv->find_button, FALSE);
377
378   DEBUG ("New account is %s", tp_proxy_get_object_path (account));
379
380   tp_clear_object (&priv->searcher);
381   tp_contact_search_new_async (account,
382       NULL, /* gtk_entry_get_text (GTK_ENTRY (priv->server_entry)), */
383       0,
384       on_searcher_created, self);
385
386   /* Make the request message textview sensitive if it can be used */
387   check_request_message_available (self, conn);
388 }
389
390 static void
391 _on_button_search_clicked (GtkWidget *widget,
392     EmpathyContactSearchDialog *self)
393 {
394   empathy_contact_search_dialog_do_search (self);
395 }
396
397 #if 0
398 static void
399 on_server_changed_cb (GtkEditable *editable,
400     gpointer user_data)
401 {
402   EmpathyContactSearchDialog *self = EMPATHY_CONTACT_SEARCH_DIALOG (user_data);
403   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
404
405   g_return_if_fail (priv->searcher != NULL);
406
407   tp_contact_search_reset_async (priv->searcher,
408       gtk_entry_get_text (GTK_ENTRY (editable)),
409       0,
410       on_searcher_reset,
411       self);
412 }
413 #endif
414
415 static void
416 empathy_account_chooser_filter_supports_contact_search (
417     TpAccount *account,
418     EmpathyAccountChooserFilterResultCallback callback,
419     gpointer callback_data,
420     gpointer user_data)
421 {
422   TpConnection *connection;
423   gboolean supported = FALSE;
424   TpCapabilities *caps;
425
426   connection = tp_account_get_connection (account);
427   if (connection == NULL)
428       goto out;
429
430   caps = tp_connection_get_capabilities (connection);
431   if (caps == NULL)
432       goto out;
433
434   supported = tp_capabilities_supports_contact_search (caps, NULL, NULL);
435
436 out:
437   callback (supported, callback_data);
438 }
439
440 static void
441 contact_search_dialog_row_activated_cb (GtkTreeView *tv,
442     GtkTreePath *path,
443     GtkTreeViewColumn *column,
444     EmpathyContactSearchDialog *self)
445 {
446   /* just emit the same response as the Add Button */
447   gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_APPLY);
448 }
449
450 static void
451 on_profile_button_got_contact_cb (GObject *source,
452     GAsyncResult *result,
453     gpointer user_data)
454 {
455   GError *error = NULL;
456   EmpathyContact *contact;
457   FolksIndividual *individual;
458
459   contact = empathy_client_factory_dup_contact_by_id_finish (
460         EMPATHY_CLIENT_FACTORY (source), result, &error);
461   if (contact == NULL)
462     {
463       g_warning ("Error while getting the contact: %s", error->message);
464       g_error_free (error);
465       return;
466     }
467
468   individual = empathy_ensure_individual_from_tp_contact (
469     empathy_contact_get_tp_contact (contact));
470
471   empathy_display_individual_info (individual);
472
473   g_object_unref (contact);
474   g_object_unref (individual);
475 }
476
477 static void
478 on_profile_button_clicked_cb (EmpathyCellRendererActivatable *cell,
479     const gchar *path_string,
480     EmpathyContactSearchDialog *self)
481 {
482   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
483   TpConnection *conn;
484   GtkTreeIter iter;
485   GtkTreeModel *model;
486   gboolean valid;
487   gchar *id;
488   EmpathyClientFactory *factory;
489
490   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->tree_view));
491
492   conn = empathy_account_chooser_get_connection (
493       EMPATHY_ACCOUNT_CHOOSER (priv->chooser));
494
495   valid = gtk_tree_model_get_iter_from_string (model, &iter, path_string);
496   g_return_if_fail (valid == TRUE);
497
498   gtk_tree_model_get (model, &iter, LOGIN_COLUMN, &id, -1);
499
500   DEBUG ("Requested to show profile for contact: %s", id);
501
502   factory = empathy_client_factory_dup ();
503
504   empathy_client_factory_dup_contact_by_id_async (factory, conn, id,
505       on_profile_button_got_contact_cb, self);
506
507   g_object_unref (factory);
508 }
509
510 static void
511 empathy_contact_search_dialog_init (EmpathyContactSearchDialog *self)
512 {
513   EmpathyContactSearchDialogPrivate *priv = GET_PRIVATE (self);
514   GtkWidget *vbox, *hbox, *scrolled_window, *label;
515   GtkCellRenderer *cell;
516   GtkTreeViewColumn *col;
517   GtkTreeSelection *selection;
518   GtkSizeGroup *size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
519   gchar *tmp;
520
521   /* Title */
522   gtk_window_set_title (GTK_WINDOW (self), _("Search contacts"));
523
524   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
525   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
526
527   /* Account chooser */
528   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
529   label = gtk_label_new (_("Account:"));
530   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
531   gtk_size_group_add_widget (size_group, label);
532
533   priv->chooser = empathy_account_chooser_new ();
534   empathy_account_chooser_set_filter (EMPATHY_ACCOUNT_CHOOSER (priv->chooser),
535       empathy_account_chooser_filter_supports_contact_search, NULL);
536   gtk_box_pack_start (GTK_BOX (hbox), priv->chooser, TRUE, TRUE, 0);
537   g_signal_connect (priv->chooser, "changed",
538       G_CALLBACK (_account_chooser_changed), self);
539
540   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
541
542 #if 0
543   /* Server entry */
544   priv->server_entry = gtk_entry_new ();
545   gtk_box_pack_start (GTK_BOX (vbox), priv->server_entry, FALSE, TRUE, 6);
546   g_signal_connect (GTK_EDITABLE (priv->server_entry), "changed",
547       G_CALLBACK (on_server_changed_cb), self);
548 #endif
549
550   /* Search input */
551   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
552   label = gtk_label_new (_("Search: "));
553   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
554   gtk_size_group_add_widget (size_group, label);
555
556   priv->search_entry = gtk_entry_new ();
557   gtk_box_pack_start (GTK_BOX (hbox), priv->search_entry, TRUE, TRUE, 0);
558   g_signal_connect (priv->search_entry, "activate",
559       G_CALLBACK (_on_button_search_clicked), self);
560
561   priv->find_button = gtk_button_new_from_stock (GTK_STOCK_FIND);
562   g_signal_connect (priv->find_button, "clicked",
563       G_CALLBACK (_on_button_search_clicked), self);
564   gtk_box_pack_end (GTK_BOX (hbox), priv->find_button, FALSE, TRUE, 0);
565
566   priv->spinner = gtk_spinner_new ();
567   gtk_box_pack_end (GTK_BOX (hbox), priv->spinner, FALSE, TRUE, 0);
568   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
569
570   /* Search results */
571   priv->store = gtk_list_store_new (N_COLUMNS,
572                                     G_TYPE_STRING,  /* Name */
573                                     G_TYPE_STRING); /* Login */
574
575   priv->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (priv->store));
576   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_view));
577   gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
578
579   g_signal_connect (priv->tree_view, "row-activated",
580       G_CALLBACK (contact_search_dialog_row_activated_cb), self);
581   g_signal_connect (selection, "changed",
582       G_CALLBACK (on_selection_changed), self);
583
584   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree_view), FALSE);
585
586   col = gtk_tree_view_column_new ();
587
588   cell = empathy_cell_renderer_text_new ();
589   gtk_tree_view_column_pack_start (col, cell, TRUE);
590   /* EmpathyCellRendererText displays "name" above and "status" below.
591    * We want the login above since it'll always be available, and the
592    * name below since we won't always have it. */
593   gtk_tree_view_column_add_attribute (col, cell,
594       "name", LOGIN_COLUMN);
595   gtk_tree_view_column_add_attribute (col, cell,
596       "status", NAME_COLUMN);
597
598   cell = empathy_cell_renderer_activatable_new ();
599   gtk_tree_view_column_pack_end (col, cell, FALSE);
600   g_object_set (cell, "stock-id", EMPATHY_IMAGE_CONTACT_INFORMATION, NULL);
601   g_signal_connect (cell, "path-activated",
602       G_CALLBACK (on_profile_button_clicked_cb), self);
603
604   gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree_view), col);
605
606   gtk_dialog_add_button (GTK_DIALOG (self),
607       GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
608
609   priv->add_button = gtk_dialog_add_button (GTK_DIALOG (self),
610       _("_Add Contact"), GTK_RESPONSE_APPLY);
611   gtk_widget_set_sensitive (priv->add_button, FALSE);
612   gtk_button_set_image (GTK_BUTTON (priv->add_button),
613       gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON));
614
615   /* Pack the dialog */
616   priv->notebook = gtk_notebook_new ();
617   gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
618   g_object_set (priv->notebook, "margin", 6, NULL);
619
620   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
621   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
622       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
623
624   gtk_container_add (GTK_CONTAINER (scrolled_window), priv->tree_view);
625
626   priv->no_contact_found = gtk_label_new (NULL);
627   tmp = g_strdup_printf ("<b><span size='xx-large'>%s</span></b>",
628       _("No contacts found"));
629   gtk_label_set_markup (GTK_LABEL (priv->no_contact_found), tmp);
630   g_free (tmp);
631
632   gtk_label_set_ellipsize (GTK_LABEL (priv->no_contact_found),
633       PANGO_ELLIPSIZE_END);
634
635   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), scrolled_window,
636       NULL);
637   gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook),
638       priv->no_contact_found, NULL);
639
640   gtk_box_pack_start (GTK_BOX (vbox), priv->notebook, TRUE, TRUE, 3);
641
642   /* Request message textview */
643   priv->message_label = gtk_label_new (
644        _("Your message introducing yourself:"));
645   gtk_misc_set_alignment (GTK_MISC (priv->message_label), 0, 0.5);
646
647   priv->message = gtk_text_view_new ();
648   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->message),
649       GTK_WRAP_WORD_CHAR);
650   gtk_text_buffer_set_text (
651       gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->message)),
652       _("Please let me see when you're online. Thanks!"), -1);
653
654   priv->message_window = gtk_scrolled_window_new (NULL, NULL);
655   gtk_scrolled_window_set_shadow_type (
656       GTK_SCROLLED_WINDOW (priv->message_window),
657       GTK_SHADOW_ETCHED_IN);
658   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->message_window),
659       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
660
661   gtk_container_add (GTK_CONTAINER (priv->message_window), priv->message);
662
663   gtk_box_pack_start (GTK_BOX (vbox), priv->message_label, FALSE, TRUE, 3);
664   gtk_box_pack_start (GTK_BOX (vbox), priv->message_window, FALSE, TRUE, 3);
665
666   gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (
667           GTK_DIALOG (self))), vbox, TRUE, TRUE, 0);
668
669   gtk_window_set_default_size (GTK_WINDOW (self), 200, 400);
670   gtk_widget_show_all (vbox);
671   gtk_widget_hide (priv->spinner);
672   g_object_unref (size_group);
673 }
674
675 GtkWidget *
676 empathy_contact_search_dialog_new (GtkWindow *parent)
677 {
678   GtkWidget *self;
679
680   g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);
681
682   self = g_object_new (EMPATHY_TYPE_CONTACT_SEARCH_DIALOG, NULL);
683
684   if (parent != NULL)
685     {
686       gtk_window_set_transient_for (GTK_WINDOW (self), parent);
687     }
688
689   return self;
690 }