| 59 G_DEFINE_TYPE(PidginRoomlistDialog, pidgin_roomlist_dialog, GTK_TYPE_DIALOG) |
59 G_DEFINE_TYPE(PidginRoomlistDialog, pidgin_roomlist_dialog, GTK_TYPE_DIALOG) |
| 60 |
60 |
| 61 typedef struct { |
61 typedef struct { |
| 62 PidginRoomlistDialog *dialog; |
62 PidginRoomlistDialog *dialog; |
| 63 GtkTreeStore *model; |
63 GtkTreeStore *model; |
| 64 GtkWidget *tree; |
|
| 65 GHashTable *cats; /* Meow. */ |
|
| 66 gint num_rooms, total_rooms; |
|
| 67 } PidginRoomlist; |
64 } PidginRoomlist; |
| 68 |
65 |
| 69 enum { |
66 enum { |
| 70 NAME_COLUMN = 0, |
67 ROOM_COLUMN = 0, |
| 71 ROOM_COLUMN, |
68 NAME_COLUMN, |
| |
69 DESCRIPTION_COLUMN, |
| 72 NUM_OF_COLUMNS, |
70 NUM_OF_COLUMNS, |
| 73 }; |
71 }; |
| |
72 |
| |
73 static gboolean |
| |
74 _search_func(GtkTreeModel *model, gint column, const gchar *key, |
| |
75 GtkTreeIter *iter, gpointer search_data) |
| |
76 { |
| |
77 gboolean result; |
| |
78 gchar *name, *fold, *fkey; |
| |
79 |
| |
80 gtk_tree_model_get(model, iter, column, &name, -1); |
| |
81 fold = g_utf8_casefold(name, -1); |
| |
82 fkey = g_utf8_casefold(key, -1); |
| |
83 |
| |
84 result = (g_strstr_len(fold, strlen(fold), fkey) == NULL); |
| |
85 |
| |
86 g_free(fold); |
| |
87 g_free(fkey); |
| |
88 g_free(name); |
| |
89 |
| |
90 return result; |
| |
91 } |
| 74 |
92 |
| 75 static gint delete_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d) |
93 static gint delete_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d) |
| 76 { |
94 { |
| 77 PidginRoomlistDialog *dialog = PIDGIN_ROOMLIST_DIALOG(w); |
95 PidginRoomlistDialog *dialog = PIDGIN_ROOMLIST_DIALOG(w); |
| 78 |
96 |
| 182 PurpleRoomlist *list; |
199 PurpleRoomlist *list; |
| 183 PurpleRoomlistRoom *room; |
200 PurpleRoomlistRoom *room; |
| 184 }; |
201 }; |
| 185 |
202 |
| 186 static void |
203 static void |
| 187 selection_changed_cb(GtkTreeSelection *selection, PidginRoomlist *grl) { |
204 selection_changed_cb(GtkTreeSelection *selection, |
| |
205 PidginRoomlistDialog *dialog) |
| |
206 { |
| 188 GtkTreeIter iter; |
207 GtkTreeIter iter; |
| 189 GValue val; |
|
| 190 PurpleRoomlistRoom *room; |
208 PurpleRoomlistRoom *room; |
| 191 static struct _menu_cb_info *info; |
209 static struct _menu_cb_info *info; |
| 192 PidginRoomlistDialog *dialog = grl->dialog; |
210 PidginRoomlist *grl = NULL; |
| |
211 |
| |
212 grl = g_object_get_data(G_OBJECT(dialog->roomlist), |
| |
213 PIDGIN_ROOMLIST_UI_DATA); |
| 193 |
214 |
| 194 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
215 if (gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
| 195 val.g_type = 0; |
216 gtk_tree_model_get(GTK_TREE_MODEL(grl->model), &iter, |
| 196 gtk_tree_model_get_value(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &val); |
217 ROOM_COLUMN, &room, |
| 197 room = g_value_get_pointer(&val); |
218 -1); |
| 198 if (!room || !(purple_roomlist_room_get_room_type(room) & PURPLE_ROOMLIST_ROOMTYPE_ROOM)) { |
|
| 199 gtk_widget_set_sensitive(dialog->join_button, FALSE); |
|
| 200 gtk_widget_set_sensitive(dialog->add_button, FALSE); |
|
| 201 return; |
|
| 202 } |
|
| 203 |
219 |
| 204 info = g_new0(struct _menu_cb_info, 1); |
220 info = g_new0(struct _menu_cb_info, 1); |
| 205 info->list = dialog->roomlist; |
221 info->list = dialog->roomlist; |
| 206 info->room = room; |
222 info->room = room; |
| 207 |
223 |
| 250 do_add_room_cb(NULL, info); |
268 do_add_room_cb(NULL, info); |
| 251 } |
269 } |
| 252 } |
270 } |
| 253 |
271 |
| 254 static void |
272 static void |
| 255 do_join_cb(G_GNUC_UNUSED GtkWidget *w, struct _menu_cb_info *info) |
273 do_join_cb(G_GNUC_UNUSED GtkWidget *w, struct _menu_cb_info *info) { |
| 256 { |
274 purple_roomlist_join_room(info->list, info->room); |
| 257 purple_roomlist_room_join(info->list, info->room); |
275 } |
| 258 } |
276 |
| 259 |
277 static void |
| 260 static void |
278 join_button_cb(GtkButton *button, G_GNUC_UNUSED gpointer data) { |
| 261 join_button_cb(GtkButton *button, G_GNUC_UNUSED gpointer data) |
|
| 262 { |
|
| 263 struct _menu_cb_info *info = g_object_get_data(G_OBJECT(button), "room-info"); |
279 struct _menu_cb_info *info = g_object_get_data(G_OBJECT(button), "room-info"); |
| 264 |
280 |
| 265 if(info != NULL) { |
281 purple_roomlist_join_room(info->list, info->room); |
| 266 do_join_cb(NULL, info); |
282 } |
| 267 } |
283 |
| 268 } |
284 static void |
| 269 |
285 row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *arg2, |
| 270 static void row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *arg2, |
286 gpointer data) |
| 271 PurpleRoomlist *list) |
287 { |
| 272 { |
288 PidginRoomlistDialog *dialog = data; |
| 273 PidginRoomlist *grl = NULL; |
289 PidginRoomlist *grl = NULL; |
| 274 GtkTreeIter iter; |
290 GtkTreeIter iter; |
| 275 PurpleRoomlistRoom *room; |
291 PurpleRoomlistRoom *room; |
| 276 GValue val; |
|
| 277 struct _menu_cb_info info; |
292 struct _menu_cb_info info; |
| 278 |
293 |
| 279 grl = g_object_get_data(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA); |
294 grl = g_object_get_data(G_OBJECT(dialog->roomlist), PIDGIN_ROOMLIST_UI_DATA); |
| 280 |
295 |
| 281 gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path); |
296 gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path); |
| 282 val.g_type = 0; |
297 gtk_tree_model_get(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &room, -1); |
| 283 gtk_tree_model_get_value(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &val); |
298 |
| 284 room = g_value_get_pointer(&val); |
299 info.list = dialog->roomlist; |
| 285 if (!room || !(purple_roomlist_room_get_room_type(room) & PURPLE_ROOMLIST_ROOMTYPE_ROOM)) |
|
| 286 return; |
|
| 287 |
|
| 288 info.list = list; |
|
| 289 info.room = room; |
300 info.room = room; |
| 290 |
301 |
| 291 do_join_cb(NULL, &info); |
302 do_join_cb(NULL, &info); |
| 292 } |
303 |
| 293 |
304 g_clear_object(&room); |
| 294 static gboolean room_click_cb(GtkWidget *tv, GdkEventButton *event, PurpleRoomlist *list) |
305 } |
| 295 { |
306 |
| |
307 static gboolean |
| |
308 room_click_cb(GtkWidget *tv, GdkEventButton *event, gpointer data) { |
| |
309 PidginRoomlistDialog *dialog = data; |
| 296 GtkTreePath *path; |
310 GtkTreePath *path; |
| 297 PidginRoomlist *grl = NULL; |
311 PidginRoomlist *grl = NULL; |
| 298 GValue val; |
|
| 299 PurpleRoomlistRoom *room; |
312 PurpleRoomlistRoom *room; |
| 300 GtkTreeIter iter; |
313 GtkTreeIter iter; |
| 301 GtkWidget *menu; |
314 GtkWidget *menu; |
| 302 GtkWidget *menuitem; |
315 GtkWidget *menuitem; |
| 303 static struct _menu_cb_info info; /* XXX? */ |
316 static struct _menu_cb_info info; /* XXX? */ |
| 304 |
317 |
| 305 if (!gdk_event_triggers_context_menu((GdkEvent *)event)) |
318 if (!gdk_event_triggers_context_menu((GdkEvent *)event)) |
| 306 return FALSE; |
319 return FALSE; |
| 307 |
320 |
| 308 grl = g_object_get_data(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA); |
321 grl = g_object_get_data(G_OBJECT(dialog->roomlist), PIDGIN_ROOMLIST_UI_DATA); |
| 309 |
322 |
| 310 /* Here we figure out which room was clicked */ |
323 /* Here we figure out which room was clicked */ |
| 311 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL)) |
324 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tv), event->x, event->y, &path, NULL, NULL, NULL)) |
| 312 return FALSE; |
325 return FALSE; |
| 313 gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path); |
326 gtk_tree_model_get_iter(GTK_TREE_MODEL(grl->model), &iter, path); |
| 314 gtk_tree_path_free(path); |
327 gtk_tree_path_free(path); |
| 315 val.g_type = 0; |
328 gtk_tree_model_get(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &room, -1); |
| 316 gtk_tree_model_get_value (GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, &val); |
329 |
| 317 room = g_value_get_pointer(&val); |
330 info.list = dialog->roomlist; |
| 318 |
|
| 319 if (!room || !(purple_roomlist_room_get_room_type(room) & PURPLE_ROOMLIST_ROOMTYPE_ROOM)) |
|
| 320 return FALSE; |
|
| 321 |
|
| 322 info.list = list; |
|
| 323 info.room = room; |
331 info.room = room; |
| |
332 |
| |
333 /* The current implementation isn't expecting a ref to unref the one we got |
| |
334 * when we pulled the room out of the model. |
| |
335 */ |
| |
336 g_clear_object(&room); |
| 324 |
337 |
| 325 menu = gtk_menu_new(); |
338 menu = gtk_menu_new(); |
| 326 |
339 |
| 327 menuitem = gtk_menu_item_new_with_mnemonic(_("_Join")); |
340 menuitem = gtk_menu_item_new_with_mnemonic(_("_Join")); |
| 328 g_signal_connect(G_OBJECT(menuitem), "activate", |
341 g_signal_connect(G_OBJECT(menuitem), "activate", |
| 338 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); |
351 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); |
| 339 |
352 |
| 340 return FALSE; |
353 return FALSE; |
| 341 } |
354 } |
| 342 |
355 |
| 343 static void row_expanded_cb(GtkTreeView *treeview, GtkTreeIter *arg1, GtkTreePath *arg2, gpointer user_data) |
|
| 344 { |
|
| 345 PurpleRoomlist *list = user_data; |
|
| 346 PurpleRoomlistRoom *category; |
|
| 347 GValue val; |
|
| 348 |
|
| 349 val.g_type = 0; |
|
| 350 gtk_tree_model_get_value(gtk_tree_view_get_model(treeview), arg1, ROOM_COLUMN, &val); |
|
| 351 category = g_value_get_pointer(&val); |
|
| 352 |
|
| 353 if (!purple_roomlist_room_get_expanded_once(category)) { |
|
| 354 purple_roomlist_expand_category(list, category); |
|
| 355 purple_roomlist_room_set_expanded_once(category, TRUE); |
|
| 356 } |
|
| 357 } |
|
| 358 |
|
| 359 #define SMALL_SPACE 6 |
356 #define SMALL_SPACE 6 |
| 360 |
357 |
| 361 static gboolean |
358 static gboolean |
| 362 pidgin_roomlist_query_tooltip(GtkWidget *widget, int x, int y, |
359 pidgin_roomlist_query_tooltip(GtkWidget *widget, int x, int y, |
| 363 gboolean keyboard_mode, GtkTooltip *tooltip, |
360 gboolean keyboard_mode, GtkTooltip *tooltip, |
| 364 gpointer data) |
361 gpointer data) |
| 365 { |
362 { |
| 366 PurpleRoomlist *list = data; |
363 PidginRoomlistDialog *dialog = data; |
| 367 PidginRoomlist *grl = NULL; |
364 PidginRoomlist *grl = NULL; |
| 368 GtkTreePath *path = NULL; |
365 GtkTreePath *path = NULL; |
| 369 PurpleRoomlistRoom *room; |
|
| 370 GtkTreeIter iter; |
366 GtkTreeIter iter; |
| 371 GValue val; |
|
| 372 gchar *name, *tmp; |
367 gchar *name, *tmp; |
| 373 GString *tooltip_text = NULL; |
368 GString *tooltip_text = NULL; |
| 374 GList *l, *k; |
369 |
| 375 gint j; |
370 grl = g_object_get_data(G_OBJECT(dialog->roomlist), PIDGIN_ROOMLIST_UI_DATA); |
| 376 gboolean first = TRUE; |
|
| 377 |
|
| 378 grl = g_object_get_data(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA); |
|
| 379 |
371 |
| 380 if (keyboard_mode) { |
372 if (keyboard_mode) { |
| 381 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); |
373 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); |
| 382 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
374 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) { |
| 383 return FALSE; |
375 return FALSE; |
| 398 gtk_tree_path_free(path); |
390 gtk_tree_path_free(path); |
| 399 return FALSE; |
391 return FALSE; |
| 400 } |
392 } |
| 401 } |
393 } |
| 402 |
394 |
| 403 val.g_type = 0; |
|
| 404 gtk_tree_model_get_value(GTK_TREE_MODEL(grl->model), &iter, ROOM_COLUMN, |
|
| 405 &val); |
|
| 406 room = g_value_get_pointer(&val); |
|
| 407 |
|
| 408 if (!room || |
|
| 409 !(purple_roomlist_room_get_room_type(room) & PURPLE_ROOMLIST_ROOMTYPE_ROOM)) |
|
| 410 { |
|
| 411 gtk_tree_path_free(path); |
|
| 412 return FALSE; |
|
| 413 } |
|
| 414 |
|
| 415 tooltip_text = g_string_new(""); |
395 tooltip_text = g_string_new(""); |
| 416 |
396 |
| 417 gtk_tree_model_get(GTK_TREE_MODEL(grl->model), &iter, NAME_COLUMN, &name, -1); |
397 gtk_tree_model_get(GTK_TREE_MODEL(grl->model), &iter, NAME_COLUMN, &name, -1); |
| 418 tmp = g_markup_escape_text(name, -1); |
398 tmp = g_markup_escape_text(name, -1); |
| 419 g_free(name); |
399 g_free(name); |
| 420 g_string_append_printf( |
400 g_string_append_printf( |
| 421 tooltip_text, "<span size='x-large' weight='bold'>%s</span>\n", tmp); |
401 tooltip_text, "<span size='x-large' weight='bold'>%s</span>\n", tmp); |
| 422 g_free(tmp); |
402 g_free(tmp); |
| 423 |
403 |
| 424 for (j = NUM_OF_COLUMNS, |
|
| 425 l = purple_roomlist_room_get_fields(room), |
|
| 426 k = purple_roomlist_get_fields(list); |
|
| 427 l && k; |
|
| 428 j++, l = l->next, k = k->next) |
|
| 429 { |
|
| 430 PurpleRoomlistField *f = k->data; |
|
| 431 gchar *label; |
|
| 432 if (purple_roomlist_field_get_hidden(f)) { |
|
| 433 continue; |
|
| 434 } |
|
| 435 label = g_markup_escape_text(purple_roomlist_field_get_label(f), -1); |
|
| 436 switch (purple_roomlist_field_get_field_type(f)) { |
|
| 437 case PURPLE_ROOMLIST_FIELD_BOOL: |
|
| 438 g_string_append_printf( |
|
| 439 tooltip_text, "%s<b>%s:</b> %s", first ? "" : "\n", label, |
|
| 440 l->data ? "True" : "False"); |
|
| 441 break; |
|
| 442 case PURPLE_ROOMLIST_FIELD_INT: |
|
| 443 g_string_append_printf( |
|
| 444 tooltip_text, "%s<b>%s:</b> %d", first ? "" : "\n", label, |
|
| 445 GPOINTER_TO_INT(l->data)); |
|
| 446 break; |
|
| 447 case PURPLE_ROOMLIST_FIELD_STRING: |
|
| 448 tmp = g_markup_escape_text((char *)l->data, -1); |
|
| 449 g_string_append_printf( |
|
| 450 tooltip_text, "%s<b>%s:</b> %s", first ? "" : "\n", label, |
|
| 451 tmp); |
|
| 452 g_free(tmp); |
|
| 453 break; |
|
| 454 } |
|
| 455 first = FALSE; |
|
| 456 g_free(label); |
|
| 457 } |
|
| 458 |
|
| 459 gtk_tooltip_set_markup(tooltip, tooltip_text->str); |
404 gtk_tooltip_set_markup(tooltip, tooltip_text->str); |
| 460 gtk_tree_view_set_tooltip_row(GTK_TREE_VIEW(widget), tooltip, path); |
405 gtk_tree_view_set_tooltip_row(GTK_TREE_VIEW(widget), tooltip, path); |
| 461 g_string_free(tooltip_text, TRUE); |
406 g_string_free(tooltip_text, TRUE); |
| 462 gtk_tree_path_free(path); |
407 gtk_tree_path_free(path); |
| 463 |
408 |
| 511 list_button); |
458 list_button); |
| 512 gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog, |
459 gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog, |
| 513 progress); |
460 progress); |
| 514 gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog, |
461 gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog, |
| 515 stop_button); |
462 stop_button); |
| 516 gtk_widget_class_bind_template_child(widget_class, PidginRoomlistDialog, |
|
| 517 sw); |
|
| 518 |
463 |
| 519 gtk_widget_class_bind_template_callback(widget_class, |
464 gtk_widget_class_bind_template_callback(widget_class, |
| 520 add_room_to_blist_cb); |
465 add_room_to_blist_cb); |
| 521 gtk_widget_class_bind_template_callback(widget_class, delete_win_cb); |
466 gtk_widget_class_bind_template_callback(widget_class, delete_win_cb); |
| |
467 gtk_widget_class_bind_template_callback(widget_class, row_activated_cb); |
| |
468 gtk_widget_class_bind_template_callback(widget_class, room_click_cb); |
| 522 gtk_widget_class_bind_template_callback(widget_class, |
469 gtk_widget_class_bind_template_callback(widget_class, |
| 523 dialog_select_account_cb); |
470 dialog_select_account_cb); |
| |
471 gtk_widget_class_bind_template_callback(widget_class, |
| |
472 selection_changed_cb); |
| |
473 gtk_widget_class_bind_template_callback(widget_class, |
| |
474 pidgin_roomlist_query_tooltip); |
| 524 gtk_widget_class_bind_template_callback(widget_class, join_button_cb); |
475 gtk_widget_class_bind_template_callback(widget_class, join_button_cb); |
| 525 gtk_widget_class_bind_template_callback(widget_class, list_button_cb); |
476 gtk_widget_class_bind_template_callback(widget_class, list_button_cb); |
| 526 gtk_widget_class_bind_template_callback(widget_class, stop_button_cb); |
477 gtk_widget_class_bind_template_callback(widget_class, stop_button_cb); |
| 527 } |
478 } |
| 528 |
479 |
| 574 void pidgin_roomlist_dialog_show(void) |
528 void pidgin_roomlist_dialog_show(void) |
| 575 { |
529 { |
| 576 pidgin_roomlist_dialog_new_with_account(NULL); |
530 pidgin_roomlist_dialog_new_with_account(NULL); |
| 577 } |
531 } |
| 578 |
532 |
| 579 static void int_cell_data_func(GtkTreeViewColumn *col, GtkCellRenderer *renderer, |
|
| 580 GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) |
|
| 581 { |
|
| 582 gchar buf[16]; |
|
| 583 int myint; |
|
| 584 |
|
| 585 gtk_tree_model_get(model, iter, GPOINTER_TO_INT(user_data), &myint, -1); |
|
| 586 |
|
| 587 if (myint) |
|
| 588 g_snprintf(buf, sizeof(buf), "%d", myint); |
|
| 589 else |
|
| 590 buf[0] = '\0'; |
|
| 591 |
|
| 592 g_object_set(renderer, "text", buf, NULL); |
|
| 593 } |
|
| 594 |
|
| 595 /* this sorts backwards on purpose, so that clicking name sorts a-z, while clicking users sorts |
|
| 596 infinity-0. you can still click again to reverse it on any of them. */ |
|
| 597 static gint int_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) |
|
| 598 { |
|
| 599 int c, d; |
|
| 600 |
|
| 601 c = d = 0; |
|
| 602 |
|
| 603 gtk_tree_model_get(model, a, GPOINTER_TO_INT(user_data), &c, -1); |
|
| 604 gtk_tree_model_get(model, b, GPOINTER_TO_INT(user_data), &d, -1); |
|
| 605 |
|
| 606 if (c == d) |
|
| 607 return 0; |
|
| 608 else if (c > d) |
|
| 609 return -1; |
|
| 610 else |
|
| 611 return 1; |
|
| 612 } |
|
| 613 |
|
| 614 static gboolean |
|
| 615 _search_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data) |
|
| 616 { |
|
| 617 gboolean result; |
|
| 618 gchar *name, *fold, *fkey; |
|
| 619 |
|
| 620 gtk_tree_model_get(model, iter, column, &name, -1); |
|
| 621 fold = g_utf8_casefold(name, -1); |
|
| 622 fkey = g_utf8_casefold(key, -1); |
|
| 623 |
|
| 624 result = (g_strstr_len(fold, strlen(fold), fkey) == NULL); |
|
| 625 |
|
| 626 g_free(fold); |
|
| 627 g_free(fkey); |
|
| 628 g_free(name); |
|
| 629 |
|
| 630 return result; |
|
| 631 } |
|
| 632 |
|
| 633 static void pidgin_roomlist_set_fields(PurpleRoomlist *list, GList *fields) |
|
| 634 { |
|
| 635 PidginRoomlist *grl = NULL; |
|
| 636 gint columns = NUM_OF_COLUMNS; |
|
| 637 int j; |
|
| 638 GtkTreeStore *model; |
|
| 639 GtkWidget *tree; |
|
| 640 GtkCellRenderer *renderer; |
|
| 641 GtkTreeViewColumn *column; |
|
| 642 GtkTreeSelection *selection; |
|
| 643 GList *l; |
|
| 644 GType *types; |
|
| 645 |
|
| 646 grl = g_object_get_data(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA); |
|
| 647 g_return_if_fail(grl != NULL); |
|
| 648 |
|
| 649 columns += g_list_length(fields); |
|
| 650 types = g_new(GType, columns); |
|
| 651 |
|
| 652 types[NAME_COLUMN] = G_TYPE_STRING; |
|
| 653 types[ROOM_COLUMN] = G_TYPE_POINTER; |
|
| 654 |
|
| 655 for (j = NUM_OF_COLUMNS, l = fields; l; l = l->next, j++) { |
|
| 656 PurpleRoomlistField *f = l->data; |
|
| 657 |
|
| 658 switch (purple_roomlist_field_get_field_type(f)) { |
|
| 659 case PURPLE_ROOMLIST_FIELD_BOOL: |
|
| 660 types[j] = G_TYPE_BOOLEAN; |
|
| 661 break; |
|
| 662 case PURPLE_ROOMLIST_FIELD_INT: |
|
| 663 types[j] = G_TYPE_INT; |
|
| 664 break; |
|
| 665 case PURPLE_ROOMLIST_FIELD_STRING: |
|
| 666 types[j] = G_TYPE_STRING; |
|
| 667 break; |
|
| 668 } |
|
| 669 } |
|
| 670 |
|
| 671 model = gtk_tree_store_newv(columns, types); |
|
| 672 g_free(types); |
|
| 673 |
|
| 674 tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); |
|
| 675 |
|
| 676 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)); |
|
| 677 g_signal_connect(G_OBJECT(selection), "changed", |
|
| 678 G_CALLBACK(selection_changed_cb), grl); |
|
| 679 |
|
| 680 g_object_unref(model); |
|
| 681 |
|
| 682 grl->model = model; |
|
| 683 grl->tree = tree; |
|
| 684 gtk_widget_show(grl->tree); |
|
| 685 |
|
| 686 renderer = gtk_cell_renderer_text_new(); |
|
| 687 column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, |
|
| 688 "text", NAME_COLUMN, NULL); |
|
| 689 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column), |
|
| 690 GTK_TREE_VIEW_COLUMN_GROW_ONLY); |
|
| 691 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); |
|
| 692 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), NAME_COLUMN); |
|
| 693 gtk_tree_view_column_set_reorderable(GTK_TREE_VIEW_COLUMN(column), TRUE); |
|
| 694 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); |
|
| 695 |
|
| 696 for (j = NUM_OF_COLUMNS, l = fields; l; l = l->next, j++) { |
|
| 697 PurpleRoomlistField *f = l->data; |
|
| 698 |
|
| 699 if (purple_roomlist_field_get_hidden(f)) |
|
| 700 continue; |
|
| 701 |
|
| 702 renderer = gtk_cell_renderer_text_new(); |
|
| 703 column = gtk_tree_view_column_new_with_attributes( |
|
| 704 purple_roomlist_field_get_label(f), renderer, |
|
| 705 "text", j, NULL); |
|
| 706 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column), |
|
| 707 GTK_TREE_VIEW_COLUMN_GROW_ONLY); |
|
| 708 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE); |
|
| 709 gtk_tree_view_column_set_sort_column_id(GTK_TREE_VIEW_COLUMN(column), j); |
|
| 710 gtk_tree_view_column_set_reorderable(GTK_TREE_VIEW_COLUMN(column), TRUE); |
|
| 711 if (purple_roomlist_field_get_field_type(f) == PURPLE_ROOMLIST_FIELD_INT) { |
|
| 712 gtk_tree_view_column_set_cell_data_func(column, renderer, int_cell_data_func, |
|
| 713 GINT_TO_POINTER(j), NULL); |
|
| 714 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(model), j, int_sort_func, |
|
| 715 GINT_TO_POINTER(j), NULL); |
|
| 716 } |
|
| 717 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column); |
|
| 718 } |
|
| 719 |
|
| 720 g_signal_connect(G_OBJECT(tree), "button-press-event", G_CALLBACK(room_click_cb), list); |
|
| 721 g_signal_connect(G_OBJECT(tree), "row-expanded", G_CALLBACK(row_expanded_cb), list); |
|
| 722 g_signal_connect(G_OBJECT(tree), "row-activated", G_CALLBACK(row_activated_cb), list); |
|
| 723 |
|
| 724 gtk_widget_set_has_tooltip(tree, TRUE); |
|
| 725 g_signal_connect(G_OBJECT(tree), "query-tooltip", |
|
| 726 G_CALLBACK(pidgin_roomlist_query_tooltip), list); |
|
| 727 |
|
| 728 /* Enable CTRL+F searching */ |
|
| 729 gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree), NAME_COLUMN); |
|
| 730 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(tree), _search_func, NULL, NULL); |
|
| 731 |
|
| 732 } |
|
| 733 |
|
| 734 static gboolean pidgin_progress_bar_pulse(gpointer data) |
533 static gboolean pidgin_progress_bar_pulse(gpointer data) |
| 735 { |
534 { |
| 736 PurpleRoomlist *list = data; |
535 PurpleRoomlist *list = data; |
| 737 PidginRoomlist *rl = NULL; |
536 PidginRoomlist *rl = NULL; |
| 738 |
537 |
| 747 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(rl->dialog->progress)); |
546 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(rl->dialog->progress)); |
| 748 rl->dialog->pg_needs_pulse = FALSE; |
547 rl->dialog->pg_needs_pulse = FALSE; |
| 749 return TRUE; |
548 return TRUE; |
| 750 } |
549 } |
| 751 |
550 |
| 752 static void pidgin_roomlist_add_room(PurpleRoomlist *list, PurpleRoomlistRoom *room) |
551 static void |
| 753 { |
552 pidgin_roomlist_add_room(PurpleRoomlist *list, PurpleRoomlistRoom *room) { |
| 754 PidginRoomlist *rl = NULL; |
553 PidginRoomlist *rl = NULL; |
| 755 GtkTreeRowReference *rr, *parentrr = NULL; |
|
| 756 GtkTreePath *path; |
554 GtkTreePath *path; |
| 757 GtkTreeIter iter, parent, child; |
555 GtkTreeIter iter; |
| 758 GList *l, *k; |
|
| 759 int j; |
|
| 760 gboolean append = TRUE; |
|
| 761 |
556 |
| 762 rl = g_object_get_data(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA); |
557 rl = g_object_get_data(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA); |
| 763 |
|
| 764 rl->total_rooms++; |
|
| 765 if (purple_roomlist_room_get_room_type(room) == PURPLE_ROOMLIST_ROOMTYPE_ROOM) |
|
| 766 rl->num_rooms++; |
|
| 767 |
558 |
| 768 if (rl->dialog) { |
559 if (rl->dialog) { |
| 769 if (rl->dialog->pg_update_to == 0) { |
560 if (rl->dialog->pg_update_to == 0) { |
| 770 g_object_ref(list); |
561 g_object_ref(list); |
| 771 rl->dialog->pg_update_to = g_timeout_add(100, pidgin_progress_bar_pulse, list); |
562 rl->dialog->pg_update_to = g_timeout_add(100, pidgin_progress_bar_pulse, list); |
| 772 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(rl->dialog->progress)); |
563 gtk_progress_bar_pulse(GTK_PROGRESS_BAR(rl->dialog->progress)); |
| 773 } else |
564 } else |
| 774 rl->dialog->pg_needs_pulse = TRUE; |
565 rl->dialog->pg_needs_pulse = TRUE; |
| 775 } |
566 } |
| 776 |
567 |
| 777 if (purple_roomlist_room_get_parent(room)) { |
568 gtk_tree_store_append(rl->model, &iter, NULL); |
| 778 parentrr = g_hash_table_lookup(rl->cats, purple_roomlist_room_get_parent(room)); |
|
| 779 path = gtk_tree_row_reference_get_path(parentrr); |
|
| 780 if (path) { |
|
| 781 PurpleRoomlistRoom *tmproom = NULL; |
|
| 782 |
|
| 783 gtk_tree_model_get_iter(GTK_TREE_MODEL(rl->model), &parent, path); |
|
| 784 gtk_tree_path_free(path); |
|
| 785 |
|
| 786 if (gtk_tree_model_iter_children(GTK_TREE_MODEL(rl->model), &child, &parent)) { |
|
| 787 gtk_tree_model_get(GTK_TREE_MODEL(rl->model), &child, ROOM_COLUMN, &tmproom, -1); |
|
| 788 if (!tmproom) |
|
| 789 append = FALSE; |
|
| 790 } |
|
| 791 } |
|
| 792 } |
|
| 793 |
|
| 794 if (append) |
|
| 795 gtk_tree_store_append(rl->model, &iter, (parentrr ? &parent : NULL)); |
|
| 796 else |
|
| 797 iter = child; |
|
| 798 |
|
| 799 if (purple_roomlist_room_get_room_type(room) & PURPLE_ROOMLIST_ROOMTYPE_CATEGORY) |
|
| 800 gtk_tree_store_append(rl->model, &child, &iter); |
|
| 801 |
569 |
| 802 path = gtk_tree_model_get_path(GTK_TREE_MODEL(rl->model), &iter); |
570 path = gtk_tree_model_get_path(GTK_TREE_MODEL(rl->model), &iter); |
| 803 |
571 |
| 804 if (purple_roomlist_room_get_room_type(room) & PURPLE_ROOMLIST_ROOMTYPE_CATEGORY) { |
|
| 805 rr = gtk_tree_row_reference_new(GTK_TREE_MODEL(rl->model), path); |
|
| 806 g_hash_table_insert(rl->cats, room, rr); |
|
| 807 } |
|
| 808 |
|
| 809 gtk_tree_path_free(path); |
572 gtk_tree_path_free(path); |
| 810 |
573 |
| 811 gtk_tree_store_set(rl->model, &iter, NAME_COLUMN, purple_roomlist_room_get_name(room), -1); |
574 gtk_tree_store_set( |
| 812 gtk_tree_store_set(rl->model, &iter, ROOM_COLUMN, room, -1); |
575 rl->model, &iter, |
| 813 |
576 ROOM_COLUMN, room, |
| 814 for (j = NUM_OF_COLUMNS, |
577 NAME_COLUMN, purple_roomlist_room_get_name(room), |
| 815 l = purple_roomlist_room_get_fields(room), |
578 DESCRIPTION_COLUMN, purple_roomlist_room_get_description(room), |
| 816 k = purple_roomlist_get_fields(list); |
579 -1); |
| 817 l && k; j++, l = l->next, k = k->next) |
|
| 818 { |
|
| 819 PurpleRoomlistField *f = k->data; |
|
| 820 if (purple_roomlist_field_get_hidden(f)) |
|
| 821 continue; |
|
| 822 gtk_tree_store_set(rl->model, &iter, j, l->data, -1); |
|
| 823 } |
|
| 824 } |
580 } |
| 825 |
581 |
| 826 static void |
582 static void |
| 827 pidgin_roomlist_in_progress(GObject *obj, G_GNUC_UNUSED GParamSpec *pspec, |
583 pidgin_roomlist_in_progress(GObject *obj, G_GNUC_UNUSED GParamSpec *pspec, |
| 828 gpointer data) |
584 gpointer data) |
| 860 PidginRoomlist *rl = g_new0(PidginRoomlist, 1); |
615 PidginRoomlist *rl = g_new0(PidginRoomlist, 1); |
| 861 |
616 |
| 862 g_object_set_data_full(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA, rl, |
617 g_object_set_data_full(G_OBJECT(list), PIDGIN_ROOMLIST_UI_DATA, rl, |
| 863 (GDestroyNotify)pidgin_roomlist_destroy); |
618 (GDestroyNotify)pidgin_roomlist_destroy); |
| 864 |
619 |
| 865 rl->cats = g_hash_table_new_full( |
620 rl->model = gtk_tree_store_new(3, G_TYPE_OBJECT, G_TYPE_STRING, |
| 866 NULL, NULL, NULL, (GDestroyNotify)gtk_tree_row_reference_free); |
621 G_TYPE_STRING); |
| 867 |
622 |
| 868 g_signal_connect(list, "notify::in-progress", |
623 g_signal_connect(list, "notify::in-progress", |
| 869 G_CALLBACK(pidgin_roomlist_in_progress), rl); |
624 G_CALLBACK(pidgin_roomlist_in_progress), rl); |
| 870 } |
625 } |
| 871 |
626 |
| 872 static PurpleRoomlistUiOps ops = { |
627 static PurpleRoomlistUiOps ops = { |
| 873 pidgin_roomlist_dialog_show_with_account, |
628 pidgin_roomlist_dialog_show_with_account, |
| 874 pidgin_roomlist_new, |
629 pidgin_roomlist_new, |
| 875 pidgin_roomlist_set_fields, |
630 NULL, |
| 876 pidgin_roomlist_add_room, |
631 pidgin_roomlist_add_room, |
| 877 NULL, |
632 NULL, |
| 878 NULL, |
633 NULL, |
| 879 NULL, |
634 NULL, |
| 880 NULL |
635 NULL |