]> git.0d.be Git - empathy.git/blob - src/empathy-debug-dialog.c
ae8cd7ce75e3cd6aa1b8d479cf9f1e0f11340326
[empathy.git] / src / empathy-debug-dialog.c
1 /*
2 *  Copyright (C) 2009 Collabora Ltd.
3 *
4 *  This library is free software; you can redistribute it and/or
5 *  modify it under the terms of the GNU Lesser General Public
6 *  License as published by the Free Software Foundation; either
7 *  version 2.1 of the License, or (at your option) any later version.
8 *
9 *  This library 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 *  Lesser General Public License for more details.
13 *
14 *  You should have received a copy of the GNU Lesser General Public
15 *  License along with this library; if not, write to the Free Software
16 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 *
18 *  Authors: Jonny Lamb <jonny.lamb@collabora.co.uk>
19 */
20
21 #include "config.h"
22
23 #include <glib/gi18n.h>
24 #include <gtk/gtk.h>
25
26 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
27 #include <libempathy/empathy-debug.h>
28 #include <libempathy/empathy-utils.h>
29
30 #include <libempathy-gtk/empathy-account-chooser.h>
31
32 #include <telepathy-glib/dbus.h>
33 #include <telepathy-glib/util.h>
34 #include <telepathy-glib/proxy-subclass.h>
35
36 #include "extensions/extensions.h"
37
38 #include "empathy-debug-dialog.h"
39
40 G_DEFINE_TYPE (EmpathyDebugDialog, empathy_debug_dialog,
41     GTK_TYPE_DIALOG)
42
43 enum
44 {
45   PROP_0,
46   PROP_PARENT
47 };
48
49 enum
50 {
51   COL_TIMESTAMP = 0,
52   COL_DOMAIN,
53   COL_CATEGORY,
54   COL_LEVEL,
55   COL_MESSAGE,
56   NUM_COLS
57 };
58
59 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyDebugDialog)
60 typedef struct
61 {
62   GtkWidget *filter;
63   GtkWindow *parent;
64   GtkWidget *view;
65   GtkWidget *cm_chooser;
66   GtkListStore *store;
67   TpProxy *proxy;
68   TpProxySignalConnection *signal_connection;
69   gboolean paused;
70   GList *bus_names;
71   gboolean dispose_run;
72 } EmpathyDebugDialogPriv;
73
74 static const gchar *
75 log_level_to_string (guint level)
76 {
77   switch (level)
78     {
79     case EMP_DEBUG_LEVEL_ERROR:
80       return _("Error");
81       break;
82     case EMP_DEBUG_LEVEL_CRITICAL:
83       return _("Critical");
84       break;
85     case EMP_DEBUG_LEVEL_WARNING:
86       return _("Warning");
87       break;
88     case EMP_DEBUG_LEVEL_MESSAGE:
89       return _("Message");
90       break;
91     case EMP_DEBUG_LEVEL_INFO:
92       return _("Info");
93       break;
94     case EMP_DEBUG_LEVEL_DEBUG:
95       return _("Debug");
96       break;
97     default:
98       g_assert_not_reached ();
99       break;
100     }
101 }
102
103 static void
104 debug_dialog_add_message (EmpathyDebugDialog *debug_dialog,
105                           gdouble timestamp,
106                           const gchar *domain_category,
107                           guint level,
108                           const gchar *message)
109 {
110   EmpathyDebugDialogPriv *priv = GET_PRIV (debug_dialog);
111   gchar *domain, *category;
112   GtkTreeIter iter;
113
114   if (g_strrstr (domain_category, "/"))
115     {
116       gchar **parts = g_strsplit (domain_category, "/", 2);
117       domain = g_strdup (parts[0]);
118       category = g_strdup (parts[1]);
119       g_strfreev (parts);
120     }
121   else
122     {
123       domain = g_strdup (domain_category);
124       category = g_strdup ("");
125     }
126
127   gtk_list_store_append (priv->store, &iter);
128   gtk_list_store_set (priv->store, &iter,
129       COL_TIMESTAMP, timestamp,
130       COL_DOMAIN, domain,
131       COL_CATEGORY, category,
132       COL_LEVEL, log_level_to_string (level),
133       COL_MESSAGE, message,
134       -1);
135
136   g_free (domain);
137   g_free (category);
138 }
139
140 static void
141 debug_dialog_new_debug_message_cb (TpProxy *proxy,
142                                    gdouble timestamp,
143                                    const gchar *domain,
144                                    guint level,
145                                    const gchar *message,
146                                    gpointer user_data,
147                                    GObject *weak_object)
148 {
149   EmpathyDebugDialog *debug_dialog = (EmpathyDebugDialog *) user_data;
150
151   debug_dialog_add_message (debug_dialog, timestamp, domain, level,
152       message);
153 }
154
155 static void
156 debug_dialog_set_enabled (EmpathyDebugDialog *debug_dialog,
157                           gboolean enabled)
158 {
159   EmpathyDebugDialogPriv *priv = GET_PRIV (debug_dialog);
160   GValue *val;
161
162   val = tp_g_value_slice_new_boolean (enabled);
163
164   tp_cli_dbus_properties_call_set (priv->proxy, -1, EMP_IFACE_DEBUG,
165       "Enabled", val, NULL, NULL, NULL, NULL);
166
167   tp_g_value_slice_free (val);
168 }
169
170 static void
171 debug_dialog_get_messages_cb (TpProxy *proxy,
172                               const GPtrArray *messages,
173                               const GError *error,
174                               gpointer user_data,
175                               GObject *weak_object)
176 {
177   EmpathyDebugDialog *debug_dialog = (EmpathyDebugDialog *) user_data;
178   EmpathyDebugDialogPriv *priv = GET_PRIV (debug_dialog);
179   gint i;
180
181   if (error != NULL)
182     {
183       DEBUG ("GetMessages failed: %s", error->message);
184       return;
185     }
186
187   for (i = 0; i < messages->len; i++)
188     {
189       GValueArray *values = g_ptr_array_index (messages, i);
190
191       debug_dialog_add_message (debug_dialog,
192           g_value_get_double (g_value_array_get_nth (values, 0)),
193           g_value_get_string (g_value_array_get_nth (values, 1)),
194           g_value_get_uint (g_value_array_get_nth (values, 2)),
195           g_value_get_string (g_value_array_get_nth (values, 3)));
196     }
197
198   /* Connect to NewDebugMessage */
199   priv->signal_connection = emp_cli_debug_connect_to_new_debug_message (
200       proxy, debug_dialog_new_debug_message_cb, debug_dialog,
201       NULL, NULL, NULL);
202
203   /* Set Enabled as appropriate */
204   debug_dialog_set_enabled (debug_dialog, !priv->paused);
205 }
206
207 static void
208 debug_dialog_cm_chooser_changed_cb (GtkComboBox *cm_chooser,
209                                     EmpathyDebugDialog *debug_dialog)
210 {
211   EmpathyDebugDialogPriv *priv = GET_PRIV (debug_dialog);
212   MissionControl *mc;
213   TpDBusDaemon *dbus;
214   GError *error = NULL;
215   const gchar *bus_name;
216   TpConnection *connection;
217
218   if (gtk_combo_box_get_active (cm_chooser) == -1)
219     {
220       DEBUG ("No CM is selected");
221       return;
222     }
223
224   mc = empathy_mission_control_dup_singleton ();
225   dbus = tp_dbus_daemon_dup (&error);
226
227   if (error != NULL)
228     {
229       DEBUG ("Failed at duping the dbus daemon: %s", error->message);
230       g_object_unref (mc);
231     }
232
233   bus_name = g_list_nth_data (priv->bus_names, gtk_combo_box_get_active (cm_chooser));
234   connection = tp_connection_new (dbus, bus_name, DEBUG_OBJECT_PATH, &error);
235
236   if (error != NULL)
237     {
238       DEBUG ("Getting a new TpConnection failed: %s", error->message);
239       g_error_free (error);
240       g_object_unref (dbus);
241       g_object_unref (mc);
242       return;
243     }
244
245   /* Disable debug signalling */
246   if (priv->proxy != NULL)
247     debug_dialog_set_enabled (debug_dialog, FALSE);
248
249   /* Disconnect from previous NewDebugMessage signal */
250   if (priv->signal_connection)
251     {
252       tp_proxy_signal_connection_disconnect (priv->signal_connection);
253       priv->signal_connection = NULL;
254     }
255
256   if (priv->proxy)
257     g_object_unref (priv->proxy);
258
259   priv->proxy = TP_PROXY (connection);
260
261   tp_proxy_add_interface_by_id (priv->proxy, emp_iface_quark_debug ());
262
263   emp_cli_debug_call_get_messages (priv->proxy, -1,
264       debug_dialog_get_messages_cb, debug_dialog, NULL, NULL);
265
266   g_object_unref (dbus);
267   g_object_unref (mc);
268 }
269
270 static void
271 debug_dialog_list_connection_names_cb (const gchar * const *names,
272                                        gsize n,
273                                        const gchar * const *cms,
274                                        const gchar * const *protocols,
275                                        const GError *error,
276                                        gpointer user_data,
277                                        GObject *weak_object)
278 {
279   EmpathyDebugDialog *debug_dialog = (EmpathyDebugDialog *) user_data;
280   EmpathyDebugDialogPriv *priv = GET_PRIV (debug_dialog);
281   int i;
282
283   if (error != NULL)
284     {
285       DEBUG ("list_connection_names failed: %s", error->message);
286       return;
287     }
288
289   for (i = 0; cms[i] != NULL; i++)
290     gtk_combo_box_append_text (GTK_COMBO_BOX (priv->cm_chooser), cms[i]);
291
292   for (i = 0; names[i] != NULL; i++)
293     priv->bus_names = g_list_append (priv->bus_names, g_strdup (names[i]));
294
295   gtk_combo_box_set_active (GTK_COMBO_BOX (priv->cm_chooser), 0);
296
297   /* Fill treeview */
298   debug_dialog_cm_chooser_changed_cb (GTK_COMBO_BOX (priv->cm_chooser), debug_dialog);
299 }
300
301 static void
302 debug_dialog_fill_cm_chooser (EmpathyDebugDialog *debug_dialog)
303 {
304   TpDBusDaemon *dbus;
305   GError *error = NULL;
306
307   dbus = tp_dbus_daemon_dup (&error);
308
309   if (error != NULL)
310     {
311       DEBUG ("Failed to dup dbus daemon: %s", error->message);
312       g_error_free (error);
313       return;
314     }
315
316   tp_list_connection_names (dbus, debug_dialog_list_connection_names_cb,
317       debug_dialog, NULL, NULL);
318
319   g_object_unref (dbus);
320 }
321
322 static void
323 debug_dialog_pause_toggled_cb (GtkToggleToolButton *pause,
324                                EmpathyDebugDialog *debug_dialog)
325 {
326   EmpathyDebugDialogPriv *priv = GET_PRIV (debug_dialog);
327
328   priv->paused = gtk_toggle_tool_button_get_active (pause);
329
330   debug_dialog_set_enabled (debug_dialog, !priv->paused);
331 }
332
333 static GObject *
334 debug_dialog_constructor (GType type,
335                           guint n_construct_params,
336                           GObjectConstructParam *construct_params)
337 {
338   GObject *object;
339   EmpathyDebugDialogPriv *priv;
340   GtkWidget *vbox;
341   GtkWidget *toolbar;
342   GtkWidget *image;
343   GtkWidget *label;
344   GtkToolItem *item;
345   GtkCellRenderer *renderer;
346   GtkWidget *scrolled_win;
347
348   object = G_OBJECT_CLASS (empathy_debug_dialog_parent_class)->constructor
349     (type, n_construct_params, construct_params);
350   priv = GET_PRIV (object);
351
352   gtk_window_set_title (GTK_WINDOW (object), _("Debug Window"));
353   gtk_window_set_default_size (GTK_WINDOW (object), 800, 400);
354   gtk_window_set_transient_for (GTK_WINDOW (object), priv->parent);
355
356   vbox = GTK_DIALOG (object)->vbox;
357
358   toolbar = gtk_toolbar_new ();
359   gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH_HORIZ);
360   gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), TRUE);
361   gtk_toolbar_set_icon_size (GTK_TOOLBAR (toolbar), GTK_ICON_SIZE_SMALL_TOOLBAR);
362   gtk_widget_show (toolbar);
363
364   gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
365
366   /* CM */
367   priv->cm_chooser = gtk_combo_box_new_text ();
368   gtk_widget_show (priv->cm_chooser);
369
370   item = gtk_tool_item_new ();
371   gtk_widget_show (GTK_WIDGET (item));
372   gtk_container_add (GTK_CONTAINER (item), priv->cm_chooser);
373   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
374   debug_dialog_fill_cm_chooser (EMPATHY_DEBUG_DIALOG (object));
375   g_signal_connect (priv->cm_chooser, "changed",
376       G_CALLBACK (debug_dialog_cm_chooser_changed_cb), object);
377   gtk_widget_show (GTK_WIDGET (priv->cm_chooser));
378
379   item = gtk_separator_tool_item_new ();
380   gtk_widget_show (GTK_WIDGET (item));
381   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
382
383   /* Save */
384   item = gtk_tool_button_new_from_stock (GTK_STOCK_SAVE);
385   gtk_widget_show (GTK_WIDGET (item));
386   gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), TRUE);
387   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
388
389   /* Clear */
390   item = gtk_tool_button_new_from_stock (GTK_STOCK_CLEAR);
391   gtk_widget_show (GTK_WIDGET (item));
392   gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), TRUE);
393   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
394
395   item = gtk_separator_tool_item_new ();
396   gtk_widget_show (GTK_WIDGET (item));
397   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
398
399   /* Pause */
400   priv->paused = FALSE;
401   image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_MENU);
402   gtk_widget_show (image);
403   item = gtk_toggle_tool_button_new ();
404   gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (item), priv->paused);
405   g_signal_connect (item, "toggled", G_CALLBACK (debug_dialog_pause_toggled_cb),
406       object);
407   gtk_widget_show (GTK_WIDGET (item));
408   gtk_tool_item_set_is_important (GTK_TOOL_ITEM (item), TRUE);
409   gtk_tool_button_set_label (GTK_TOOL_BUTTON (item), _("Pause"));
410   gtk_tool_button_set_icon_widget (GTK_TOOL_BUTTON (item), image);
411   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
412
413   item = gtk_separator_tool_item_new ();
414   gtk_widget_show (GTK_WIDGET (item));
415   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
416
417   /* Level */
418   item = gtk_tool_item_new ();
419   gtk_widget_show (GTK_WIDGET (item));
420   label = gtk_label_new (_("Level "));
421   gtk_widget_show (label);
422   gtk_container_add (GTK_CONTAINER (item), label);
423   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
424
425   priv->filter = gtk_combo_box_new_text ();
426   gtk_widget_show (priv->filter);
427
428   item = gtk_tool_item_new ();
429   gtk_widget_show (GTK_WIDGET (item));
430   gtk_container_add (GTK_CONTAINER (item), priv->filter);
431   gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
432
433   gtk_combo_box_append_text (GTK_COMBO_BOX (priv->filter), _("All"));
434   gtk_combo_box_append_text (GTK_COMBO_BOX (priv->filter), _("Debug"));
435   gtk_combo_box_append_text (GTK_COMBO_BOX (priv->filter), _("Info"));
436   gtk_combo_box_append_text (GTK_COMBO_BOX (priv->filter), _("Message"));
437   gtk_combo_box_append_text (GTK_COMBO_BOX (priv->filter), _("Warning"));
438   gtk_combo_box_append_text (GTK_COMBO_BOX (priv->filter), _("Critical"));
439   gtk_combo_box_append_text (GTK_COMBO_BOX (priv->filter), _("Error"));
440
441   gtk_combo_box_set_active (GTK_COMBO_BOX (priv->filter), 0);
442   gtk_widget_show (GTK_WIDGET (priv->filter));
443
444   /* Debug treeview */
445   priv->view = gtk_tree_view_new ();
446   gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (priv->view), TRUE);
447
448   renderer = gtk_cell_renderer_text_new ();
449
450   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->view),
451       -1, _("Time"), renderer, "text", COL_TIMESTAMP, NULL);
452   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->view),
453       -1, _("Domain"), renderer, "text", COL_DOMAIN, NULL);
454   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->view),
455       -1, _("Category"), renderer, "text", COL_CATEGORY, NULL);
456   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->view),
457       -1, _("Level"), renderer, "text", COL_LEVEL, NULL);
458   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (priv->view),
459       -1, _("Message"), renderer, "text", COL_MESSAGE, NULL);
460
461   priv->store = gtk_list_store_new (NUM_COLS, G_TYPE_DOUBLE,
462       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
463   gtk_tree_view_set_model (GTK_TREE_VIEW (priv->view),
464       GTK_TREE_MODEL (priv->store));
465
466   /* Scrolled window */
467   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
468   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
469       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
470
471   gtk_widget_show (priv->view);
472   gtk_container_add (GTK_CONTAINER (scrolled_win), priv->view);
473
474   gtk_widget_show (scrolled_win);
475   gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
476
477   gtk_widget_show (GTK_WIDGET (object));
478
479   return object;
480 }
481
482 static void
483 empathy_debug_dialog_init (EmpathyDebugDialog *empathy_debug_dialog)
484 {
485   EmpathyDebugDialogPriv *priv =
486       G_TYPE_INSTANCE_GET_PRIVATE (empathy_debug_dialog,
487       EMPATHY_TYPE_DEBUG_DIALOG, EmpathyDebugDialogPriv);
488
489   empathy_debug_dialog->priv = priv;
490
491   priv->dispose_run = FALSE;
492 }
493
494 static void
495 debug_dialog_set_property (GObject *object,
496                            guint prop_id,
497                            const GValue *value,
498                            GParamSpec *pspec)
499 {
500   EmpathyDebugDialogPriv *priv = GET_PRIV (object);
501
502   switch (prop_id)
503     {
504       case PROP_PARENT:
505         priv->parent = GTK_WINDOW (g_value_dup_object (value));
506         break;
507       default:
508         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
509         break;
510     }
511 }
512
513 static void
514 debug_dialog_get_property (GObject *object,
515                            guint prop_id,
516                            GValue *value,
517                            GParamSpec *pspec)
518 {
519   EmpathyDebugDialogPriv *priv = GET_PRIV (object);
520
521   switch (prop_id)
522     {
523       case PROP_PARENT:
524         g_value_set_object (value, priv->parent);
525         break;
526       default:
527         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
528         break;
529     }
530 }
531
532 static void
533 debug_dialog_dispose (GObject *object)
534 {
535   EmpathyDebugDialog *selector = EMPATHY_DEBUG_DIALOG (object);
536   EmpathyDebugDialogPriv *priv = GET_PRIV (selector);
537
538   if (priv->dispose_run)
539     return;
540
541   priv->dispose_run = TRUE;
542
543   if (priv->parent)
544     g_object_unref (priv->parent);
545
546   if (priv->store)
547     g_object_unref (priv->store);
548
549   if (priv->proxy)
550     {
551       debug_dialog_set_enabled (EMPATHY_DEBUG_DIALOG (object), FALSE);
552       g_object_unref (priv->proxy);
553     }
554
555   if (priv->signal_connection)
556     tp_proxy_signal_connection_disconnect (priv->signal_connection);
557
558   if (priv->bus_names)
559     {
560       g_list_foreach (priv->bus_names, (GFunc) g_free, NULL);
561       g_list_free (priv->bus_names);
562     }
563
564   (G_OBJECT_CLASS (empathy_debug_dialog_parent_class)->dispose) (object);
565 }
566
567 static void
568 empathy_debug_dialog_class_init (EmpathyDebugDialogClass *klass)
569 {
570   GObjectClass *object_class = G_OBJECT_CLASS (klass);
571   object_class->constructor = debug_dialog_constructor;
572   object_class->dispose = debug_dialog_dispose;
573   object_class->set_property = debug_dialog_set_property;
574   object_class->get_property = debug_dialog_get_property;
575   g_type_class_add_private (klass, sizeof (EmpathyDebugDialogPriv));
576
577   g_object_class_install_property (object_class, PROP_PARENT,
578       g_param_spec_object ("parent", "parent", "parent",
579       GTK_TYPE_WINDOW, G_PARAM_CONSTRUCT_ONLY |
580       G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
581 }
582
583 /* public methods */
584
585 GtkWidget *
586 empathy_debug_dialog_new (GtkWindow *parent)
587 {
588   g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
589
590   return GTK_WIDGET (g_object_new (EMPATHY_TYPE_DEBUG_DIALOG,
591       "parent", parent, NULL));
592 }