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