| 300 else if (log->type == PURPLE_LOG_SYSTEM) |
305 else if (log->type == PURPLE_LOG_SYSTEM) |
| 301 { |
306 { |
| 302 tmp = g_strdup_printf(_("Are you sure you want to permanently delete the system log " |
307 tmp = g_strdup_printf(_("Are you sure you want to permanently delete the system log " |
| 303 "which started at %s?"), time); |
308 "which started at %s?"), time); |
| 304 } |
309 } |
| 305 else |
310 else { |
| |
311 g_free(time); |
| |
312 g_free(iter); |
| 306 g_return_if_reached(); |
313 g_return_if_reached(); |
| |
314 } |
| 307 |
315 |
| 308 /* The only way to free data in all cases is to tie it to the menuitem with |
316 /* The only way to free data in all cases is to tie it to the menuitem with |
| 309 * g_object_set_data_full(). But, since we need to get some data down to |
317 * g_object_set_data_full(). But, since we need to get some data down to |
| 310 * delete_log_cb() to delete the log from the log viewer after the file is |
318 * delete_log_cb() to delete the log from the log viewer after the file is |
| 311 * deleted, we have to allocate a new data array and make sure it gets freed |
319 * deleted, we have to allocate a new data array and make sure it gets freed |
| 312 * either way. */ |
320 * either way. */ |
| 313 data2 = g_new(gpointer, 3); |
321 data2 = g_new(gpointer, 3); |
| 314 data2[0] = lv->treestore; |
322 data2[0] = lv->treestore; |
| 315 data2[1] = data[3]; /* iter */ |
323 data2[1] = iter; |
| 316 data2[2] = log; |
324 data2[2] = log; |
| 317 purple_request_action(lv, NULL, _("Delete Log?"), tmp, 0, |
325 purple_request_action(lv, NULL, _("Delete Log?"), tmp, 0, |
| 318 NULL, |
326 NULL, |
| 319 data2, 2, |
327 data2, 2, |
| 320 _("Delete"), delete_log_cb, |
328 _("Delete"), delete_log_cb, |
| 321 _("Cancel"), delete_log_cleanup_cb); |
329 _("Cancel"), delete_log_cleanup_cb); |
| |
330 g_free(time); |
| 322 g_free(tmp); |
331 g_free(tmp); |
| 323 } |
332 } |
| 324 |
333 |
| 325 static void log_show_popup_menu(GtkWidget *treeview, GdkEventButton *event, gpointer *data) |
334 static GtkWidget * |
| 326 { |
335 log_create_popup_menu(GtkWidget *treeview, PidginLogViewer *lv, GtkTreeIter *iter) |
| 327 GtkWidget *menu = gtk_menu_new(); |
336 { |
| 328 GtkWidget *menuitem = gtk_menu_item_new_with_label(_("Delete Log...")); |
337 GValue val; |
| 329 |
338 PurpleLog *log; |
| 330 if (!purple_log_is_deletable((PurpleLog *)data[1])) |
339 GtkWidget *menu; |
| |
340 GtkWidget *menuitem; |
| |
341 |
| |
342 val.g_type = 0; |
| |
343 gtk_tree_model_get_value(GTK_TREE_MODEL(lv->treestore), iter, 1, &val); |
| |
344 log = g_value_get_pointer(&val); |
| |
345 if (log == NULL) { |
| |
346 g_free(iter); |
| |
347 return NULL; |
| |
348 } |
| |
349 |
| |
350 menu = gtk_menu_new(); |
| |
351 menuitem = gtk_menu_item_new_with_label(_("Delete Log...")); |
| |
352 |
| |
353 if (purple_log_is_deletable(log)) { |
| |
354 gpointer *data = g_new(gpointer, 3); |
| |
355 data[0] = lv; |
| |
356 data[1] = log; |
| |
357 data[2] = iter; |
| |
358 |
| |
359 g_signal_connect(menuitem, "activate", G_CALLBACK(log_delete_log_cb), data); |
| |
360 g_object_set_data_full(G_OBJECT(menuitem), "log-viewer-data", data, g_free); |
| |
361 } else { |
| 331 gtk_widget_set_sensitive(menuitem, FALSE); |
362 gtk_widget_set_sensitive(menuitem, FALSE); |
| 332 |
363 } |
| 333 g_signal_connect(menuitem, "activate", G_CALLBACK(log_delete_log_cb), data); |
|
| 334 g_object_set_data_full(G_OBJECT(menuitem), "log-viewer-data", data, g_free); |
|
| 335 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); |
364 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); |
| 336 gtk_widget_show_all(menu); |
365 gtk_widget_show_all(menu); |
| 337 |
366 |
| 338 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, (GtkMenuPositionFunc)data[2], NULL, |
367 return menu; |
| 339 (event != NULL) ? event->button : 0, |
|
| 340 gdk_event_get_time((GdkEvent *)event)); |
|
| 341 } |
368 } |
| 342 |
369 |
| 343 static gboolean log_button_press_cb(GtkWidget *treeview, GdkEventButton *event, PidginLogViewer *lv) |
370 static gboolean log_button_press_cb(GtkWidget *treeview, GdkEventButton *event, PidginLogViewer *lv) |
| 344 { |
371 { |
| 345 if (event->type == GDK_BUTTON_PRESS && event->button == 3) |
372 if (gdk_event_triggers_context_menu((GdkEvent *)event)) { |
| 346 { |
|
| 347 GtkTreePath *path; |
373 GtkTreePath *path; |
| 348 GtkTreeIter *iter; |
374 GtkTreeIter *iter; |
| 349 GValue val; |
375 GtkWidget *menu; |
| 350 PurpleLog *log; |
|
| 351 gpointer *data; |
|
| 352 |
376 |
| 353 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), event->x, event->y, &path, NULL, NULL, NULL)) |
377 if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(treeview), event->x, event->y, &path, NULL, NULL, NULL)) |
| 354 return FALSE; |
378 return FALSE; |
| 355 iter = g_new(GtkTreeIter, 1); |
379 iter = g_new(GtkTreeIter, 1); |
| 356 gtk_tree_model_get_iter(GTK_TREE_MODEL(lv->treestore), iter, path); |
380 gtk_tree_model_get_iter(GTK_TREE_MODEL(lv->treestore), iter, path); |
| 357 val.g_type = 0; |
|
| 358 gtk_tree_model_get_value(GTK_TREE_MODEL(lv->treestore), iter, 1, &val); |
|
| 359 gtk_tree_path_free(path); |
381 gtk_tree_path_free(path); |
| 360 |
382 |
| 361 log = g_value_get_pointer(&val); |
383 menu = log_create_popup_menu(treeview, lv, iter); |
| 362 |
384 if (menu) { |
| 363 if (log == NULL) |
385 gtk_menu_popup_at_pointer(GTK_MENU(menu), (GdkEvent *)event); |
| 364 { |
386 return TRUE; |
| 365 g_free(iter); |
387 } else { |
| 366 return FALSE; |
388 return FALSE; |
| 367 } |
389 } |
| 368 |
|
| 369 data = g_new(gpointer, 4); |
|
| 370 data[0] = lv; |
|
| 371 data[1] = log; |
|
| 372 data[2] = NULL; |
|
| 373 data[3] = iter; |
|
| 374 |
|
| 375 log_show_popup_menu(treeview, event, data); |
|
| 376 return TRUE; |
|
| 377 } |
390 } |
| 378 |
391 |
| 379 return FALSE; |
392 return FALSE; |
| 380 } |
393 } |
| 381 |
394 |
| 382 static gboolean log_popup_menu_cb(GtkWidget *treeview, PidginLogViewer *lv) |
395 static gboolean log_popup_menu_cb(GtkWidget *treeview, PidginLogViewer *lv) |
| 383 { |
396 { |
| 384 GtkTreeSelection *sel; |
397 GtkTreeSelection *sel; |
| 385 GtkTreeIter *iter; |
398 GtkTreeIter *iter; |
| 386 GValue val; |
399 GtkWidget *menu; |
| 387 PurpleLog *log; |
|
| 388 gpointer *data; |
|
| 389 |
400 |
| 390 iter = g_new(GtkTreeIter, 1); |
401 iter = g_new(GtkTreeIter, 1); |
| 391 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(lv->treeview)); |
402 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(lv->treeview)); |
| 392 if (!gtk_tree_selection_get_selected(sel, NULL, iter)) |
403 if (!gtk_tree_selection_get_selected(sel, NULL, iter)) { |
| 393 { |
404 g_free(iter); |
| 394 return FALSE; |
405 return FALSE; |
| 395 } |
406 } |
| 396 |
407 |
| 397 val.g_type = 0; |
408 menu = log_create_popup_menu(treeview, lv, iter); |
| 398 gtk_tree_model_get_value(GTK_TREE_MODEL(lv->treestore), |
409 if (menu) { |
| 399 iter, NODE_COLUMN, &val); |
410 pidgin_menu_popup_at_treeview_selection(menu, treeview); |
| 400 |
411 return TRUE; |
| 401 log = g_value_get_pointer(&val); |
412 } else { |
| 402 |
|
| 403 if (log == NULL) |
|
| 404 return FALSE; |
413 return FALSE; |
| 405 |
414 } |
| 406 data = g_new(gpointer, 4); |
|
| 407 data[0] = lv; |
|
| 408 data[1] = log; |
|
| 409 data[2] = pidgin_treeview_popup_menu_position_func; |
|
| 410 data[3] = iter; |
|
| 411 |
|
| 412 log_show_popup_menu(treeview, NULL, data); |
|
| 413 return TRUE; |
|
| 414 } |
415 } |
| 415 |
416 |
| 416 static gboolean search_find_cb(gpointer data) |
417 static gboolean search_find_cb(gpointer data) |
| 417 { |
418 { |
| 418 PidginLogViewer *viewer = data; |
419 PidginLogViewer *viewer = data; |
| 442 return; |
443 return; |
| 443 |
444 |
| 444 pidgin_set_cursor(viewer->window, GDK_WATCH); |
445 pidgin_set_cursor(viewer->window, GDK_WATCH); |
| 445 |
446 |
| 446 if (log->type != PURPLE_LOG_SYSTEM) { |
447 if (log->type != PURPLE_LOG_SYSTEM) { |
| |
448 gchar *log_date = log_get_date(log); |
| 447 char *title; |
449 char *title; |
| 448 if (log->type == PURPLE_LOG_CHAT) |
450 if (log->type == PURPLE_LOG_CHAT) |
| 449 title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation in %s on %s</span>"), |
451 title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation in %s on %s</span>"), |
| 450 log->name, log_get_date(log)); |
452 log->name, log_date); |
| 451 else |
453 else |
| 452 title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation with %s on %s</span>"), |
454 title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation with %s on %s</span>"), |
| 453 log->name, log_get_date(log)); |
455 log->name, log_date); |
| 454 |
456 |
| 455 gtk_label_set_markup(viewer->label, title); |
457 gtk_label_set_markup(viewer->label, title); |
| |
458 g_free(log_date); |
| 456 g_free(title); |
459 g_free(title); |
| 457 } |
460 } |
| 458 |
461 |
| 459 read = purple_log_read(log, &flags); |
462 read = purple_log_read(log, &flags); |
| 460 viewer->flags = flags; |
463 viewer->flags = flags; |
| 490 */ |
493 */ |
| 491 static void populate_log_tree(PidginLogViewer *lv) |
494 static void populate_log_tree(PidginLogViewer *lv) |
| 492 /* Logs are made from trees in real life. |
495 /* Logs are made from trees in real life. |
| 493 This is a tree made from logs */ |
496 This is a tree made from logs */ |
| 494 { |
497 { |
| 495 const char *month; |
498 gchar *month; |
| 496 char prev_top_month[30] = ""; |
499 char prev_top_month[30] = ""; |
| 497 GtkTreeIter toplevel, child; |
500 GtkTreeIter toplevel, child; |
| 498 GList *logs = lv->logs; |
501 GList *logs = lv->logs; |
| 499 |
502 |
| 500 while (logs != NULL) { |
503 while (logs != NULL) { |
| 501 PurpleLog *log = logs->data; |
504 PurpleLog *log = logs->data; |
| 502 |
505 GDateTime *dt; |
| 503 month = purple_utf8_strftime(_("%B %Y"), |
506 gchar *log_date; |
| 504 log->tm ? log->tm : localtime(&log->time)); |
507 |
| 505 |
508 dt = g_date_time_to_local(log->time); |
| 506 if (!purple_strequal(month, prev_top_month)) |
509 month = g_date_time_format(dt, _("%B %Y")); |
| 507 { |
510 |
| |
511 if (!purple_strequal(month, prev_top_month)) { |
| 508 /* top level */ |
512 /* top level */ |
| 509 gtk_tree_store_append(lv->treestore, &toplevel, NULL); |
513 gtk_tree_store_append(lv->treestore, &toplevel, NULL); |
| 510 gtk_tree_store_set(lv->treestore, &toplevel, 0, month, 1, NULL, -1); |
514 gtk_tree_store_set(lv->treestore, &toplevel, 0, month, 1, NULL, -1); |
| 511 |
515 |
| 512 g_strlcpy(prev_top_month, month, sizeof(prev_top_month)); |
516 g_strlcpy(prev_top_month, month, sizeof(prev_top_month)); |
| 513 } |
517 } |
| 514 |
518 |
| 515 /* sub */ |
519 /* sub */ |
| |
520 log_date = g_date_time_format(dt, "%c"); |
| 516 gtk_tree_store_append(lv->treestore, &child, &toplevel); |
521 gtk_tree_store_append(lv->treestore, &child, &toplevel); |
| 517 gtk_tree_store_set(lv->treestore, &child, |
522 gtk_tree_store_set(lv->treestore, &child, |
| 518 0, log_get_date(log), |
523 0, log_date, |
| 519 1, log, |
524 1, log, |
| 520 -1); |
525 -1); |
| 521 |
526 |
| |
527 g_free(log_date); |
| |
528 g_free(month); |
| |
529 g_date_time_unref(dt); |
| 522 logs = logs->next; |
530 logs = logs->next; |
| 523 } |
531 } |
| 524 } |
532 } |
| 525 |
533 |
| 526 static PidginLogViewer *display_log_viewer(struct log_viewer_hash_t *ht, GList *logs, |
534 static PidginLogViewer *display_log_viewer(struct log_viewer_hash_t *ht, GList *logs, |