Mercurial > pidgin
annotate src/gtkroomlist.c @ 10470:eaa9552a5e0f
[gaim-migrate @ 11752]
Fix sf patch #1094564, from Evan Schoenberg
Basically our ft API allows the filename to be NULL, but there are
times when we attempt to print the filename and don't check if it's
NULL first. This apparently sometimes causes crashes (on win32, OSX,
Solaris, and I guess any other OS that doesn't let you printf("%s", NULL);
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 04 Jan 2005 01:58:36 +0000 |
parents | 75f052c26f16 |
children | a511b77a368b |
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; | |
169 GValue val = { 0, }; | |
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)) { | |
177 gtk_tree_model_get_value(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &val); | |
178 room = g_value_get_pointer(&val); | |
179 if (!room || !(room->type & GAIM_ROOMLIST_ROOMTYPE_ROOM)) { | |
180 gtk_widget_set_sensitive(dialog->join_button, FALSE); | |
181 return; | |
182 } | |
183 | |
184 info = g_new0(struct _menu_cb_info, 1); | |
185 info->list = dialog->roomlist; | |
186 info->room = room; | |
187 | |
8377 | 188 g_object_set_data_full(G_OBJECT(dialog->join_button), "room-info", |
189 info, join_button_data_change_cb); | |
8199 | 190 |
191 gtk_widget_set_sensitive(dialog->join_button, TRUE); | |
192 } else { | |
193 gtk_widget_set_sensitive(dialog->join_button, FALSE); | |
194 } | |
195 } | |
196 | |
8113 | 197 static void do_join_cb(GtkWidget *w, struct _menu_cb_info *info) |
198 { | |
8199 | 199 gaim_roomlist_room_join(info->list, info->room); |
200 } | |
8113 | 201 |
8199 | 202 static void join_button_cb(GtkButton *button, GaimGtkRoomlistDialog *dialog) |
203 { | |
204 GaimRoomlist *rl = dialog->roomlist; | |
205 GaimGtkRoomlist *grl = rl->ui_data; | |
206 struct _menu_cb_info *info; | |
207 | |
208 info = (struct _menu_cb_info*)g_object_get_data(G_OBJECT(button), "room-info"); | |
209 | |
8377 | 210 if(info != NULL) |
211 do_join_cb(grl->tree, info); | |
8113 | 212 } |
213 | |
214 static void row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *arg2, | |
215 GaimRoomlist *list) | |
216 { | |
217 GaimGtkRoomlist *grl = list->ui_data; | |
218 GtkTreeIter iter; | |
219 GaimRoomlistRoom *room; | |
220 GValue val = { 0, }; | |
221 struct _menu_cb_info info; | |
222 | |
223 gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path); | |
224 gtk_tree_model_get_value(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &val); | |
225 room = g_value_get_pointer(&val); | |
226 if (!room || !(room->type & GAIM_ROOMLIST_ROOMTYPE_ROOM)) | |
227 return; | |
228 | |
229 info.list = list; | |
230 info.room = room; | |
231 | |
232 do_join_cb(GTK_WIDGET(tv), &info); | |
233 } | |
234 | |
235 static gboolean room_click_cb(GtkWidget *tv, GdkEventButton *event, GaimRoomlist *list) | |
236 { | |
237 GtkTreePath *path; | |
238 GaimGtkRoomlist *grl = list->ui_data; | |
239 GValue val = { 0, }; | |
240 GaimRoomlistRoom *room; | |
241 GtkTreeIter iter; | |
242 GtkWidget *menu; | |
243 static struct _menu_cb_info info; /* XXX? */ | |
244 | |
245 if (event->button != 3 || event->type != GDK_BUTTON_PRESS) | |
246 return FALSE; | |
247 | |
248 /* Here we figure out which room was clicked */ | |
249 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL)) | |
250 return FALSE; | |
251 gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path); | |
252 gtk_tree_path_free(path); | |
253 gtk_tree_model_get_value (GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &val); | |
254 room = g_value_get_pointer(&val); | |
255 | |
256 if (!room || !(room->type & GAIM_ROOMLIST_ROOMTYPE_ROOM)) | |
257 return FALSE; | |
258 | |
259 info.list = list; | |
260 info.room = room; | |
261 | |
262 | |
263 menu = gtk_menu_new(); | |
264 gaim_new_item_from_stock(menu, _("_Join"), GAIM_STOCK_CHAT, | |
265 G_CALLBACK(do_join_cb), &info, 0, 0, NULL); | |
266 | |
267 | |
268 gtk_widget_show_all(menu); | |
269 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time); | |
270 | |
271 return FALSE; | |
272 } | |
273 | |
274 static void row_expanded_cb(GtkTreeView *treeview, GtkTreeIter *arg1, GtkTreePath *arg2, gpointer user_data) | |
275 { | |
276 GaimRoomlist *list = user_data; | |
8584 | 277 GaimRoomlistRoom *category; |
8113 | 278 GValue val = { 0, }; |
279 | |
280 gtk_tree_model_get_value(gtk_tree_view_get_model(treeview), arg1, ROOM_COLUMN, &val); | |
8584 | 281 category = g_value_get_pointer(&val); |
8113 | 282 |
8584 | 283 if (!category->expanded_once) { |
284 gaim_roomlist_expand_category(list, category); | |
285 category->expanded_once = TRUE; | |
8113 | 286 } |
287 } | |
288 | |
8939 | 289 static gboolean account_filter_func(GaimAccount *account) |
8113 | 290 { |
8939 | 291 GaimConnection *gc = gaim_account_get_connection(account); |
292 GaimPluginProtocolInfo *prpl_info = NULL; | |
293 | |
294 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
295 | |
296 return (prpl_info->roomlist_get_list != NULL); | |
297 } | |
298 | |
299 gboolean | |
300 gaim_gtk_roomlist_is_showable() | |
301 { | |
302 GList *c; | |
8113 | 303 GaimConnection *gc; |
304 | |
8939 | 305 for (c = gaim_connections_get_all(); c != NULL; c = c->next) { |
306 gc = c->data; | |
307 | |
308 if (account_filter_func(gaim_connection_get_account(gc))) | |
309 return TRUE; | |
310 } | |
311 | |
312 return FALSE; | |
8113 | 313 } |
314 | |
315 GaimGtkRoomlistDialog *gaim_gtk_roomlist_dialog_new_with_account(GaimAccount *account) | |
316 { | |
317 GaimGtkRoomlistDialog *dialog; | |
318 GtkWidget *window; | |
8199 | 319 GtkWidget *vbox; |
320 GtkWidget *vbox2; | |
8113 | 321 GtkWidget *account_hbox; |
322 GtkWidget *bbox; | |
323 GtkWidget *label; | |
324 | |
325 dialog = g_new0(GaimGtkRoomlistDialog, 1); | |
8937 | 326 dialog->account = account; |
8113 | 327 |
328 /* Create the window. */ | |
329 dialog->window = window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
330 gtk_window_set_role(GTK_WINDOW(window), "room list"); | |
331 gtk_window_set_title(GTK_WINDOW(window), _("Room List")); | |
332 | |
333 gtk_container_set_border_width(GTK_CONTAINER(window), 12); | |
334 | |
335 g_signal_connect(G_OBJECT(window), "delete_event", | |
336 G_CALLBACK(delete_win_cb), dialog); | |
337 | |
338 /* Create the parent vbox for everything. */ | |
8199 | 339 vbox = gtk_vbox_new(FALSE, 12); |
340 gtk_container_add(GTK_CONTAINER(window), vbox); | |
341 gtk_widget_show(vbox); | |
8113 | 342 |
8199 | 343 vbox2 = gtk_vbox_new(FALSE, 12); |
344 gtk_container_add(GTK_CONTAINER(vbox), vbox2); | |
8113 | 345 gtk_widget_show(vbox2); |
346 | |
8352 | 347 /* accounts dropdown list */ |
8425
6d8ec773a485
[gaim-migrate @ 9155]
Christian Hammond <chipx86@chipx86.com>
parents:
8377
diff
changeset
|
348 account_hbox = gtk_hbox_new(FALSE, 6); |
8352 | 349 gtk_box_pack_start(GTK_BOX(vbox2), account_hbox, FALSE, FALSE, 0); |
350 gtk_widget_show(account_hbox); | |
8113 | 351 |
8352 | 352 label = gtk_label_new(NULL); |
8425
6d8ec773a485
[gaim-migrate @ 9155]
Christian Hammond <chipx86@chipx86.com>
parents:
8377
diff
changeset
|
353 gtk_box_pack_start(GTK_BOX(account_hbox), label, FALSE, FALSE, 0); |
8352 | 354 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Account:")); |
8425
6d8ec773a485
[gaim-migrate @ 9155]
Christian Hammond <chipx86@chipx86.com>
parents:
8377
diff
changeset
|
355 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); |
8352 | 356 gtk_widget_show(label); |
8113 | 357 |
8352 | 358 dialog->account_widget = gaim_gtk_account_option_menu_new(dialog->account, FALSE, |
8939 | 359 G_CALLBACK(dialog_select_account_cb), account_filter_func, dialog); |
8199 | 360 |
9067 | 361 if (!dialog->account) /* this is normally null, and we normally don't care what the first selected item is */ |
362 dialog->account = gaim_gtk_account_option_menu_get_selected(dialog->account_widget); | |
363 | |
8352 | 364 gtk_box_pack_start(GTK_BOX(account_hbox), dialog->account_widget, TRUE, TRUE, 0); |
365 gtk_label_set_mnemonic_widget(GTK_LABEL(label), GTK_WIDGET(dialog->account_widget)); | |
366 gtk_widget_show(dialog->account_widget); | |
8113 | 367 |
8199 | 368 /* scrolled window */ |
8113 | 369 dialog->sw = gtk_scrolled_window_new(NULL, NULL); |
370 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(dialog->sw), | |
371 GTK_SHADOW_IN); | |
372 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dialog->sw), | |
373 GTK_POLICY_AUTOMATIC, | |
374 GTK_POLICY_AUTOMATIC); | |
8199 | 375 gtk_box_pack_start(GTK_BOX(vbox2), dialog->sw, TRUE, TRUE, 0); |
376 gtk_widget_set_size_request(dialog->sw, -1, 250); | |
8113 | 377 gtk_widget_show(dialog->sw); |
378 | |
8199 | 379 /* progress bar */ |
380 dialog->progress = gtk_progress_bar_new(); | |
381 gtk_progress_bar_set_pulse_step(GTK_PROGRESS_BAR(dialog->progress), 0.1); | |
382 gtk_box_pack_start(GTK_BOX(vbox2), dialog->progress, FALSE, FALSE, 0); | |
383 gtk_widget_show(dialog->progress); | |
384 | |
385 | |
386 /* button box */ | |
387 bbox = gtk_hbutton_box_new(); | |
388 gtk_box_set_spacing(GTK_BOX(bbox), 6); | |
389 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); | |
390 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); | |
391 gtk_widget_show(bbox); | |
392 | |
393 /* stop button */ | |
394 dialog->stop_button = gtk_button_new_from_stock(GTK_STOCK_STOP); | |
395 gtk_box_pack_start(GTK_BOX(bbox), dialog->stop_button, FALSE, FALSE, 0); | |
396 g_signal_connect(G_OBJECT(dialog->stop_button), "clicked", | |
397 G_CALLBACK(stop_button_cb), dialog); | |
398 gtk_widget_set_sensitive(dialog->stop_button, FALSE); | |
399 gtk_widget_show(dialog->stop_button); | |
400 | |
401 /* list button */ | |
402 dialog->list_button = gtk_button_new_with_mnemonic(_("_Get List")); | |
403 gtk_box_pack_start(GTK_BOX(bbox), dialog->list_button, FALSE, FALSE, 0); | |
404 g_signal_connect(G_OBJECT(dialog->list_button), "clicked", | |
405 G_CALLBACK(list_button_cb), dialog); | |
406 gtk_widget_show(dialog->list_button); | |
407 | |
408 /* join button */ | |
409 dialog->join_button = gaim_pixbuf_button_from_stock(_("_Join"), GAIM_STOCK_CHAT, | |
410 GAIM_BUTTON_HORIZONTAL); | |
411 gtk_box_pack_start(GTK_BOX(bbox), dialog->join_button, FALSE, FALSE, 0); | |
412 g_signal_connect(G_OBJECT(dialog->join_button), "clicked", | |
413 G_CALLBACK(join_button_cb), dialog); | |
414 gtk_widget_set_sensitive(dialog->join_button, FALSE); | |
415 gtk_widget_show(dialog->join_button); | |
416 | |
417 /* close button */ | |
418 dialog->close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); | |
419 gtk_box_pack_start(GTK_BOX(bbox), dialog->close_button, FALSE, FALSE, 0); | |
420 g_signal_connect(G_OBJECT(dialog->close_button), "clicked", | |
421 G_CALLBACK(close_button_cb), dialog); | |
422 gtk_widget_show(dialog->close_button); | |
423 | |
424 /* show the dialog window and return the dialog */ | |
425 gtk_widget_show(dialog->window); | |
426 | |
8113 | 427 return dialog; |
428 } | |
429 | |
430 GaimGtkRoomlistDialog *gaim_gtk_roomlist_dialog_new(void) | |
431 { | |
432 return gaim_gtk_roomlist_dialog_new_with_account(NULL); | |
433 } | |
434 | |
8352 | 435 static void gaim_gtk_roomlist_dialog_show_with_account(GaimAccount *account) |
436 { | |
437 GaimGtkRoomlistDialog *dialog; | |
438 | |
439 dialog = gaim_gtk_roomlist_dialog_new_with_account(account); | |
440 if (!dialog) | |
441 return; | |
442 | |
443 list_button_cb(GTK_BUTTON(dialog->list_button), dialog); | |
444 } | |
445 | |
8113 | 446 void gaim_gtk_roomlist_dialog_show(void) |
447 { | |
448 gaim_gtk_roomlist_dialog_new(); | |
449 } | |
450 | |
451 static void gaim_gtk_roomlist_new(GaimRoomlist *list) | |
452 { | |
453 GaimGtkRoomlist *rl; | |
454 | |
455 rl = g_new0(GaimGtkRoomlist, 1); | |
456 | |
457 list->ui_data = rl; | |
458 | |
459 rl->cats = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)gtk_tree_row_reference_free); | |
460 | |
461 roomlists = g_list_append(roomlists, list); | |
462 } | |
463 | |
464 static void int_cell_data_func(GtkTreeViewColumn *col, GtkCellRenderer *renderer, | |
465 GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) | |
466 { | |
467 gchar buf[16]; | |
468 int myint; | |
469 | |
470 gtk_tree_model_get(model, iter, GPOINTER_TO_INT(user_data), &myint, -1); | |
471 | |
472 if (myint) | |
473 g_snprintf(buf, sizeof(buf), "%d", myint); | |
474 else | |
475 buf[0] = '\0'; | |
476 | |
477 g_object_set(renderer, "text", buf, NULL); | |
478 } | |
479 | |
480 /* this sorts backwards on purpose, so that clicking name sorts a-z, while clicking users sorts | |
481 infinity-0. you can still click again to reverse it on any of them. */ | |
482 static gint int_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) | |
483 { | |
484 int c, d; | |
485 | |
486 c = d = 0; | |
487 | |
488 gtk_tree_model_get(model, a, GPOINTER_TO_INT(user_data), &c, -1); | |
489 gtk_tree_model_get(model, b, GPOINTER_TO_INT(user_data), &d, -1); | |
490 | |
491 if (c == d) | |
492 return 0; | |
493 else if (c > d) | |
494 return -1; | |
495 else | |
496 return 1; | |
497 } | |
498 | |
499 static void gaim_gtk_roomlist_set_fields(GaimRoomlist *list, GList *fields) | |
500 { | |
501 GaimGtkRoomlist *grl = list->ui_data; | |
502 gint columns = NUM_OF_COLUMNS; | |
503 int j; | |
504 GtkTreeStore *model; | |
505 GtkWidget *tree; | |
506 GtkCellRenderer *renderer; | |
507 GtkTreeViewColumn *column; | |
8199 | 508 GtkTreeSelection *selection; |
8113 | 509 GList *l; |
510 GType *types; | |
511 | |
512 g_return_if_fail(grl != NULL); | |
513 | |
514 columns += g_list_length(fields); | |
515 types = g_new(GType, columns); | |
516 | |
517 types[NAME_COLUMN] = G_TYPE_STRING; | |
518 types[ROOM_COLUMN] = G_TYPE_POINTER; | |
519 | |
520 for (j = NUM_OF_COLUMNS, l = fields; l; l = l->next, j++) { | |
521 GaimRoomlistField *f = l->data; | |
522 | |
523 switch (f->type) { | |
524 case GAIM_ROOMLIST_FIELD_BOOL: | |
525 types[j] = G_TYPE_BOOLEAN; | |
526 break; | |
527 case GAIM_ROOMLIST_FIELD_INT: | |
528 types[j] = G_TYPE_INT; | |
529 break; | |
530 case GAIM_ROOMLIST_FIELD_STRING: | |
531 types[j] = G_TYPE_STRING; | |
532 break; | |
533 } | |
534 } | |
535 | |
536 model = gtk_tree_store_newv(columns, types); | |
537 g_free(types); | |
538 | |
539 tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); | |
540 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE); | |
541 | |
8199 | 542 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)); |
543 g_signal_connect(G_OBJECT(selection), "changed", | |
544 G_CALLBACK(selection_changed_cb), grl); | |
545 | |
8113 | 546 g_object_unref(model); |
547 | |
548 grl->model = model; | |
549 grl->tree = tree; | |
550 gtk_widget_show(grl->tree); | |
551 | |
552 renderer = gtk_cell_renderer_text_new(); | |
553 column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, | |
554 "text", NAME_COLUMN, NULL); | |
555 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column), | |
556 GTK_TREE_VIEW_COLUMN_GROW_ONLY); | |
557 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); | |
558 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), NAME_COLUMN); | |
559 gtk_tree_view_column_set_reorderable(GTK_TREE_VIEW_COLUMN(column), TRUE); | |
560 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); | |
561 | |
562 for (j = NUM_OF_COLUMNS, l = fields; l; l = l->next, j++) { | |
563 GaimRoomlistField *f = l->data; | |
564 | |
565 if (f->hidden) | |
566 continue; | |
567 | |
568 renderer = gtk_cell_renderer_text_new(); | |
569 column = gtk_tree_view_column_new_with_attributes(f->label, renderer, | |
570 "text", j, NULL); | |
571 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column), | |
572 GTK_TREE_VIEW_COLUMN_GROW_ONLY); | |
573 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); | |
574 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), j); | |
575 gtk_tree_view_column_set_reorderable(GTK_TREE_VIEW_COLUMN(column), TRUE); | |
576 if (f->type == GAIM_ROOMLIST_FIELD_INT) { | |
577 gtk_tree_view_column_set_cell_data_func(column, renderer, int_cell_data_func, | |
578 GINT_TO_POINTER(j), NULL); | |
579 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), j, int_sort_func, | |
580 GINT_TO_POINTER(j), NULL); | |
581 } | |
582 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); | |
583 } | |
584 | |
585 g_signal_connect(G_OBJECT(tree), "button-press-event", G_CALLBACK(room_click_cb), list); | |
586 g_signal_connect(G_OBJECT(tree), "row-expanded", G_CALLBACK(row_expanded_cb), list); | |
587 g_signal_connect(G_OBJECT(tree), "row-activated", G_CALLBACK(row_activated_cb), list); | |
588 } | |
589 | |
8230 | 590 static gboolean gaim_gtk_progress_bar_pulse(gpointer data) |
591 { | |
592 GaimRoomlist *list = data; | |
593 GaimGtkRoomlist *rl = list->ui_data; | |
594 | |
595 if (!rl || !rl->dialog || !rl->dialog->pg_needs_pulse) { | |
596 rl->dialog->pg_to_active = FALSE; | |
597 gaim_roomlist_unref(list); | |
598 return FALSE; | |
599 } | |
600 | |
601 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(rl->dialog->progress)); | |
602 rl->dialog->pg_needs_pulse = FALSE; | |
603 return TRUE; | |
604 } | |
605 | |
8113 | 606 static void gaim_gtk_roomlist_add_room(GaimRoomlist *list, GaimRoomlistRoom *room) |
607 { | |
608 GaimGtkRoomlist *rl= list->ui_data; | |
609 GtkTreeRowReference *rr, *parentrr = NULL; | |
610 GtkTreePath *path; | |
611 GtkTreeIter iter, parent, child; | |
612 GList *l, *k; | |
613 int j; | |
614 gboolean append = TRUE; | |
615 | |
616 rl->total_rooms++; | |
617 if (room->type == GAIM_ROOMLIST_ROOMTYPE_ROOM) | |
618 rl->num_rooms++; | |
619 | |
620 if (rl->dialog) { | |
8230 | 621 if (!rl->dialog->pg_to_active) { |
622 rl->dialog->pg_to_active = TRUE; | |
623 gaim_roomlist_ref(list); | |
624 rl->dialog->pg_update_to = g_timeout_add(100, gaim_gtk_progress_bar_pulse, list); | |
625 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(rl->dialog->progress)); | |
626 } else { | |
627 rl->dialog->pg_needs_pulse = TRUE; | |
628 } | |
8113 | 629 } |
630 if (room->parent) { | |
631 parentrr = g_hash_table_lookup(rl->cats, room->parent); | |
632 path = gtk_tree_row_reference_get_path(parentrr); | |
633 if (path) { | |
634 GaimRoomlistRoom *tmproom = NULL; | |
635 | |
636 gtk_tree_model_get_iter(GTK_TREE_MODEL(rl->model), &parent, path); | |
637 gtk_tree_path_free(path); | |
638 | |
639 if (gtk_tree_model_iter_children(GTK_TREE_MODEL(rl->model), &child, &parent)) { | |
640 gtk_tree_model_get(GTK_TREE_MODEL(rl->model), &child, ROOM_COLUMN, &tmproom, -1); | |
641 if (!tmproom) | |
642 append = FALSE; | |
643 } | |
644 } | |
645 } | |
646 | |
647 if (append) | |
648 gtk_tree_store_append(rl->model, &iter, (parentrr ? &parent : NULL)); | |
649 else | |
650 iter = child; | |
651 | |
8584 | 652 if (room->type & GAIM_ROOMLIST_ROOMTYPE_CATEGORY) |
8113 | 653 gtk_tree_store_append(rl->model, &child, &iter); |
654 | |
655 path = gtk_tree_model_get_path(GTK_TREE_MODEL(rl->model), &iter); | |
656 | |
8584 | 657 if (room->type & GAIM_ROOMLIST_ROOMTYPE_CATEGORY) { |
8113 | 658 rr = gtk_tree_row_reference_new(GTK_TREE_MODEL(rl->model), path); |
659 g_hash_table_insert(rl->cats, room, rr); | |
660 } | |
661 | |
662 gtk_tree_path_free(path); | |
663 | |
664 gtk_tree_store_set(rl->model, &iter, NAME_COLUMN, room->name, -1); | |
665 gtk_tree_store_set(rl->model, &iter, ROOM_COLUMN, room, -1); | |
666 | |
667 for (j = NUM_OF_COLUMNS, l = room->fields, k = list->fields; l && k; j++, l = l->next, k = k->next) { | |
668 GaimRoomlistField *f = k->data; | |
669 if (f->hidden) | |
670 continue; | |
671 gtk_tree_store_set(rl->model, &iter, j, l->data, -1); | |
672 } | |
673 } | |
674 | |
675 static void gaim_gtk_roomlist_in_progress(GaimRoomlist *list, gboolean flag) | |
676 { | |
677 GaimGtkRoomlist *rl = list->ui_data; | |
678 | |
679 if (!rl || !rl->dialog) | |
680 return; | |
681 | |
682 if (flag) { | |
8199 | 683 if (rl->dialog->account_widget) |
684 gtk_widget_set_sensitive(rl->dialog->account_widget, FALSE); | |
685 gtk_widget_set_sensitive(rl->dialog->stop_button, TRUE); | |
686 gtk_widget_set_sensitive(rl->dialog->list_button, FALSE); | |
8113 | 687 } else { |
8230 | 688 rl->dialog->pg_needs_pulse = FALSE; |
8113 | 689 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(rl->dialog->progress), 0.0); |
8199 | 690 if (rl->dialog->account_widget) |
691 gtk_widget_set_sensitive(rl->dialog->account_widget, TRUE); | |
692 gtk_widget_set_sensitive(rl->dialog->stop_button, FALSE); | |
693 gtk_widget_set_sensitive(rl->dialog->list_button, TRUE); | |
8113 | 694 } |
695 } | |
696 | |
697 static void gaim_gtk_roomlist_destroy(GaimRoomlist *list) | |
698 { | |
699 GaimGtkRoomlist *rl; | |
700 | |
701 roomlists = g_list_remove(roomlists, list); | |
702 | |
703 rl = list->ui_data; | |
704 | |
705 g_return_if_fail(rl != NULL); | |
706 | |
707 g_hash_table_destroy(rl->cats); | |
708 g_free(rl); | |
709 list->ui_data = NULL; | |
710 } | |
711 | |
712 static GaimRoomlistUiOps ops = { | |
8352 | 713 gaim_gtk_roomlist_dialog_show_with_account, |
8113 | 714 gaim_gtk_roomlist_new, |
715 gaim_gtk_roomlist_set_fields, | |
716 gaim_gtk_roomlist_add_room, | |
717 gaim_gtk_roomlist_in_progress, | |
718 gaim_gtk_roomlist_destroy | |
719 }; | |
720 | |
721 | |
722 void gaim_gtk_roomlist_init(void) | |
723 { | |
724 gaim_roomlist_set_ui_ops(&ops); | |
725 } |