]> git.0d.be Git - empathy.git/blob - ubuntu-online-accounts/cc-plugins/empathy-accounts-plugin-widget.c
accounts-plugin-widget: keep a ref on the 'Done' button
[empathy.git] / ubuntu-online-accounts / cc-plugins / empathy-accounts-plugin-widget.c
1 /*
2  * empathy-accounts-plugin-widget.c
3  *
4  * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21
22 #include "config.h"
23
24 #include "empathy-accounts-plugin-widget.h"
25
26 #include <glib/gi18n-lib.h>
27
28 #include <telepathy-glib/telepathy-glib.h>
29
30 #include <libaccounts-glib/ag-service.h>
31 #include <libaccounts-glib/ag-account-service.h>
32
33 #include <libempathy-gtk/empathy-account-widget.h>
34
35 G_DEFINE_TYPE (EmpathyAccountsPluginWidget, empathy_accounts_plugin_widget, GTK_TYPE_BOX)
36
37 enum
38 {
39   PROP_ACCOUNT = 1,
40   N_PROPS
41 };
42
43 enum
44 {
45   SIG_DONE,
46   LAST_SIGNAL
47 };
48
49 static guint signals[LAST_SIGNAL];
50
51 struct _EmpathyAccountsPluginWidgetPriv
52 {
53   AgAccount *account;
54
55   EmpathyAccountSettings *settings;
56
57   EmpathyAccountWidget *account_widget;
58   GtkWidget *done_button;
59 };
60
61 static void
62 empathy_accounts_plugin_widget_get_property (GObject *object,
63     guint property_id,
64     GValue *value,
65     GParamSpec *pspec)
66 {
67   EmpathyAccountsPluginWidget *self = EMPATHY_ACCOUNTS_PLUGIN_WIDGET (object);
68
69   switch (property_id)
70     {
71       case PROP_ACCOUNT:
72         g_value_set_object (value, self->priv->account);
73         break;
74       default:
75         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
76         break;
77     }
78 }
79
80 static void
81 empathy_accounts_plugin_widget_set_property (GObject *object,
82     guint property_id,
83     const GValue *value,
84     GParamSpec *pspec)
85 {
86   EmpathyAccountsPluginWidget *self = EMPATHY_ACCOUNTS_PLUGIN_WIDGET (object);
87
88   switch (property_id)
89     {
90       case PROP_ACCOUNT:
91         self->priv->account = g_value_dup_object (value);
92         break;
93       default:
94         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
95         break;
96     }
97 }
98
99 static EmpathyAccountSettings *
100 create_account_settings (AgAccount *account)
101 {
102   AgService *service;
103   GList *services;
104   AgAccountService *account_service;
105   GValue v = G_VALUE_INIT;
106   gchar *manager = NULL, *protocol = NULL;
107   EmpathyAccountSettings *settings;
108
109   g_assert (account->id == 0);
110
111   services = ag_account_list_services_by_type (account, "IM");
112   g_return_val_if_fail (services != NULL, NULL);
113   service = (AgService *) services->data;
114
115   account_service = ag_account_service_new (account, service);
116
117   g_value_init (&v, G_TYPE_STRING);
118   if (ag_account_service_get_value (account_service,
119         "telepathy/manager", &v) != AG_SETTING_SOURCE_NONE)
120     manager = g_value_dup_string (&v);
121   g_value_unset (&v);
122
123   g_value_init (&v, G_TYPE_STRING);
124   if (ag_account_service_get_value (account_service,
125         "telepathy/protocol", &v) != AG_SETTING_SOURCE_NONE)
126     protocol = g_value_dup_string (&v);
127   g_value_unset (&v);
128
129   g_return_val_if_fail (manager != NULL, NULL);
130   g_return_val_if_fail (protocol != NULL, NULL);
131
132   settings = empathy_account_settings_new (manager, protocol, NULL,
133       ag_service_get_display_name (service));
134
135   empathy_account_settings_set_storage_provider (settings,
136       EMPATHY_UOA_PROVIDER);
137
138   empathy_account_settings_set_icon_name_async (settings,
139     ag_service_get_icon_name (service), NULL, NULL);
140
141   g_free (manager);
142   g_free (protocol);
143
144   return settings;
145 }
146
147 static void
148 response_cb (GtkWidget *widget,
149     gint response,
150     EmpathyAccountsPluginWidget *self)
151 {
152   if (response == GTK_RESPONSE_OK)
153     {
154       empathy_account_widget_apply_and_log_in (self->priv->account_widget);
155
156       /* Rely on account_widget_close_cb to fire the 'done' signal */
157     }
158   else
159     {
160       empathy_account_widget_discard_pending_changes (
161           self->priv->account_widget);
162
163       g_signal_emit (self, signals[SIG_DONE], 0);
164     }
165 }
166
167 static GtkWidget *
168 create_top_bar (EmpathyAccountsPluginWidget *self)
169 {
170   GtkWidget *bar, *content, *action, *label;
171   GtkCssProvider *css;
172   GError *error = NULL;
173
174   bar = gtk_info_bar_new_with_buttons (
175       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
176       NULL);
177
178   self->priv->done_button = gtk_info_bar_add_button (GTK_INFO_BAR (bar),
179       _("Done"), GTK_RESPONSE_OK);
180
181   gtk_widget_set_hexpand (bar, TRUE);
182   gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_QUESTION);
183   action = gtk_info_bar_get_action_area (GTK_INFO_BAR (bar));
184   gtk_orientable_set_orientation (GTK_ORIENTABLE (action),
185       GTK_ORIENTATION_HORIZONTAL);
186   gtk_widget_set_name (bar, "authorization-infobar");
187   css = gtk_css_provider_new ();
188   if (gtk_css_provider_load_from_data (css,
189           "@define-color question_bg_color rgb (222, 222, 222);"
190           "GtkInfoBar#authorization-infobar"
191           "{"
192           "  color: @fg_color;"
193           "}",
194           -1, &error))
195     {
196       GtkStyleContext *context = gtk_widget_get_style_context (bar);
197
198       gtk_style_context_add_provider (context, (GtkStyleProvider *) css,
199           GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
200     }
201   else
202     {
203       g_warning ("Error processing CSS theme override: %s", error->message);
204       g_clear_error (&error);
205     }
206   g_object_unref (css);
207
208   content = gtk_info_bar_get_content_area (GTK_INFO_BAR (bar));
209
210   label = gtk_label_new (_("Please enter your account details"));
211   gtk_container_add (GTK_CONTAINER (content), label);
212   gtk_widget_show (label);
213
214   g_signal_connect (bar, "response",
215       G_CALLBACK (response_cb), self);
216
217   return bar;
218 }
219
220 static void
221 account_widget_handle_apply_cb (EmpathyAccountWidget *widget,
222     gboolean valid,
223     EmpathyAccountsPluginWidget *self)
224 {
225   gtk_widget_set_sensitive (self->priv->done_button, valid);
226 }
227
228 static void
229 account_widget_close_cb (EmpathyAccountWidget *widget,
230     GtkResponseType response,
231     EmpathyAccountsPluginWidget *self)
232 {
233   g_signal_emit (self, signals[SIG_DONE], 0);
234 }
235
236 static void
237 add_account_widget (EmpathyAccountsPluginWidget *self)
238 {
239   GtkWidget *alig;
240
241   alig = gtk_alignment_new (0.5, 0, 0, 0);
242
243   gtk_box_pack_start (GTK_BOX (self), alig, TRUE, TRUE, 0);
244   gtk_widget_show (GTK_WIDGET (alig));
245
246   self->priv->account_widget = empathy_account_widget_new_for_protocol (
247       self->priv->settings, TRUE);
248
249   empathy_account_widget_hide_buttons (self->priv->account_widget);
250
251   gtk_widget_set_valign (GTK_WIDGET (self->priv->account_widget),
252       GTK_ALIGN_CENTER);
253
254   gtk_container_add (GTK_CONTAINER (alig),
255       GTK_WIDGET (self->priv->account_widget));
256   gtk_widget_show (GTK_WIDGET (self->priv->account_widget));
257
258   if (!empathy_account_settings_is_valid (self->priv->settings))
259     {
260       gtk_widget_set_sensitive (self->priv->done_button, FALSE);
261     }
262
263   g_signal_connect (self->priv->account_widget, "handle-apply",
264       G_CALLBACK (account_widget_handle_apply_cb), self);
265   g_signal_connect (self->priv->account_widget, "close",
266       G_CALLBACK (account_widget_close_cb), self);
267 }
268
269 static void
270 maybe_add_account_widget (EmpathyAccountsPluginWidget *self)
271 {
272   g_return_if_fail (self->priv->settings != NULL);
273
274   if (empathy_account_settings_is_ready (self->priv->settings))
275     {
276       add_account_widget (self);
277     }
278   else
279     {
280       g_signal_connect_swapped (self->priv->settings, "notify::ready",
281           G_CALLBACK (add_account_widget), self);
282     }
283 }
284
285 static void
286 manager_prepared_cb (GObject *source,
287     GAsyncResult *result,
288     gpointer user_data)
289 {
290   EmpathyAccountsPluginWidget *self = user_data;
291   TpAccountManager *manager = (TpAccountManager *) source;
292   GList *accounts;
293   GError *error = NULL;
294
295   if (!tp_proxy_prepare_finish (manager, result, &error))
296     {
297       g_debug ("Error preparing Account Manager: %s", error->message);
298       g_clear_error (&error);
299       goto out;
300     }
301
302   accounts = tp_account_manager_get_valid_accounts (manager);
303   while (accounts != NULL)
304     {
305       TpAccount *account = accounts->data;
306       const GValue *value;
307
308       value = tp_account_get_storage_identifier (account);
309       if (G_VALUE_HOLDS_UINT (value) &&
310           g_value_get_uint (value) == self->priv->account->id)
311         {
312           self->priv->settings = empathy_account_settings_new_for_account (
313               account);
314           maybe_add_account_widget (self);
315           break;
316         }
317
318       accounts = g_list_delete_link (accounts, accounts);
319     }
320   g_list_free (accounts);
321
322 out:
323   g_object_unref (self);
324 }
325
326 static void
327 empathy_accounts_plugin_widget_constructed (GObject *object)
328 {
329   EmpathyAccountsPluginWidget *self = EMPATHY_ACCOUNTS_PLUGIN_WIDGET (object);
330   void (*chain_up) (GObject *) =
331       ((GObjectClass *) empathy_accounts_plugin_widget_parent_class)->constructed;
332   GtkWidget *top;
333
334   if (chain_up != NULL)
335     chain_up (object);
336
337   g_return_if_fail (AG_IS_ACCOUNT (self->priv->account));
338
339   /* Top bar */
340   top = create_top_bar (self);
341   gtk_widget_show (top);
342   gtk_box_pack_start (GTK_BOX (self), top, FALSE, FALSE, 0);
343
344   if (self->priv->account->id != 0)
345     {
346       TpAccountManager *manager;
347
348       /* Prepare tp's account manager to find the TpAccount corresponding to our
349        * AgAccount */
350       manager = tp_account_manager_dup ();
351
352       tp_proxy_prepare_async (manager, NULL,
353           manager_prepared_cb, g_object_ref (self));
354       g_object_unref (manager);
355       return;
356     }
357
358   self->priv->settings = create_account_settings (self->priv->account);
359   maybe_add_account_widget (self);
360 }
361
362 static void
363 empathy_accounts_plugin_widget_dispose (GObject *object)
364 {
365   EmpathyAccountsPluginWidget *self = EMPATHY_ACCOUNTS_PLUGIN_WIDGET (object);
366   void (*chain_up) (GObject *) =
367       ((GObjectClass *) empathy_accounts_plugin_widget_parent_class)->dispose;
368
369   g_clear_object (&self->priv->account);
370   g_clear_object (&self->priv->settings);
371
372   if (chain_up != NULL)
373     chain_up (object);
374 }
375
376 static void
377 empathy_accounts_plugin_widget_class_init (
378     EmpathyAccountsPluginWidgetClass *klass)
379 {
380   GObjectClass *oclass = G_OBJECT_CLASS (klass);
381   GParamSpec *spec;
382
383   oclass->get_property = empathy_accounts_plugin_widget_get_property;
384   oclass->set_property = empathy_accounts_plugin_widget_set_property;
385   oclass->constructed = empathy_accounts_plugin_widget_constructed;
386   oclass->dispose = empathy_accounts_plugin_widget_dispose;
387
388   spec = g_param_spec_object ("account", "account",
389       "AgAccount",
390       AG_TYPE_ACCOUNT,
391       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
392   g_object_class_install_property (oclass, PROP_ACCOUNT, spec);
393
394   signals[SIG_DONE] = g_signal_new ("done",
395       G_OBJECT_CLASS_TYPE (klass),
396       G_SIGNAL_RUN_LAST,
397       0, NULL, NULL, NULL,
398       G_TYPE_NONE,
399       0);
400
401   g_type_class_add_private (klass, sizeof (EmpathyAccountsPluginWidgetPriv));
402 }
403
404 static void
405 empathy_accounts_plugin_widget_init (EmpathyAccountsPluginWidget *self)
406 {
407   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
408       EMPATHY_TYPE_ACCOUNTS_PLUGIN_WIDGET, EmpathyAccountsPluginWidgetPriv);
409 }
410
411 GtkWidget *
412 empathy_accounts_plugin_widget_new (AgAccount *account)
413 {
414   return g_object_new (EMPATHY_TYPE_ACCOUNTS_PLUGIN_WIDGET,
415       "account", account,
416       "orientation", GTK_ORIENTATION_VERTICAL,
417       "spacing", 10,
418       NULL);
419 }