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