Mercurial > pidgin
annotate src/gtkroomlist.c @ 12767:53218d758ba9
[gaim-migrate @ 15114]
Make the dns lookup for udp connecting asynchronous. Thomas pointed out that it should be instantaneous anyway because the SRV lookup that has just been done, but this'll avoid blocking if the SRV lookup failed or something.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Sun, 08 Jan 2006 22:09:28 +0000 |
parents | e856f985a0b9 |
children | 82fd52867ffc |
rev | line source |
---|---|
8113 | 1 /** |
8939 | 2 * @file gtkroomlist.c GTK+ Room List UI |
8113 | 3 * @ingroup gtkui |
4 * | |
5 * gaim | |
6 * | |
8146 | 7 * Gaim is the legal property of its developers, whose names are too numerous |
8 * to list here. Please refer to the COPYRIGHT file distributed with this | |
9 * source distribution. | |
8113 | 10 * |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 */ | |
25 | |
9791 | 26 #include "internal.h" |
27 #include "gtkgaim.h" | |
8113 | 28 #include "gtkutils.h" |
10299 | 29 #include "gtkstock.h" |
8113 | 30 #include "debug.h" |
31 #include "account.h" | |
32 #include "connection.h" | |
33 #include "notify.h" | |
34 | |
35 #include "gtkroomlist.h" | |
36 | |
37 typedef struct _GaimGtkRoomlist { | |
38 GaimGtkRoomlistDialog *dialog; | |
39 GtkTreeStore *model; | |
40 GtkWidget *tree; | |
41 GHashTable *cats; /**< Meow. */ | |
42 gint num_rooms, total_rooms; | |
43 } GaimGtkRoomlist; | |
44 | |
45 struct _GaimGtkRoomlistDialog { | |
46 GtkWidget *window; | |
47 GtkWidget *account_widget; | |
48 GtkWidget *progress; | |
49 GtkWidget *sw; | |
50 | |
8199 | 51 GtkWidget *stop_button; |
8113 | 52 GtkWidget *list_button; |
8199 | 53 GtkWidget *join_button; |
8113 | 54 GtkWidget *close_button; |
55 | |
56 GaimAccount *account; | |
57 GaimRoomlist *roomlist; | |
8230 | 58 |
59 gboolean pg_needs_pulse; | |
60 gboolean pg_to_active; | |
61 guint pg_update_to; | |
8113 | 62 }; |
63 | |
64 enum { | |
65 NAME_COLUMN = 0, | |
66 ROOM_COLUMN, | |
67 NUM_OF_COLUMNS, | |
68 }; | |
69 | |
70 static GList *roomlists = NULL; | |
71 | |
72 static gint delete_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d) | |
73 { | |
74 GaimGtkRoomlistDialog *dialog; | |
75 | |
76 dialog = (GaimGtkRoomlistDialog *) d; | |
77 | |
8199 | 78 if (dialog->roomlist && gaim_roomlist_get_in_progress(dialog->roomlist)) |
79 gaim_roomlist_cancel_get_list(dialog->roomlist); | |
80 | |
8230 | 81 if (dialog->roomlist) { |
82 if (dialog->pg_to_active) { | |
8287
ef881489396e
[gaim-migrate @ 9011]
Christian Hammond <chipx86@chipx86.com>
parents:
8230
diff
changeset
|
83 gaim_timeout_remove(dialog->pg_update_to); |
8230 | 84 dialog->pg_to_active = FALSE; |
85 /* yes, that's right, unref it twice. */ | |
86 gaim_roomlist_unref(dialog->roomlist); | |
87 } | |
88 } | |
89 | |
8113 | 90 /* free stuff here */ |
91 if (dialog->roomlist) | |
92 gaim_roomlist_unref(dialog->roomlist); | |
93 g_free(dialog); | |
94 | |
95 return FALSE; | |
96 } | |
97 | |
98 static void dialog_select_account_cb(GObject *w, GaimAccount *account, | |
99 GaimGtkRoomlistDialog *dialog) | |
100 { | |
101 dialog->account = account; | |
102 } | |
103 | |
104 static void list_button_cb(GtkButton *button, GaimGtkRoomlistDialog *dialog) | |
105 { | |
106 GaimConnection *gc; | |
107 GaimGtkRoomlist *rl; | |
108 | |
109 gc = gaim_account_get_connection(dialog->account); | |
110 if (!gc) | |
111 return; | |
112 | |
8199 | 113 if (dialog->roomlist != NULL) { |
114 rl = dialog->roomlist->ui_data; | |
115 gtk_widget_destroy(rl->tree); | |
116 gaim_roomlist_unref(dialog->roomlist); | |
117 } | |
118 | |
8113 | 119 dialog->roomlist = gaim_roomlist_get_list(gc); |
9159 | 120 if (!dialog->roomlist) |
121 return; | |
8113 | 122 gaim_roomlist_ref(dialog->roomlist); |
123 rl = dialog->roomlist->ui_data; | |
124 rl->dialog = dialog; | |
8199 | 125 |
8113 | 126 if (dialog->account_widget) |
127 gtk_widget_set_sensitive(dialog->account_widget, FALSE); | |
8199 | 128 |
129 gtk_container_add(GTK_CONTAINER(dialog->sw), rl->tree); | |
130 | |
131 gtk_widget_set_sensitive(dialog->stop_button, TRUE); | |
8113 | 132 gtk_widget_set_sensitive(dialog->list_button, FALSE); |
8199 | 133 gtk_widget_set_sensitive(dialog->join_button, FALSE); |
8113 | 134 } |
135 | |
136 static void stop_button_cb(GtkButton *button, GaimGtkRoomlistDialog *dialog) | |
137 { | |
138 gaim_roomlist_cancel_get_list(dialog->roomlist); | |
8199 | 139 |
140 if (dialog->account_widget) | |
141 gtk_widget_set_sensitive(dialog->account_widget, TRUE); | |
142 | |
143 gtk_widget_set_sensitive(dialog->stop_button, FALSE); | |
144 gtk_widget_set_sensitive(dialog->list_button, TRUE); | |
145 gtk_widget_set_sensitive(dialog->join_button, FALSE); | |
8113 | 146 } |
147 | |
148 static void close_button_cb(GtkButton *button, GaimGtkRoomlistDialog *dialog) | |
149 { | |
150 GtkWidget *window = dialog->window; | |
151 | |
152 delete_win_cb(NULL, NULL, dialog); | |
153 gtk_widget_destroy(window); | |
154 } | |
155 | |
156 struct _menu_cb_info { | |
157 GaimRoomlist *list; | |
158 GaimRoomlistRoom *room; | |
159 }; | |
160 | |
8199 | 161 static void |
8377 | 162 join_button_data_change_cb(gpointer data) { |
163 g_free(data); | |
164 } | |
165 | |
166 static void | |
8199 | 167 selection_changed_cb(GtkTreeSelection *selection, GaimGtkRoomlist *grl) { |
168 GtkTreeIter iter; | |
12600
e856f985a0b9
[gaim-migrate @ 14934]
Richard Laager <rlaager@wiktel.com>
parents:
12286
diff
changeset
|
169 GValue val; |
8199 | 170 GaimRoomlistRoom *room; |
171 static struct _menu_cb_info *info; | |
172 GaimGtkRoomlistDialog *dialog; | |
173 | |
174 dialog = grl->dialog; | |
175 | |
176 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) { | |
12600
e856f985a0b9
[gaim-migrate @ 14934]
Richard Laager <rlaager@wiktel.com>
parents:
12286
diff
changeset
|
177 val.g_type = 0; |
8199 | 178 gtk_tree_model_get_value(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &val); |
179 room = g_value_get_pointer(&val); | |
180 if (!room || !(room->type & GAIM_ROOMLIST_ROOMTYPE_ROOM)) { | |
181 gtk_widget_set_sensitive(dialog->join_button, FALSE); | |
182 return; | |
183 } | |
184 | |
185 info = g_new0(struct _menu_cb_info, 1); | |
186 info->list = dialog->roomlist; | |
187 info->room = room; | |
188 | |
8377 | 189 g_object_set_data_full(G_OBJECT(dialog->join_button), "room-info", |
190 info, join_button_data_change_cb); | |
8199 | 191 |
192 gtk_widget_set_sensitive(dialog->join_button, TRUE); | |
193 } else { | |
194 gtk_widget_set_sensitive(dialog->join_button, FALSE); | |
195 } | |
196 } | |
197 | |
8113 | 198 static void do_join_cb(GtkWidget *w, struct _menu_cb_info *info) |
199 { | |
8199 | 200 gaim_roomlist_room_join(info->list, info->room); |
201 } | |
8113 | 202 |
8199 | 203 static void join_button_cb(GtkButton *button, GaimGtkRoomlistDialog *dialog) |
204 { | |
205 GaimRoomlist *rl = dialog->roomlist; | |
206 GaimGtkRoomlist *grl = rl->ui_data; | |
207 struct _menu_cb_info *info; | |
208 | |
209 info = (struct _menu_cb_info*)g_object_get_data(G_OBJECT(button), "room-info"); | |
210 | |
8377 | 211 if(info != NULL) |
212 do_join_cb(grl->tree, info); | |
8113 | 213 } |
214 | |
215 static void row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *arg2, | |
216 GaimRoomlist *list) | |
217 { | |
218 GaimGtkRoomlist *grl = list->ui_data; | |
219 GtkTreeIter iter; | |
220 GaimRoomlistRoom *room; | |
12600
e856f985a0b9
[gaim-migrate @ 14934]
Richard Laager <rlaager@wiktel.com>
parents:
12286
diff
changeset
|
221 GValue val; |
8113 | 222 struct _menu_cb_info info; |
223 | |
224 gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path); | |
12600
e856f985a0b9
[gaim-migrate @ 14934]
Richard Laager <rlaager@wiktel.com>
parents:
12286
diff
changeset
|
225 val.g_type = 0; |
8113 | 226 gtk_tree_model_get_value(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &val); |
227 room = g_value_get_pointer(&val); | |
228 if (!room || !(room->type & GAIM_ROOMLIST_ROOMTYPE_ROOM)) | |
229 return; | |
230 | |
231 info.list = list; | |
232 info.room = room; | |
233 | |
234 do_join_cb(GTK_WIDGET(tv), &info); | |
235 } | |
236 | |
237 static gboolean room_click_cb(GtkWidget *tv, GdkEventButton *event, GaimRoomlist *list) | |
238 { | |
239 GtkTreePath *path; | |
240 GaimGtkRoomlist *grl = list->ui_data; | |
12600
e856f985a0b9
[gaim-migrate @ 14934]
Richard Laager <rlaager@wiktel.com>
parents:
12286
diff
changeset
|
241 GValue val; |
8113 | 242 GaimRoomlistRoom *room; |
243 GtkTreeIter iter; | |
244 GtkWidget *menu; | |
245 static struct _menu_cb_info info; /* XXX? */ | |
246 | |
247 if (event->button != 3 || event->type != GDK_BUTTON_PRESS) | |
248 return FALSE; | |
249 | |
250 /* Here we figure out which room was clicked */ | |
251 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL)) | |
252 return FALSE; | |
253 gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path); | |
254 gtk_tree_path_free(path); | |
12600
e856f985a0b9
[gaim-migrate @ 14934]
Richard Laager <rlaager@wiktel.com>
parents:
12286
diff
changeset
|
255 val.g_type = 0; |
8113 | 256 gtk_tree_model_get_value (GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &val); |
257 room = g_value_get_pointer(&val); | |
258 | |
259 if (!room || !(room->type & GAIM_ROOMLIST_ROOMTYPE_ROOM)) | |
260 return FALSE; | |
261 | |
262 info.list = list; | |
263 info.room = room; | |
264 | |
265 | |
266 menu = gtk_menu_new(); | |
267 gaim_new_item_from_stock(menu, _("_Join"), GAIM_STOCK_CHAT, | |
268 G_CALLBACK(do_join_cb), &info, 0, 0, NULL); | |
269 | |
270 | |
271 gtk_widget_show_all(menu); | |
272 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time); | |
273 | |
274 return FALSE; | |
275 } | |
276 | |
277 static void row_expanded_cb(GtkTreeView *treeview, GtkTreeIter *arg1, GtkTreePath *arg2, gpointer user_data) | |
278 { | |
279 GaimRoomlist *list = user_data; | |
8584 | 280 GaimRoomlistRoom *category; |
12600
e856f985a0b9
[gaim-migrate @ 14934]
Richard Laager <rlaager@wiktel.com>
parents:
12286
diff
changeset
|
281 GValue val; |
8113 | 282 |
12600
e856f985a0b9
[gaim-migrate @ 14934]
Richard Laager <rlaager@wiktel.com>
parents:
12286
diff
changeset
|
283 val.g_type = 0; |
8113 | 284 gtk_tree_model_get_value(gtk_tree_view_get_model(treeview), arg1, ROOM_COLUMN, &val); |
8584 | 285 category = g_value_get_pointer(&val); |
8113 | 286 |
8584 | 287 if (!category->expanded_once) { |
288 gaim_roomlist_expand_category(list, category); | |
289 category->expanded_once = TRUE; | |
8113 | 290 } |
291 } | |
292 | |
8939 | 293 static gboolean account_filter_func(GaimAccount *account) |
8113 | 294 { |
8939 | 295 GaimConnection *gc = gaim_account_get_connection(account); |
296 GaimPluginProtocolInfo *prpl_info = NULL; | |
297 | |
298 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
299 | |
300 return (prpl_info->roomlist_get_list != NULL); | |
301 } | |
302 | |
303 gboolean | |
304 gaim_gtk_roomlist_is_showable() | |
305 { | |
306 GList *c; | |
8113 | 307 GaimConnection *gc; |
308 | |
8939 | 309 for (c = gaim_connections_get_all(); c != NULL; c = c->next) { |
310 gc = c->data; | |
311 | |
312 if (account_filter_func(gaim_connection_get_account(gc))) | |
313 return TRUE; | |
314 } | |
315 | |
316 return FALSE; | |
8113 | 317 } |
318 | |
319 GaimGtkRoomlistDialog *gaim_gtk_roomlist_dialog_new_with_account(GaimAccount *account) | |
320 { | |
321 GaimGtkRoomlistDialog *dialog; | |
322 GtkWidget *window; | |
8199 | 323 GtkWidget *vbox; |
324 GtkWidget *vbox2; | |
8113 | 325 GtkWidget *account_hbox; |
326 GtkWidget *bbox; | |
327 GtkWidget *label; | |
328 | |
329 dialog = g_new0(GaimGtkRoomlistDialog, 1); | |
8937 | 330 dialog->account = account; |
8113 | 331 |
332 /* Create the window. */ | |
333 dialog->window = window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
334 gtk_window_set_role(GTK_WINDOW(window), "room list"); | |
335 gtk_window_set_title(GTK_WINDOW(window), _("Room List")); | |
336 | |
11243 | 337 gtk_container_set_border_width(GTK_CONTAINER(window), GAIM_HIG_BORDER); |
8113 | 338 |
339 g_signal_connect(G_OBJECT(window), "delete_event", | |
340 G_CALLBACK(delete_win_cb), dialog); | |
341 | |
342 /* Create the parent vbox for everything. */ | |
11243 | 343 vbox = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); |
8199 | 344 gtk_container_add(GTK_CONTAINER(window), vbox); |
345 gtk_widget_show(vbox); | |
8113 | 346 |
11243 | 347 vbox2 = gtk_vbox_new(FALSE, GAIM_HIG_BORDER); |
8199 | 348 gtk_container_add(GTK_CONTAINER(vbox), vbox2); |
8113 | 349 gtk_widget_show(vbox2); |
350 | |
8352 | 351 /* accounts dropdown list */ |
11243 | 352 account_hbox = gtk_hbox_new(FALSE, GAIM_HIG_BOX_SPACE); |
8352 | 353 gtk_box_pack_start(GTK_BOX(vbox2), account_hbox, FALSE, FALSE, 0); |
354 gtk_widget_show(account_hbox); | |
8113 | 355 |
8352 | 356 label = gtk_label_new(NULL); |
8425
6d8ec773a485
[gaim-migrate @ 9155]
Christian Hammond <chipx86@chipx86.com>
parents:
8377
diff
changeset
|
357 gtk_box_pack_start(GTK_BOX(account_hbox), label, FALSE, FALSE, 0); |
8352 | 358 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Account:")); |
8425
6d8ec773a485
[gaim-migrate @ 9155]
Christian Hammond <chipx86@chipx86.com>
parents:
8377
diff
changeset
|
359 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |
8352 | 360 gtk_widget_show(label); |
8113 | 361 |
8352 | 362 dialog->account_widget = gaim_gtk_account_option_menu_new(dialog->account, FALSE, |
8939 | 363 G_CALLBACK(dialog_select_account_cb), account_filter_func, dialog); |
8199 | 364 |
9067 | 365 if (!dialog->account) /* this is normally null, and we normally don't care what the first selected item is */ |
366 dialog->account = gaim_gtk_account_option_menu_get_selected(dialog->account_widget); | |
367 | |
8352 | 368 gtk_box_pack_start(GTK_BOX(account_hbox), dialog->account_widget, TRUE, TRUE, 0); |
369 gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_WIDGET(dialog->account_widget)); | |
370 gtk_widget_show(dialog->account_widget); | |
8113 | 371 |
8199 | 372 /* scrolled window */ |
8113 | 373 dialog->sw = gtk_scrolled_window_new(NULL, NULL); |
374 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(dialog->sw), | |
375 GTK_SHADOW_IN); | |
376 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dialog->sw), | |
377 GTK_POLICY_AUTOMATIC, | |
378 GTK_POLICY_AUTOMATIC); | |
8199 | 379 gtk_box_pack_start(GTK_BOX(vbox2), dialog->sw, TRUE, TRUE, 0); |
380 gtk_widget_set_size_request(dialog->sw, -1, 250); | |
8113 | 381 gtk_widget_show(dialog->sw); |
382 | |
8199 | 383 /* progress bar */ |
384 dialog->progress = gtk_progress_bar_new(); | |
385 gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(dialog->progress), 0.1); | |
386 gtk_box_pack_start(GTK_BOX(vbox2), dialog->progress, FALSE, FALSE, 0); | |
387 gtk_widget_show(dialog->progress); | |
388 | |
389 | |
390 /* button box */ | |
391 bbox = gtk_hbutton_box_new(); | |
11243 | 392 gtk_box_set_spacing(GTK_BOX(bbox), GAIM_HIG_BOX_SPACE); |
8199 | 393 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); |
394 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); | |
395 gtk_widget_show(bbox); | |
396 | |
397 /* stop button */ | |
398 dialog->stop_button = gtk_button_new_from_stock(GTK_STOCK_STOP); | |
399 gtk_box_pack_start(GTK_BOX(bbox), dialog->stop_button, FALSE, FALSE, 0); | |
400 g_signal_connect(G_OBJECT(dialog->stop_button), "clicked", | |
401 G_CALLBACK(stop_button_cb), dialog); | |
402 gtk_widget_set_sensitive(dialog->stop_button, FALSE); | |
403 gtk_widget_show(dialog->stop_button); | |
404 | |
405 /* list button */ | |
406 dialog->list_button = gtk_button_new_with_mnemonic(_("_Get List")); | |
407 gtk_box_pack_start(GTK_BOX(bbox), dialog->list_button, FALSE, FALSE, 0); | |
408 g_signal_connect(G_OBJECT(dialog->list_button), "clicked", | |
409 G_CALLBACK(list_button_cb), dialog); | |
410 gtk_widget_show(dialog->list_button); | |
411 | |
412 /* join button */ | |
413 dialog->join_button = gaim_pixbuf_button_from_stock(_("_Join"), GAIM_STOCK_CHAT, | |
414 GAIM_BUTTON_HORIZONTAL); | |
415 gtk_box_pack_start(GTK_BOX(bbox), dialog->join_button, FALSE, FALSE, 0); | |
416 g_signal_connect(G_OBJECT(dialog->join_button), "clicked", | |
417 G_CALLBACK(join_button_cb), dialog); | |
418 gtk_widget_set_sensitive(dialog->join_button, FALSE); | |
419 gtk_widget_show(dialog->join_button); | |
420 | |
421 /* close button */ | |
422 dialog->close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); | |
423 gtk_box_pack_start(GTK_BOX(bbox), dialog->close_button, FALSE, FALSE, 0); | |
424 g_signal_connect(G_OBJECT(dialog->close_button), "clicked", | |
425 G_CALLBACK(close_button_cb), dialog); | |
426 gtk_widget_show(dialog->close_button); | |
427 | |
428 /* show the dialog window and return the dialog */ | |
429 gtk_widget_show(dialog->window); | |
430 | |
8113 | 431 return dialog; |
432 } | |
433 | |
434 GaimGtkRoomlistDialog *gaim_gtk_roomlist_dialog_new(void) | |
435 { | |
436 return gaim_gtk_roomlist_dialog_new_with_account(NULL); | |
437 } | |
438 | |
8352 | 439 static void gaim_gtk_roomlist_dialog_show_with_account(GaimAccount *account) |
440 { | |
441 GaimGtkRoomlistDialog *dialog; | |
442 | |
443 dialog = gaim_gtk_roomlist_dialog_new_with_account(account); | |
444 if (!dialog) | |
445 return; | |
446 | |
447 list_button_cb(GTK_BUTTON(dialog->list_button), dialog); | |
448 } | |
449 | |
8113 | 450 void gaim_gtk_roomlist_dialog_show(void) |
451 { | |
452 gaim_gtk_roomlist_dialog_new(); | |
453 } | |
454 | |
455 static void gaim_gtk_roomlist_new(GaimRoomlist *list) | |
456 { | |
457 GaimGtkRoomlist *rl; | |
458 | |
459 rl = g_new0(GaimGtkRoomlist, 1); | |
460 | |
461 list->ui_data = rl; | |
462 | |
463 rl->cats = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)gtk_tree_row_reference_free); | |
464 | |
465 roomlists = g_list_append(roomlists, list); | |
466 } | |
467 | |
468 static void int_cell_data_func(GtkTreeViewColumn *col, GtkCellRenderer *renderer, | |
469 GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) | |
470 { | |
471 gchar buf[16]; | |
472 int myint; | |
473 | |
474 gtk_tree_model_get(model, iter, GPOINTER_TO_INT(user_data), &myint, -1); | |
475 | |
476 if (myint) | |
477 g_snprintf(buf, sizeof(buf), "%d", myint); | |
478 else | |
479 buf[0] = '\0'; | |
480 | |
481 g_object_set(renderer, "text", buf, NULL); | |
482 } | |
483 | |
484 /* this sorts backwards on purpose, so that clicking name sorts a-z, while clicking users sorts | |
485 infinity-0. you can still click again to reverse it on any of them. */ | |
486 static gint int_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) | |
487 { | |
488 int c, d; | |
489 | |
490 c = d = 0; | |
491 | |
492 gtk_tree_model_get(model, a, GPOINTER_TO_INT(user_data), &c, -1); | |
493 gtk_tree_model_get(model, b, GPOINTER_TO_INT(user_data), &d, -1); | |
494 | |
495 if (c == d) | |
496 return 0; | |
497 else if (c > d) | |
498 return -1; | |
499 else | |
500 return 1; | |
501 } | |
502 | |
11490 | 503 static gboolean |
504 _search_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data) | |
505 { | |
506 gboolean result; | |
507 gchar *name, *fold, *fkey; | |
508 | |
509 gtk_tree_model_get(model, iter, column, &name, -1); | |
510 fold = g_utf8_casefold(name, -1); | |
511 fkey = g_utf8_casefold(key, -1); | |
512 | |
513 result = (g_strstr_len(fold, strlen(fold), fkey) == NULL); | |
514 | |
515 g_free(fold); | |
516 g_free(fkey); | |
517 g_free(name); | |
518 | |
519 return result; | |
520 } | |
521 | |
8113 | 522 static void gaim_gtk_roomlist_set_fields(GaimRoomlist *list, GList *fields) |
523 { | |
524 GaimGtkRoomlist *grl = list->ui_data; | |
525 gint columns = NUM_OF_COLUMNS; | |
526 int j; | |
527 GtkTreeStore *model; | |
528 GtkWidget *tree; | |
529 GtkCellRenderer *renderer; | |
530 GtkTreeViewColumn *column; | |
8199 | 531 GtkTreeSelection *selection; |
8113 | 532 GList *l; |
533 GType *types; | |
534 | |
535 g_return_if_fail(grl != NULL); | |
536 | |
537 columns += g_list_length(fields); | |
538 types = g_new(GType, columns); | |
539 | |
540 types[NAME_COLUMN] = G_TYPE_STRING; | |
541 types[ROOM_COLUMN] = G_TYPE_POINTER; | |
542 | |
543 for (j = NUM_OF_COLUMNS, l = fields; l; l = l->next, j++) { | |
544 GaimRoomlistField *f = l->data; | |
545 | |
546 switch (f->type) { | |
547 case GAIM_ROOMLIST_FIELD_BOOL: | |
548 types[j] = G_TYPE_BOOLEAN; | |
549 break; | |
550 case GAIM_ROOMLIST_FIELD_INT: | |
551 types[j] = G_TYPE_INT; | |
552 break; | |
553 case GAIM_ROOMLIST_FIELD_STRING: | |
554 types[j] = G_TYPE_STRING; | |
555 break; | |
556 } | |
557 } | |
558 | |
559 model = gtk_tree_store_newv(columns, types); | |
560 g_free(types); | |
561 | |
562 tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); | |
563 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE); | |
564 | |
8199 | 565 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)); |
566 g_signal_connect(G_OBJECT(selection), "changed", | |
567 G_CALLBACK(selection_changed_cb), grl); | |
568 | |
8113 | 569 g_object_unref(model); |
570 | |
571 grl->model = model; | |
572 grl->tree = tree; | |
573 gtk_widget_show(grl->tree); | |
574 | |
575 renderer = gtk_cell_renderer_text_new(); | |
576 column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, | |
577 "text", NAME_COLUMN, NULL); | |
578 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column), | |
579 GTK_TREE_VIEW_COLUMN_GROW_ONLY); | |
580 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); | |
581 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), NAME_COLUMN); | |
582 gtk_tree_view_column_set_reorderable(GTK_TREE_VIEW_COLUMN(column), TRUE); | |
583 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); | |
584 | |
585 for (j = NUM_OF_COLUMNS, l = fields; l; l = l->next, j++) { | |
586 GaimRoomlistField *f = l->data; | |
587 | |
588 if (f->hidden) | |
589 continue; | |
590 | |
591 renderer = gtk_cell_renderer_text_new(); | |
592 column = gtk_tree_view_column_new_with_attributes(f->label, renderer, | |
593 "text", j, NULL); | |
594 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column), | |
595 GTK_TREE_VIEW_COLUMN_GROW_ONLY); | |
596 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); | |
597 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), j); | |
598 gtk_tree_view_column_set_reorderable(GTK_TREE_VIEW_COLUMN(column), TRUE); | |
599 if (f->type == GAIM_ROOMLIST_FIELD_INT) { | |
600 gtk_tree_view_column_set_cell_data_func(column, renderer, int_cell_data_func, | |
601 GINT_TO_POINTER(j), NULL); | |
602 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), j, int_sort_func, | |
603 GINT_TO_POINTER(j), NULL); | |
604 } | |
605 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); | |
606 } | |
607 | |
608 g_signal_connect(G_OBJECT(tree), "button-press-event", G_CALLBACK(room_click_cb), list); | |
609 g_signal_connect(G_OBJECT(tree), "row-expanded", G_CALLBACK(row_expanded_cb), list); | |
610 g_signal_connect(G_OBJECT(tree), "row-activated", G_CALLBACK(row_activated_cb), list); | |
11490 | 611 |
612 /* Enable CTRL+F searching */ | |
613 gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree), NAME_COLUMN); | |
614 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(tree), _search_func, NULL, NULL); | |
615 | |
8113 | 616 } |
617 | |
8230 | 618 static gboolean gaim_gtk_progress_bar_pulse(gpointer data) |
619 { | |
620 GaimRoomlist *list = data; | |
621 GaimGtkRoomlist *rl = list->ui_data; | |
622 | |
623 if (!rl || !rl->dialog || !rl->dialog->pg_needs_pulse) { | |
624 rl->dialog->pg_to_active = FALSE; | |
625 gaim_roomlist_unref(list); | |
626 return FALSE; | |
627 } | |
628 | |
629 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(rl->dialog->progress)); | |
630 rl->dialog->pg_needs_pulse = FALSE; | |
631 return TRUE; | |
632 } | |
633 | |
8113 | 634 static void gaim_gtk_roomlist_add_room(GaimRoomlist *list, GaimRoomlistRoom *room) |
635 { | |
12286
255e6912607b
[gaim-migrate @ 14590]
Etan Reisner <pidgin@unreliablesource.net>
parents:
11490
diff
changeset
|
636 GaimGtkRoomlist *rl = list->ui_data; |
8113 | 637 GtkTreeRowReference *rr, *parentrr = NULL; |
638 GtkTreePath *path; | |
639 GtkTreeIter iter, parent, child; | |
640 GList *l, *k; | |
641 int j; | |
642 gboolean append = TRUE; | |
643 | |
644 rl->total_rooms++; | |
645 if (room->type == GAIM_ROOMLIST_ROOMTYPE_ROOM) | |
646 rl->num_rooms++; | |
647 | |
648 if (rl->dialog) { | |
8230 | 649 if (!rl->dialog->pg_to_active) { |
650 rl->dialog->pg_to_active = TRUE; | |
651 gaim_roomlist_ref(list); | |
652 rl->dialog->pg_update_to = g_timeout_add(100, gaim_gtk_progress_bar_pulse, list); | |
653 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(rl->dialog->progress)); | |
654 } else { | |
655 rl->dialog->pg_needs_pulse = TRUE; | |
656 } | |
8113 | 657 } |
658 if (room->parent) { | |
659 parentrr = g_hash_table_lookup(rl->cats, room->parent); | |
660 path = gtk_tree_row_reference_get_path(parentrr); | |
661 if (path) { | |
662 GaimRoomlistRoom *tmproom = NULL; | |
663 | |
664 gtk_tree_model_get_iter(GTK_TREE_MODEL(rl->model), &parent, path); | |
665 gtk_tree_path_free(path); | |
666 | |
667 if (gtk_tree_model_iter_children(GTK_TREE_MODEL(rl->model), &child, &parent)) { | |
668 gtk_tree_model_get(GTK_TREE_MODEL(rl->model), &child, ROOM_COLUMN, &tmproom, -1); | |
669 if (!tmproom) | |
670 append = FALSE; | |
671 } | |
672 } | |
673 } | |
674 | |
675 if (append) | |
676 gtk_tree_store_append(rl->model, &iter, (parentrr ? &parent : NULL)); | |
677 else | |
678 iter = child; | |
679 | |
8584 | 680 if (room->type & GAIM_ROOMLIST_ROOMTYPE_CATEGORY) |
8113 | 681 gtk_tree_store_append(rl->model, &child, &iter); |
682 | |
683 path = gtk_tree_model_get_path(GTK_TREE_MODEL(rl->model), &iter); | |
684 | |
8584 | 685 if (room->type & GAIM_ROOMLIST_ROOMTYPE_CATEGORY) { |
8113 | 686 rr = gtk_tree_row_reference_new(GTK_TREE_MODEL(rl->model), path); |
687 g_hash_table_insert(rl->cats, room, rr); | |
688 } | |
689 | |
690 gtk_tree_path_free(path); | |
691 | |
692 gtk_tree_store_set(rl->model, &iter, NAME_COLUMN, room->name, -1); | |
693 gtk_tree_store_set(rl->model, &iter, ROOM_COLUMN, room, -1); | |
694 | |
695 for (j = NUM_OF_COLUMNS, l = room->fields, k = list->fields; l && k; j++, l = l->next, k = k->next) { | |
696 GaimRoomlistField *f = k->data; | |
697 if (f->hidden) | |
698 continue; | |
699 gtk_tree_store_set(rl->model, &iter, j, l->data, -1); | |
700 } | |
701 } | |
702 | |
703 static void gaim_gtk_roomlist_in_progress(GaimRoomlist *list, gboolean flag) | |
704 { | |
705 GaimGtkRoomlist *rl = list->ui_data; | |
706 | |
707 if (!rl || !rl->dialog) | |
708 return; | |
709 | |
710 if (flag) { | |
8199 | 711 if (rl->dialog->account_widget) |
712 gtk_widget_set_sensitive(rl->dialog->account_widget, FALSE); | |
713 gtk_widget_set_sensitive(rl->dialog->stop_button, TRUE); | |
714 gtk_widget_set_sensitive(rl->dialog->list_button, FALSE); | |
8113 | 715 } else { |
8230 | 716 rl->dialog->pg_needs_pulse = FALSE; |
8113 | 717 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(rl->dialog->progress), 0.0); |
8199 | 718 if (rl->dialog->account_widget) |
719 gtk_widget_set_sensitive(rl->dialog->account_widget, TRUE); | |
720 gtk_widget_set_sensitive(rl->dialog->stop_button, FALSE); | |
721 gtk_widget_set_sensitive(rl->dialog->list_button, TRUE); | |
8113 | 722 } |
723 } | |
724 | |
725 static void gaim_gtk_roomlist_destroy(GaimRoomlist *list) | |
726 { | |
727 GaimGtkRoomlist *rl; | |
728 | |
729 roomlists = g_list_remove(roomlists, list); | |
730 | |
731 rl = list->ui_data; | |
732 | |
733 g_return_if_fail(rl != NULL); | |
734 | |
735 g_hash_table_destroy(rl->cats); | |
736 g_free(rl); | |
737 list->ui_data = NULL; | |
738 } | |
739 | |
740 static GaimRoomlistUiOps ops = { | |
8352 | 741 gaim_gtk_roomlist_dialog_show_with_account, |
8113 | 742 gaim_gtk_roomlist_new, |
743 gaim_gtk_roomlist_set_fields, | |
744 gaim_gtk_roomlist_add_room, | |
745 gaim_gtk_roomlist_in_progress, | |
746 gaim_gtk_roomlist_destroy | |
747 }; | |
748 | |
749 | |
750 void gaim_gtk_roomlist_init(void) | |
751 { | |
752 gaim_roomlist_set_ui_ops(&ops); | |
753 } |