assert that iter convert don't fail
[empathy-mirror.git] / libempathy-gtk / empathy-irc-network-chooser-dialog.c
blob001f1dfbda8e4ca22d422c250542352dbec49184
1 /*
2 * Copyright (C) 2007-2008 Guillaume Desmottes
3 * Copyright (C) 2010 Collabora Ltd.
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.
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.
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
19 * Authors: Guillaume Desmottes <gdesmott@gnome.org>
22 #include "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
28 #include <glib/gi18n-lib.h>
29 #include <gtk/gtk.h>
31 #include <libempathy/empathy-utils.h>
32 #include <libempathy/empathy-irc-network-manager.h>
34 #include "empathy-irc-network-dialog.h"
35 #include "empathy-ui-utils.h"
36 #include "empathy-live-search.h"
38 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT | EMPATHY_DEBUG_IRC
39 #include <libempathy/empathy-debug.h>
41 #include "empathy-irc-network-chooser-dialog.h"
43 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIrcNetworkChooserDialog)
45 enum {
46 PROP_SETTINGS = 1,
47 PROP_NETWORK
50 typedef struct {
51 EmpathyAccountSettings *settings;
52 EmpathyIrcNetwork *network;
54 EmpathyIrcNetworkManager *network_manager;
55 gboolean changed;
57 GtkWidget *treeview;
58 GtkListStore *store;
59 GtkTreeModelFilter *filter;
60 GtkWidget *search;
61 GtkWidget *select_button;
63 gulong search_sig;
64 } EmpathyIrcNetworkChooserDialogPriv;
66 enum {
67 COL_NETWORK_OBJ,
68 COL_NETWORK_NAME,
71 G_DEFINE_TYPE (EmpathyIrcNetworkChooserDialog, empathy_irc_network_chooser_dialog,
72 GTK_TYPE_DIALOG);
74 static void
75 empathy_irc_network_chooser_dialog_set_property (GObject *object,
76 guint prop_id,
77 const GValue *value,
78 GParamSpec *pspec)
80 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (object);
82 switch (prop_id)
84 case PROP_SETTINGS:
85 priv->settings = g_value_dup_object (value);
86 break;
87 case PROP_NETWORK:
88 priv->network = g_value_dup_object (value);
89 break;
90 default:
91 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
92 break;
96 static void
97 empathy_irc_network_chooser_dialog_get_property (GObject *object,
98 guint prop_id,
99 GValue *value,
100 GParamSpec *pspec)
102 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (object);
104 switch (prop_id)
106 case PROP_SETTINGS:
107 g_value_set_object (value, priv->settings);
108 break;
109 case PROP_NETWORK:
110 g_value_set_object (value, priv->network);
111 break;
112 default:
113 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
114 break;
118 /* The iter returned by *it is a priv->store iter (not a filter one) */
119 static EmpathyIrcNetwork *
120 dup_selected_network (EmpathyIrcNetworkChooserDialog *self,
121 GtkTreeIter *it)
123 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
124 EmpathyIrcNetwork *network;
125 GtkTreeSelection *selection;
126 GtkTreeIter iter;
127 GtkTreeModel *model;
129 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
130 if (!gtk_tree_selection_get_selected (selection, &model, &iter))
131 return NULL;
133 gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1);
134 g_assert (network != NULL);
136 if (it != NULL)
138 gtk_tree_model_filter_convert_iter_to_child_iter (priv->filter, it,
139 &iter);
142 return network;
145 static void
146 treeview_changed_cb (GtkTreeView *treeview,
147 EmpathyIrcNetworkChooserDialog *self)
149 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
150 EmpathyIrcNetwork *network;
152 network = dup_selected_network (self, NULL);
153 if (network == priv->network)
155 g_object_unref (network);
156 return;
159 tp_clear_object (&priv->network);
160 /* Transfer the reference */
161 priv->network = network;
163 priv->changed = TRUE;
166 /* Take a filter iterator as argument */
167 static void
168 scroll_to_iter (EmpathyIrcNetworkChooserDialog *self,
169 GtkTreeIter *filter_iter)
171 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
172 GtkTreePath *path;
174 path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->filter), filter_iter);
176 if (path != NULL)
178 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->treeview),
179 path, NULL, FALSE, 0, 0);
181 gtk_tree_path_free (path);
185 /* Take a filter iterator as argument */
186 static void
187 select_iter (EmpathyIrcNetworkChooserDialog *self,
188 GtkTreeIter *filter_iter,
189 gboolean emulate_changed)
191 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
192 GtkTreeSelection *selection;
193 GtkTreePath *path;
195 /* Select the network */
196 selection = gtk_tree_view_get_selection (
197 GTK_TREE_VIEW (priv->treeview));
199 gtk_tree_selection_select_iter (selection, filter_iter);
201 path = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->filter), filter_iter);
202 if (path != NULL)
204 gtk_tree_view_set_cursor (GTK_TREE_VIEW (priv->treeview), path,
205 NULL, FALSE);
207 gtk_tree_path_free (path);
210 /* Scroll to the selected network */
211 scroll_to_iter (self, filter_iter);
213 if (emulate_changed)
215 /* gtk_tree_selection_select_iter doesn't fire the 'cursor-changed' signal
216 * so we call the callback manually. */
217 treeview_changed_cb (GTK_TREE_VIEW (priv->treeview), self);
221 static void
222 fill_store (EmpathyIrcNetworkChooserDialog *self)
224 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
225 GSList *networks, *l;
227 networks = empathy_irc_network_manager_get_networks (
228 priv->network_manager);
230 for (l = networks; l != NULL; l = g_slist_next (l))
232 EmpathyIrcNetwork *network = l->data;
233 GtkTreeIter iter;
235 gtk_list_store_insert_with_values (priv->store, &iter, -1,
236 COL_NETWORK_OBJ, network,
237 COL_NETWORK_NAME, empathy_irc_network_get_name (network),
238 -1);
240 if (network == priv->network)
242 GtkTreeIter filter_iter;
244 /* Convert to a filter iter */
245 g_assert (gtk_tree_model_filter_convert_child_iter_to_iter (
246 priv->filter, &filter_iter, &iter));
248 select_iter (self, &filter_iter, FALSE);
251 g_object_unref (network);
254 g_slist_free (networks);
257 static void
258 irc_network_dialog_destroy_cb (GtkWidget *widget,
259 EmpathyIrcNetworkChooserDialog *self)
261 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
262 EmpathyIrcNetwork *network;
263 GtkTreeIter iter, filter_iter;
265 priv->changed = TRUE;
267 network = dup_selected_network (self, &iter);
268 if (network == NULL)
269 return;
271 /* name could be changed */
272 gtk_list_store_set (GTK_LIST_STORE (priv->store), &iter,
273 COL_NETWORK_NAME, empathy_irc_network_get_name (network), -1);
275 /* Convert to a filter iter */
276 g_assert (gtk_tree_model_filter_convert_child_iter_to_iter (priv->filter,
277 &filter_iter, &iter));
279 scroll_to_iter (self, &iter);
281 g_object_unref (network);
284 static void
285 display_irc_network_dialog (EmpathyIrcNetworkChooserDialog *self,
286 EmpathyIrcNetwork *network)
288 GtkWidget *dialog;
290 dialog = empathy_irc_network_dialog_show (network, NULL);
292 g_signal_connect (dialog, "destroy",
293 G_CALLBACK (irc_network_dialog_destroy_cb), self);
296 static void
297 edit_network (EmpathyIrcNetworkChooserDialog *self)
299 EmpathyIrcNetwork *network;
301 network = dup_selected_network (self, NULL);
302 if (network == NULL)
303 return;
305 display_irc_network_dialog (self, network);
307 g_object_unref (network);
310 static void
311 add_network (EmpathyIrcNetworkChooserDialog *self)
313 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
314 EmpathyIrcNetwork *network;
315 GtkTreeIter iter, filter_iter;
317 network = empathy_irc_network_new (_("New Network"));
318 empathy_irc_network_manager_add (priv->network_manager, network);
320 gtk_list_store_insert_with_values (priv->store, &iter, -1,
321 COL_NETWORK_OBJ, network,
322 COL_NETWORK_NAME, empathy_irc_network_get_name (network),
323 -1);
325 /* Convert to a filter iter */
326 g_assert (gtk_tree_model_filter_convert_child_iter_to_iter (priv->filter,
327 &filter_iter, &iter));
329 select_iter (self, &filter_iter, TRUE);
331 display_irc_network_dialog (self, network);
333 g_object_unref (network);
336 static void
337 remove_network (EmpathyIrcNetworkChooserDialog *self)
339 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
340 EmpathyIrcNetwork *network;
341 GtkTreeIter iter;
343 network = dup_selected_network (self, &iter);
344 if (network == NULL)
345 return;
347 DEBUG ("Remove network %s", empathy_irc_network_get_name (network));
349 gtk_list_store_remove (priv->store, &iter);
350 empathy_irc_network_manager_remove (priv->network_manager, network);
352 /* Select next network */
353 if (gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->store), &iter))
354 select_iter (self, &iter, TRUE);
356 g_object_unref (network);
359 static void
360 dialog_response_cb (GtkDialog *dialog,
361 gint response,
362 EmpathyIrcNetworkChooserDialog *self)
364 if (response == GTK_RESPONSE_OK)
365 add_network (self);
366 else if (response == GTK_RESPONSE_APPLY)
367 edit_network (self);
368 else if (response == GTK_RESPONSE_REJECT)
369 remove_network (self);
372 static gboolean
373 filter_visible_func (GtkTreeModel *model,
374 GtkTreeIter *iter,
375 gpointer user_data)
377 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (user_data);
378 EmpathyIrcNetwork *network;
379 gboolean visible;
381 gtk_tree_model_get (model, iter, COL_NETWORK_OBJ, &network, -1);
383 visible = empathy_live_search_match (EMPATHY_LIVE_SEARCH (priv->search),
384 empathy_irc_network_get_name (network));
386 g_object_unref (network);
387 return visible;
391 static void
392 search_text_notify_cb (EmpathyLiveSearch *search,
393 GParamSpec *pspec,
394 EmpathyIrcNetworkChooserDialog *self)
396 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
397 GtkTreeIter iter;
398 gboolean sensitive = FALSE;
400 gtk_tree_model_filter_refilter (priv->filter);
402 /* Select first matching network */
403 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->filter), &iter))
405 select_iter (self, &iter, TRUE);
406 sensitive = TRUE;
409 gtk_widget_set_sensitive (priv->select_button, sensitive);
412 static void
413 dialog_destroy_cb (GtkWidget *widget,
414 EmpathyIrcNetworkChooserDialog *self)
416 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
418 g_signal_handler_disconnect (priv->search, priv->search_sig);
421 static void
422 empathy_irc_network_chooser_dialog_constructed (GObject *object)
424 EmpathyIrcNetworkChooserDialog *self = (EmpathyIrcNetworkChooserDialog *) object;
425 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
426 GtkDialog *dialog = GTK_DIALOG (self);
427 GtkCellRenderer *renderer;
428 GtkWidget *vbox;
429 GtkTreeViewColumn *column;
430 GtkWidget *scroll;
432 g_assert (priv->settings != NULL);
434 gtk_window_set_title (GTK_WINDOW (self), _("Choose an IRC network"));
436 /* Create store and treeview */
437 priv->store = gtk_list_store_new (2, G_TYPE_OBJECT, G_TYPE_STRING);
439 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->store),
440 COL_NETWORK_NAME,
441 GTK_SORT_ASCENDING);
443 priv->treeview = gtk_tree_view_new ();
444 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->treeview), FALSE);
445 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (priv->treeview), FALSE);
447 column = gtk_tree_view_column_new ();
448 gtk_tree_view_append_column (GTK_TREE_VIEW (priv->treeview), column);
450 renderer = gtk_cell_renderer_text_new ();
451 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, TRUE);
452 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (column),
453 renderer,
454 "text", COL_NETWORK_NAME,
455 NULL);
457 /* add the treeview in a GtkScrolledWindow */
458 vbox = gtk_dialog_get_content_area (dialog);
460 scroll = gtk_scrolled_window_new (NULL, NULL);
461 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
462 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
464 gtk_container_add (GTK_CONTAINER (scroll), priv->treeview);
465 gtk_box_pack_start (GTK_BOX (vbox), scroll, TRUE, TRUE, 6);
467 /* Live search */
468 priv->search = empathy_live_search_new (priv->treeview);
470 gtk_box_pack_start (GTK_BOX (vbox), priv->search, FALSE, TRUE, 0);
472 priv->filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (
473 GTK_TREE_MODEL (priv->store), NULL));
474 gtk_tree_model_filter_set_visible_func (priv->filter,
475 filter_visible_func, self, NULL);
477 gtk_tree_view_set_model (GTK_TREE_VIEW (priv->treeview),
478 GTK_TREE_MODEL (priv->filter));
480 priv->search_sig = g_signal_connect (priv->search, "notify::text",
481 G_CALLBACK (search_text_notify_cb), self);
483 /* Add buttons */
484 gtk_dialog_add_buttons (dialog,
485 GTK_STOCK_ADD, GTK_RESPONSE_OK,
486 GTK_STOCK_EDIT, GTK_RESPONSE_APPLY,
487 GTK_STOCK_REMOVE, GTK_RESPONSE_REJECT,
488 NULL);
490 priv->select_button = gtk_dialog_add_button (dialog, _("Select"),
491 GTK_RESPONSE_CLOSE);
493 fill_store (self);
495 g_signal_connect (priv->treeview, "cursor-changed",
496 G_CALLBACK (treeview_changed_cb), self);
498 g_signal_connect (self, "response",
499 G_CALLBACK (dialog_response_cb), self);
500 g_signal_connect (self, "destroy",
501 G_CALLBACK (dialog_destroy_cb), self);
503 /* Request a side ensuring to display at least some networks */
504 gtk_widget_set_size_request (GTK_WIDGET (self), -1, 300);
507 static void
508 empathy_irc_network_chooser_dialog_dispose (GObject *object)
510 EmpathyIrcNetworkManager *self = (EmpathyIrcNetworkManager *) object;
511 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
513 tp_clear_object (&priv->settings);
514 tp_clear_object (&priv->network);
515 tp_clear_object (&priv->network_manager);
516 tp_clear_object (&priv->store);
517 tp_clear_object (&priv->filter);
519 if (G_OBJECT_CLASS (empathy_irc_network_chooser_dialog_parent_class)->dispose)
520 G_OBJECT_CLASS (empathy_irc_network_chooser_dialog_parent_class)->dispose (object);
523 static void
524 empathy_irc_network_chooser_dialog_class_init (EmpathyIrcNetworkChooserDialogClass *klass)
526 GObjectClass *object_class = G_OBJECT_CLASS (klass);
528 object_class->get_property = empathy_irc_network_chooser_dialog_get_property;
529 object_class->set_property = empathy_irc_network_chooser_dialog_set_property;
530 object_class->constructed = empathy_irc_network_chooser_dialog_constructed;
531 object_class->dispose = empathy_irc_network_chooser_dialog_dispose;
533 g_object_class_install_property (object_class, PROP_SETTINGS,
534 g_param_spec_object ("settings",
535 "Settings",
536 "The EmpathyAccountSettings to show and edit",
537 EMPATHY_TYPE_ACCOUNT_SETTINGS,
538 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
540 g_object_class_install_property (object_class, PROP_NETWORK,
541 g_param_spec_object ("network",
542 "Network",
543 "The EmpathyIrcNetwork selected in the treeview",
544 EMPATHY_TYPE_IRC_NETWORK,
545 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
547 g_type_class_add_private (object_class,
548 sizeof (EmpathyIrcNetworkChooserDialogPriv));
551 static void
552 empathy_irc_network_chooser_dialog_init (EmpathyIrcNetworkChooserDialog *self)
554 EmpathyIrcNetworkChooserDialogPriv *priv;
556 priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
557 EMPATHY_TYPE_IRC_NETWORK_CHOOSER_DIALOG, EmpathyIrcNetworkChooserDialogPriv);
558 self->priv = priv;
560 priv->network_manager = empathy_irc_network_manager_dup_default ();
563 GtkWidget *
564 empathy_irc_network_chooser_dialog_new (EmpathyAccountSettings *settings,
565 EmpathyIrcNetwork *network)
567 return g_object_new (EMPATHY_TYPE_IRC_NETWORK_CHOOSER_DIALOG,
568 "settings", settings,
569 "network", network,
570 NULL);
573 EmpathyIrcNetwork *
574 empathy_irc_network_chooser_dialog_get_network (
575 EmpathyIrcNetworkChooserDialog *self)
577 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
579 return priv->network;
582 gboolean
583 empathy_irc_network_chooser_dialog_get_changed (
584 EmpathyIrcNetworkChooserDialog *self)
586 EmpathyIrcNetworkChooserDialogPriv *priv = GET_PRIV (self);
588 return priv->changed;