]> git.0d.be Git - empathy.git/blob - src/empathy-import-dialog.c
Report errors during creation
[empathy.git] / src / empathy-import-dialog.c
1 /*
2  * Copyright (C) 2008 Collabora Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA  02110-1301  USA
18  *
19  * Authors: Jonny Lamb <jonny.lamb@collabora.co.uk>
20  * */
21
22 #include <config.h>
23
24 #include <string.h>
25
26 #include <glib.h>
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29
30 #include <telepathy-glib/util.h>
31
32 #include "empathy-import-dialog.h"
33 #include "empathy-import-pidgin.h"
34
35 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
36 #include <libempathy/empathy-debug.h>
37 #include <libempathy/empathy-utils.h>
38 #include <libempathy/empathy-account-manager.h>
39 #include <libempathy/empathy-connection-managers.h>
40 #include <libempathy-gtk/empathy-ui-utils.h>
41
42 typedef struct
43 {
44   GtkWidget *window;
45   GtkWidget *treeview;
46   GtkWidget *button_ok;
47   GtkWidget *button_cancel;
48   GList *accounts;
49 } EmpathyImportDialog;
50
51 enum
52 {
53   COL_IMPORT = 0,
54   COL_PROTOCOL,
55   COL_NAME,
56   COL_SOURCE,
57   COL_ACCOUNT_DATA,
58   COL_COUNT
59 };
60
61 EmpathyImportAccountData *
62 empathy_import_account_data_new (const gchar *source)
63 {
64   EmpathyImportAccountData *data;
65
66   g_return_val_if_fail (!EMP_STR_EMPTY (source), NULL);
67
68   data = g_slice_new0 (EmpathyImportAccountData);
69   data->settings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
70     (GDestroyNotify) tp_g_value_slice_free);
71   data->source = g_strdup (source);
72   data->protocol = NULL;
73   data->connection_manager = NULL;
74
75   return data;
76 }
77
78 void
79 empathy_import_account_data_free (EmpathyImportAccountData *data)
80 {
81   if (data == NULL)
82     return;
83   if (data->protocol != NULL)
84     g_free (data->protocol);
85   if (data->connection_manager != NULL)
86     g_free (data->connection_manager);
87   if (data->settings != NULL)
88     g_hash_table_destroy (data->settings);
89   if (data->source != NULL)
90     g_free (data->source);
91
92   g_slice_free (EmpathyImportAccountData, data);
93 }
94
95 static void
96 import_dialog_create_account_cb (GObject *source,
97   GAsyncResult *result,
98   gpointer user_data)
99 {
100   EmpathyImportAccountData *data = (EmpathyImportAccountData *) user_data;
101   EmpathyAccount *account;
102   GError *error = NULL;
103
104   account = empathy_account_manager_create_account_finish (
105     EMPATHY_ACCOUNT_MANAGER (source), result, &error);
106
107   if (account == NULL)
108     {
109       DEBUG ("Failed to create account: %s",
110           error ? error->message : "No error given");
111       g_clear_error (&error);
112       empathy_import_account_data_free (data);
113       return;
114     }
115
116   DEBUG ("account created\n");
117
118   g_object_unref (account);
119 }
120
121 static void
122 import_dialog_add_account (EmpathyImportAccountData *data)
123 {
124   EmpathyAccountManager *account_manager;
125   gchar *display_name;
126   GHashTable *properties;
127   GValue *username;
128
129   account_manager = empathy_account_manager_dup_singleton ();
130
131   DEBUG ("connection_manager: %s\n", data->connection_manager);
132
133   /* Set the display name of the account */
134   username = g_hash_table_lookup (data->settings, "account");
135   display_name = g_strdup_printf ("%s (%s)",
136       data->protocol,
137       g_value_get_string (username));
138
139   DEBUG ("display name: %s\n", display_name);
140
141   properties = g_hash_table_new (NULL, NULL);
142
143   empathy_account_manager_create_account_async (account_manager,
144       (const gchar*) data->connection_manager, data->protocol, display_name,
145       data->settings, properties, import_dialog_create_account_cb, NULL);
146
147   g_hash_table_unref (properties);
148   g_free (display_name);
149   g_object_unref (account_manager);
150 }
151
152 static gboolean
153 import_dialog_account_id_in_list (GList *accounts,
154                                   const gchar *account_id)
155 {
156   GList *l;
157
158   for (l = accounts; l; l = l->next)
159     {
160       EmpathyAccount *account = l->data;
161       const gchar *account_string;
162       GValue *value;
163       gboolean result;
164       const GHashTable *parameters;
165
166       parameters = empathy_account_get_parameters (account);
167
168       value = g_hash_table_lookup ((GHashTable *) parameters, "account");
169
170       if (value == NULL)
171         continue;
172
173       account_string = g_value_get_string (value);
174
175       result = tp_strdiff (account_string, account_id);
176
177       if (!result)
178         return TRUE;
179     }
180
181   return FALSE;
182 }
183
184 static gboolean protocol_is_supported (EmpathyImportAccountData *data)
185 {
186   EmpathyConnectionManagers *cm =
187       empathy_connection_managers_dup_singleton ();
188   GList *cms = empathy_connection_managers_get_cms (cm);
189   GList *l;
190   gboolean proto_is_supported = FALSE;
191
192   for (l = cms; l; l = l->next)
193     {
194       TpConnectionManager *tp_cm = l->data;
195       const gchar *cm_name = tp_connection_manager_get_name (tp_cm);
196       if (tp_connection_manager_has_protocol (tp_cm,
197           (const gchar*)data->protocol))
198         {
199           data->connection_manager = g_strdup (cm_name);
200           proto_is_supported = TRUE;
201           break;
202         }
203     }
204
205   g_object_unref (cm);
206
207   return proto_is_supported;
208 }
209
210 static void
211 import_dialog_add_accounts_to_model (EmpathyImportDialog *dialog)
212 {
213   GtkTreeModel *model;
214   GtkTreeIter iter;
215   GList *l;
216   EmpathyAccountManager *manager = empathy_account_manager_dup_singleton ();
217
218   model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
219
220   for (l = dialog->accounts; l; l = l->next)
221     {
222       GValue *value;
223       EmpathyImportAccountData *data = l->data;
224       gboolean import;
225       GList *accounts;
226
227       if (!protocol_is_supported (data))
228         continue;
229
230       value = g_hash_table_lookup (data->settings, "account");
231
232       accounts = empathy_account_manager_dup_accounts (manager);
233
234       /* Only set the "Import" cell to be active if there isn't already an
235        * account set up with the same account id. */
236       import = !import_dialog_account_id_in_list (accounts,
237           g_value_get_string (value));
238
239       g_list_foreach (accounts, (GFunc) g_object_unref, NULL);
240       g_list_free (accounts);
241
242       gtk_list_store_append (GTK_LIST_STORE (model), &iter);
243
244       gtk_list_store_set (GTK_LIST_STORE (model), &iter,
245           COL_IMPORT, import,
246           COL_PROTOCOL, data->protocol,
247           COL_NAME, g_value_get_string (value),
248           COL_SOURCE, data->source,
249           COL_ACCOUNT_DATA, data,
250           -1);
251     }
252
253   g_object_unref (manager);
254 }
255
256 static void
257 import_dialog_cell_toggled_cb (GtkCellRendererToggle *cell_renderer,
258                                const gchar *path_str,
259                                EmpathyImportDialog *dialog)
260 {
261   GtkTreeModel *model;
262   GtkTreeIter iter;
263   GtkTreePath *path;
264
265   path = gtk_tree_path_new_from_string (path_str);
266   model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
267
268   gtk_tree_model_get_iter (model, &iter, path);
269
270   gtk_list_store_set (GTK_LIST_STORE (model), &iter,
271       COL_IMPORT, !gtk_cell_renderer_toggle_get_active (cell_renderer),
272       -1);
273
274   gtk_tree_path_free (path);
275 }
276
277 static void
278 import_dialog_set_up_account_list (EmpathyImportDialog *dialog)
279 {
280   GtkListStore *store;
281   GtkTreeView *view;
282   GtkTreeViewColumn *column;
283   GtkCellRenderer *cell;
284
285   store = gtk_list_store_new (COL_COUNT, G_TYPE_BOOLEAN, G_TYPE_STRING,
286       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
287
288   gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview),
289       GTK_TREE_MODEL (store));
290
291   g_object_unref (store);
292
293   view = GTK_TREE_VIEW (dialog->treeview);
294   gtk_tree_view_set_headers_visible (view, TRUE);
295
296   /* Import column */
297   cell = gtk_cell_renderer_toggle_new ();
298   gtk_tree_view_insert_column_with_attributes (view, -1,
299       /* Translators: this is the header of a treeview column */
300       _("Import"), cell,
301       "active", COL_IMPORT,
302       NULL);
303
304   g_signal_connect (cell, "toggled",
305       G_CALLBACK (import_dialog_cell_toggled_cb), dialog);
306
307   /* Protocol column */
308   column = gtk_tree_view_column_new ();
309   gtk_tree_view_column_set_title (column, _("Protocol"));
310   gtk_tree_view_column_set_expand (column, TRUE);
311   gtk_tree_view_append_column (view, column);
312
313   cell = gtk_cell_renderer_text_new ();
314   g_object_set (cell,
315       "editable", FALSE,
316       NULL);
317   gtk_tree_view_column_pack_start (column, cell, TRUE);
318   gtk_tree_view_column_add_attribute (column, cell, "text", COL_PROTOCOL);
319
320   /* Account column */
321   column = gtk_tree_view_column_new ();
322   gtk_tree_view_column_set_title (column, _("Account"));
323   gtk_tree_view_column_set_expand (column, TRUE);
324   gtk_tree_view_append_column (view, column);
325
326   cell = gtk_cell_renderer_text_new ();
327   g_object_set (cell,
328       "editable", FALSE,
329       NULL);
330   gtk_tree_view_column_pack_start (column, cell, TRUE);
331   gtk_tree_view_column_add_attribute (column, cell, "text", COL_NAME);
332
333   /* Source column */
334   column = gtk_tree_view_column_new ();
335   gtk_tree_view_column_set_title (column, _("Source"));
336   gtk_tree_view_column_set_expand (column, TRUE);
337   gtk_tree_view_append_column (view, column);
338
339   cell = gtk_cell_renderer_text_new ();
340   g_object_set (cell,
341       "editable", FALSE,
342       NULL);
343   gtk_tree_view_column_pack_start (column, cell, TRUE);
344   gtk_tree_view_column_add_attribute (column, cell, "text", COL_SOURCE);
345
346   import_dialog_add_accounts_to_model (dialog);
347 }
348
349 static gboolean
350 import_dialog_tree_model_foreach (GtkTreeModel *model,
351                                   GtkTreePath *path,
352                                   GtkTreeIter *iter,
353                                   gpointer user_data)
354 {
355   gboolean to_import;
356   EmpathyImportAccountData *data;
357
358   gtk_tree_model_get (model, iter,
359       COL_IMPORT, &to_import,
360       COL_ACCOUNT_DATA, &data,
361       -1);
362
363   if (to_import)
364     import_dialog_add_account (data);
365
366   return FALSE;
367 }
368
369 static void
370 import_dialog_response_cb (GtkWidget *widget,
371                            gint response,
372                            EmpathyImportDialog *dialog)
373 {
374   if (response == GTK_RESPONSE_OK)
375     {
376       GtkTreeModel *model;
377
378       model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview));
379       gtk_tree_model_foreach (model, import_dialog_tree_model_foreach, dialog);
380     }
381
382   gtk_widget_destroy (dialog->window);
383 }
384
385 static void
386 import_dialog_destroy_cb (GtkWidget *widget,
387                           EmpathyImportDialog *dialog)
388 {
389   g_list_foreach (dialog->accounts, (GFunc) empathy_import_account_data_free,
390     NULL);
391   g_list_free (dialog->accounts);
392   g_slice_free (EmpathyImportDialog, dialog);
393 }
394
395 gboolean
396 empathy_import_dialog_accounts_to_import (void)
397 {
398   return empathy_import_pidgin_accounts_to_import ();
399 }
400
401 void
402 empathy_import_dialog_show (GtkWindow *parent,
403                             gboolean warning)
404 {
405   static EmpathyImportDialog *dialog = NULL;
406   GtkBuilder *gui;
407   gchar *filename;
408   GList *accounts = NULL;
409
410   /* This window is a singleton. If it already exist, present it */
411   if (dialog)
412     {
413       gtk_window_present (GTK_WINDOW (dialog->window));
414       return;
415     }
416
417   /* Load all accounts from all supported applications */
418   accounts = g_list_concat (accounts, empathy_import_pidgin_load ());
419
420   /* Check if we have accounts to import before creating the window */
421   if (!accounts)
422     {
423       GtkWidget *message;
424
425       if (warning)
426         {
427           message = gtk_message_dialog_new (parent,
428               GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE,
429               _("No accounts to import could be found. Empathy currently only "
430                 "supports importing accounts from Pidgin."));
431
432           gtk_dialog_run (GTK_DIALOG (message));
433           gtk_widget_destroy (message);
434         }
435       else
436         DEBUG ("No accounts to import; closing dialog silently.");
437
438       return;
439     }
440
441   /* We have accounts, let's display the window with them */
442   dialog = g_slice_new0 (EmpathyImportDialog);
443   dialog->accounts = accounts;
444
445   filename = empathy_file_lookup ("empathy-import-dialog.ui", "src");
446   gui = empathy_builder_get_file (filename,
447       "import_dialog", &dialog->window,
448       "treeview", &dialog->treeview,
449       NULL);
450
451   empathy_builder_connect (gui, dialog,
452       "import_dialog", "destroy", import_dialog_destroy_cb,
453       "import_dialog", "response", import_dialog_response_cb,
454       NULL);
455
456   g_object_add_weak_pointer (G_OBJECT (dialog->window), (gpointer) &dialog);
457
458   g_free (filename);
459   g_object_unref (gui);
460
461   if (parent)
462     gtk_window_set_transient_for (GTK_WINDOW (dialog->window), parent);
463
464   import_dialog_set_up_account_list (dialog);
465
466   gtk_widget_show (dialog->window);
467 }
468