changeset 10663:241d2e62bed2

[gaim-migrate @ 12202] Richard Laager did this committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Mon, 07 Mar 2005 18:10:45 +0000
parents 54ac161a876e
children 7244386075c6
files ChangeLog src/gtkblist.c src/gtklog.c src/gtklog.h
diffstat 4 files changed, 334 insertions(+), 234 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Mon Mar 07 02:19:09 2005 +0000
+++ b/ChangeLog	Mon Mar 07 18:10:45 2005 +0000
@@ -25,6 +25,8 @@
 	  (Richard Laager)
 	* Ability to set ICQ "require authorization" and "web aware"
 	  setting (Ettore Simone)
+	* Log viewer aggregates logs from the same "Person," (contact, meta-
+	  contact, whatever) (Richard Laager)
 
 	Bug fixes:
 	* People using input methods can now use Enter again.
--- a/src/gtkblist.c	Mon Mar 07 02:19:09 2005 +0000
+++ b/src/gtkblist.c	Mon Mar 07 18:10:45 2005 +0000
@@ -574,6 +574,7 @@
 	GaimLogType type;
 	GaimAccount *account;
 	char *name = NULL;
+
 	if (GAIM_BLIST_NODE_IS_BUDDY(node)) {
 		GaimBuddy *b = (GaimBuddy*) node;
 		type = GAIM_LOG_IM;
@@ -588,6 +589,9 @@
 		if (prpl_info && prpl_info->get_chat_name) {
 			name = prpl_info->get_chat_name(c->components);
 		}
+	} else if (GAIM_BLIST_NODE_IS_CONTACT(node)) {
+		gaim_gtk_log_show_contact((GaimContact *)node);
+		return;
 	} else
 		return;
 
@@ -1156,12 +1160,19 @@
 void
 gaim_gtk_blist_make_buddy_menu(GtkWidget *menu, GaimBuddy *buddy, gboolean sub) {
 	GaimPluginProtocolInfo *prpl_info;
+	GaimContact *contact;
+	gboolean contact_expanded = FALSE;
 
 	g_return_if_fail(menu);
 	g_return_if_fail(buddy);
 
 	prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(buddy->account->gc->prpl);
 
+	contact = gaim_buddy_get_contact(buddy);
+	if (contact) {
+		contact_expanded = ((struct _gaim_gtk_blist_node *)(((GaimBlistNode*)contact)->ui_data))->contact_expanded;
+	}
+
 	if (prpl_info && prpl_info->get_info) {
 		gaim_new_item_from_stock(menu, _("Get _Info"), GAIM_STOCK_INFO,
 				G_CALLBACK(gtk_blist_menu_info_cb), buddy, 0, 0, NULL);
@@ -1180,8 +1191,15 @@
 	}
 	gaim_new_item_from_stock(menu, _("Add Buddy _Pounce"), NULL,
 			G_CALLBACK(gtk_blist_menu_bp_cb), buddy, 0, 0, NULL);
-	gaim_new_item_from_stock(menu, _("View _Log"), NULL,
-			G_CALLBACK(gtk_blist_menu_showlog_cb), buddy, 0, 0, NULL);
+
+	if(((GaimBlistNode*)buddy)->parent->child->next && !sub && !contact_expanded) {
+		gaim_new_item_from_stock(menu, _("View _Log"), NULL,
+				G_CALLBACK(gtk_blist_menu_showlog_cb),
+				contact, 0, 0, NULL);
+	} else if (!sub) {
+		gaim_new_item_from_stock(menu, _("View _Log"), NULL,
+				G_CALLBACK(gtk_blist_menu_showlog_cb), buddy, 0, 0, NULL);
+	}
 
 	gaim_gtk_append_blist_node_proto_menu(menu, buddy->account->gc,
 										  (GaimBlistNode *)buddy);
@@ -1189,17 +1207,17 @@
 
 	gaim_separator(menu);
 
-	if(((GaimBlistNode*)buddy)->parent->child->next && !sub) {
+	if(((GaimBlistNode*)buddy)->parent->child->next && !sub && !contact_expanded) {
 		gaim_new_item_from_stock(menu, _("_Alias Buddy..."), GAIM_STOCK_ALIAS,
 				G_CALLBACK(gtk_blist_menu_alias_cb), buddy, 0, 0, NULL);
 		gaim_new_item_from_stock(menu, _("_Remove Buddy"), GTK_STOCK_REMOVE,
 				G_CALLBACK(gaim_gtk_blist_remove_cb), buddy, 0, 0, NULL);
 		gaim_new_item_from_stock(menu, _("Alias Contact..."), GAIM_STOCK_ALIAS,
 				G_CALLBACK(gtk_blist_menu_alias_cb),
-				gaim_buddy_get_contact(buddy), 0, 0, NULL);
+				contact, 0, 0, NULL);
 		gaim_new_item_from_stock(menu, _("Remove Contact"), GTK_STOCK_REMOVE,
 				G_CALLBACK(gaim_gtk_blist_remove_cb),
-				gaim_buddy_get_contact(buddy), 0, 0, NULL);
+				contact, 0, 0, NULL);
 	} else {
 		gaim_new_item_from_stock(menu, _("_Alias..."), GAIM_STOCK_ALIAS,
 				G_CALLBACK(gtk_blist_menu_alias_cb), buddy, 0, 0, NULL);
@@ -1299,13 +1317,23 @@
 	GtkWidget *menu;
 
 	menu = gtk_menu_new();
+
+	gaim_new_item_from_stock(menu, _("View _Log"), NULL,
+				 G_CALLBACK(gtk_blist_menu_showlog_cb),
+				 node, 0, 0, NULL);
+
+	gaim_separator(menu);
+
 	gaim_new_item_from_stock(menu, _("_Alias..."), GAIM_STOCK_ALIAS,
 				 G_CALLBACK(gtk_blist_menu_alias_cb), node, 0, 0, NULL);
+	gaim_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE,
+				 G_CALLBACK(gaim_gtk_blist_remove_cb), node, 0, 0, NULL);
+
+	gaim_separator(menu);
+
 	gaim_new_item_from_stock(menu, _("_Collapse"), GTK_STOCK_ZOOM_OUT,
 				 G_CALLBACK(gaim_gtk_blist_collapse_contact_cb),
 				 node, 0, 0, NULL);
-	gaim_new_item_from_stock(menu, _("_Remove"), GTK_STOCK_REMOVE,
-				 G_CALLBACK(gaim_gtk_blist_remove_cb), node, 0, 0, NULL);
 
 	gaim_gtk_append_blist_node_extended_menu(menu, node);
 
--- a/src/gtklog.c	Mon Mar 07 02:19:09 2005 +0000
+++ b/src/gtklog.c	Mon Mar 07 18:10:45 2005 +0000
@@ -39,18 +39,24 @@
 static GaimGtkLogViewer *syslog_viewer = NULL;
 
 struct log_viewer_hash_t {
+	GaimLogType type;
 	char *screenname;
 	GaimAccount *account;
+	GaimContact *contact;
 };
 
 static guint log_viewer_hash(gconstpointer data)
 {
 	const struct log_viewer_hash_t *viewer = data;
-	return g_str_hash(viewer->screenname) + g_str_hash(gaim_account_get_username(viewer->account));
 
+	if (viewer->contact != NULL)
+		return g_direct_hash(viewer->contact);
+
+	return g_str_hash(viewer->screenname) +
+		g_str_hash(gaim_account_get_username(viewer->account));
 }
 
-static gint log_viewer_equal(gconstpointer y, gconstpointer z)
+static gboolean log_viewer_equal(gconstpointer y, gconstpointer z)
 {
 	const struct log_viewer_hash_t *a, *b;
 	int ret;
@@ -59,10 +65,21 @@
 	a = y;
 	b = z;
 
+	if (a->contact != NULL) {
+		if (b->contact != NULL)
+			return (a->contact == b->contact);
+		else
+			return FALSE;
+	} else {
+		if (b->contact != NULL)
+			return FALSE;
+	}
+
 	normal = g_strdup(gaim_normalize(a->account, a->screenname));
 	ret = (a->account == b->account) &&
 		!strcmp(normal, gaim_normalize(b->account, b->screenname));
 	g_free(normal);
+
 	return ret;
 }
 
@@ -72,7 +89,7 @@
 	GList *logs;
 	GdkCursor *cursor = gdk_cursor_new(GDK_WATCH);
 
-	if (lv->search)
+	if (lv->search != NULL)
 		g_free(lv->search);
 
        	gtk_tree_store_clear(lv->treestore);
@@ -118,49 +135,43 @@
 static gboolean destroy_cb(GtkWidget *w, gint resp, struct log_viewer_hash_t *ht) {
 	GaimGtkLogViewer *lv = syslog_viewer;
 
-	if(ht != NULL){
+	if (ht != NULL) {
 		lv = g_hash_table_lookup(log_viewers, ht);
 		g_hash_table_remove(log_viewers, ht);
-		g_free(ht->screenname);
+
+		if (ht->screenname != NULL)
+			g_free(ht->screenname);
+
 		g_free(ht);
 	} else
 		syslog_viewer = NULL;
 
-	while (lv->logs) {
-		GaimLog *log = lv->logs->data;
+	while (lv->logs != NULL) {
 		GList *logs2;
-		gaim_log_free(log);
+
+		gaim_log_free((GaimLog *)lv->logs->data);
+
 		logs2 = lv->logs->next;
 		g_list_free_1(lv->logs);
 		lv->logs = logs2;
 	}
-	if (lv->search)
+
+	if (lv->search != NULL)
 		g_free(lv->search);
+
 	g_free(lv);
 	gtk_widget_destroy(w);
 
 	return TRUE;
 }
-#if 0
-static gboolean destroy_syslog_cb(GtkWidget *w, gint resp, void *cb)
-{
-	while (syslog_viewer->logs) {
-		GaimLog *log = syslog_viewer->logs->data;
-		GList *logs2;
-		gaim_log_free(log);
-		logs2 = syslog_viewer->logs->next;
-		g_list_free_1(syslog_viewer->logs);
-		syslog_viewer->logs = logs2;
-	}
-	if (syslog_viewer->search)
-		g_free(syslog_viewer->search);
-	g_free(syslog_viewer);
-	syslog_viewer = NULL;
-	gtk_widget_destroy(w);
 
-	return TRUE;
+static void log_row_activated_cb(GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, GaimGtkLogViewer *viewer) {
+	if (gtk_tree_view_row_expanded(tv, path))
+		gtk_tree_view_collapse_row(tv, path);
+	else
+		gtk_tree_view_expand_row(tv, path, FALSE);
 }
-#endif
+
 static void log_select_cb(GtkTreeSelection *sel, GaimGtkLogViewer *viewer) {
 	GtkTreeIter   iter;
 	GValue val = { 0, };
@@ -170,26 +181,39 @@
 	char *read = NULL;
 	char time[64];
 
-	char *title;
-	char *title_utf8; /* temporary variable for utf8 conversion */
-
-	if (! gtk_tree_selection_get_selected (sel, &model, &iter))
+	if (!gtk_tree_selection_get_selected(sel, &model, &iter))
 		return;
 	gtk_tree_model_get_value (model, &iter, 1, &val);
 	log = g_value_get_pointer(&val);
 	g_value_unset(&val);
 
-	if (!log)
+	if (log == NULL)
 		return;
 
+	if (log->type != GAIM_LOG_SYSTEM) {
+		char *title;
+		char *title_utf8; /* temporary variable for utf8 conversion */
+
+		gaim_strftime(time, sizeof(time), "%c", localtime(&log->time));
+
+		if (log->type == GAIM_LOG_CHAT)
+			title = g_strdup_printf(_("Conversation in %s on %s"), log->name, time);
+		else
+			title = g_strdup_printf(_("Conversation with %s on %s"), log->name, time);
+
+		title_utf8 = gaim_utf8_try_convert(title);
+		g_free(title);
+
+		title = g_strdup_printf("<span size='larger' weight='bold'>%s</span>", title_utf8);
+		g_free(title_utf8);
+
+		gtk_label_set_markup(GTK_LABEL(viewer->label), title);
+		g_free(title);
+	}
+
 	read = gaim_log_read(log, &flags);
 	viewer->flags = flags;
-	gaim_strftime(time, sizeof(time), "%c", localtime(&log->time));
-	title = g_strdup_printf("%s - %s", log->name, time);
-	title_utf8 = gaim_utf8_try_convert(title);
-	g_free(title);
-	title = title_utf8;
-	gtk_window_set_title(GTK_WINDOW(viewer->window), title);
+
 	gtk_imhtml_clear(GTK_IMHTML(viewer->imhtml));
 	gtk_imhtml_set_protocol_name(GTK_IMHTML(viewer->imhtml),
 	                            gaim_account_get_protocol_name(log->account));
@@ -197,14 +221,12 @@
 			       GTK_IMHTML_NO_COMMENTS | GTK_IMHTML_NO_TITLE | GTK_IMHTML_NO_SCROLL |
 			       ((flags & GAIM_LOG_READ_NO_NEWLINE) ? GTK_IMHTML_NO_NEWLINE : 0));
 
-	if (viewer->search)
-	{
+	if (viewer->search != NULL) {
 		gtk_imhtml_search_clear(GTK_IMHTML(viewer->imhtml));
 		gtk_imhtml_search_find(GTK_IMHTML(viewer->imhtml), viewer->search);
 	}
 
 	g_free(read);
-	g_free(title);
 }
 
 /* I want to make this smarter, but haven't come up with a cool algorithm to do so, yet.
@@ -219,11 +241,12 @@
 {
 	char month[30];
 	char title[64];
-	char prev_top_month[30];
+	char prev_top_month[30] = "";
 	char *utf8_tmp; /* temporary variable for utf8 conversion */
 	GtkTreeIter toplevel, child;
 	GList *logs = lv->logs;
-	while (logs) {
+
+	while (logs != NULL) {
 		GaimLog *log = logs->data;
 
 		gaim_strftime(month, sizeof(month), "%B %Y", localtime(&log->time));
@@ -256,36 +279,21 @@
 	}
 }
 
-void gaim_gtk_log_show(GaimLogType type, const char *screenname, GaimAccount *account) {
-	/* if (log_viewers && g_hash_table */
-	GtkWidget *hbox, *vbox;
-	GdkPixbuf *pixbuf, *scale;
-	GtkCellRenderer *rend;
-	GtkTreeViewColumn *col;
-	GaimGtkLogViewer *lv = NULL;
-	GtkTreeSelection *sel;
-	GtkWidget *icon, *label, *pane, *sw, *button, *frame;
-	GList *logs;
-	char *text ,*ttext;
-	struct log_viewer_hash_t *ht = g_new0(struct log_viewer_hash_t, 1);
-
-	ht->screenname = g_strdup(screenname);
-	ht->account = account;
-
-	if (!log_viewers) {
-		log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal);
-	} else if ((lv = g_hash_table_lookup(log_viewers, ht))) {
-		gtk_window_present(GTK_WINDOW(lv->window));
-		g_free(ht);
-		return;
-	}
+static GaimGtkLogViewer *display_log_viewer(struct log_viewer_hash_t *ht, GList *logs,
+						const char *title, GdkPixbuf *pixbuf)
+{
+	GaimGtkLogViewer *lv;
+	GtkWidget *title_box;
+	char *text;
 
 	lv = g_new0(GaimGtkLogViewer, 1);
-	lv->logs = logs = gaim_log_get_logs(type, screenname, account);
-	g_hash_table_insert(log_viewers, ht, lv);
+	lv->logs = logs;
+
+	if (ht != NULL)
+		g_hash_table_insert(log_viewers, ht, lv);
 
 	/* Window ***********/
-	lv->window = gtk_dialog_new_with_buttons(screenname, NULL, 0,
+	lv->window = gtk_dialog_new_with_buttons(title, NULL, 0,
 					     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
 	gtk_container_set_border_width (GTK_CONTAINER(lv->window), 6);
 	gtk_dialog_set_has_separator(GTK_DIALOG(lv->window), FALSE);
@@ -293,181 +301,242 @@
 	g_signal_connect(G_OBJECT(lv->window), "response",
 					 G_CALLBACK(destroy_cb), ht);
 
-	hbox = gtk_hbox_new(FALSE, 6);
-	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
-	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), hbox, FALSE, FALSE, 0);
+	/* Icon *************/
+	if (pixbuf != NULL) {
+		GdkPixbuf *scale;
+		GtkWidget *icon;
 
-	/* Icon *************/
-	pixbuf = create_prpl_icon(account);
-	scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR);
-	icon = gtk_image_new_from_pixbuf(scale);
-	gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0);
-	g_object_unref(G_OBJECT(pixbuf));
-	g_object_unref(G_OBJECT(scale));
+		title_box = gtk_hbox_new(FALSE, 6);
+		gtk_container_set_border_width(GTK_CONTAINER(title_box), 6);
+		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), title_box, FALSE, FALSE, 0);
+
+		scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR);
+		icon = gtk_image_new_from_pixbuf(scale);
+		gtk_box_pack_start(GTK_BOX(title_box), icon, FALSE, FALSE, 0);
+		g_object_unref(G_OBJECT(pixbuf));
+		g_object_unref(G_OBJECT(scale));
+	} else
+		title_box = GTK_DIALOG(lv->window)->vbox;
 
 	/* Label ************/
-	label = gtk_label_new(NULL);
+	lv->label = gtk_label_new(NULL);
+
+	text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>", title);
 
-	ttext = g_strdup_printf(_("Conversations with %s"), screenname);
-	text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>",ttext);
-	g_free(ttext);
-
-	gtk_label_set_markup(GTK_LABEL(label), text);
-	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	gtk_label_set_markup(GTK_LABEL(lv->label), text);
+	gtk_misc_set_alignment(GTK_MISC(lv->label), 0, 0);
+	gtk_box_pack_start(GTK_BOX(title_box), lv->label, FALSE, FALSE, 0);
 	g_free(text);
 
-	/* Pane *************/
-	pane = gtk_hpaned_new();
-	gtk_container_set_border_width(GTK_CONTAINER(pane), 6);
-	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), pane, TRUE, TRUE, 0);
+	if (logs != NULL) {
+		GtkWidget *pane;
+		GtkWidget *sw;
+		GtkCellRenderer *rend;
+		GtkTreeViewColumn *col;
+		GtkTreeSelection *sel;
+		GtkWidget *vbox;
+		GtkWidget *frame;
+		GtkWidget *hbox;
+		GtkWidget *button;
 
-	/* List *************/
-	sw = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-	gtk_paned_add1(GTK_PANED(pane), sw);
-	lv->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
-	lv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (lv->treestore));
-	rend = gtk_cell_renderer_text_new();
-	col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL);
-	gtk_tree_view_append_column (GTK_TREE_VIEW(lv->treeview), col);
-	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (lv->treeview), FALSE);
-	gtk_container_add (GTK_CONTAINER (sw), lv->treeview);
-	populate_log_tree(lv);
+		/* Pane *************/
+		pane = gtk_hpaned_new();
+		gtk_container_set_border_width(GTK_CONTAINER(pane), 6);
+		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), pane, TRUE, TRUE, 0);
 
-	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (lv->treeview));
-	g_signal_connect (G_OBJECT (sel), "changed",
-			  G_CALLBACK (log_select_cb),
-			  lv);
-	gaim_set_accessible_label(lv->treeview, label);
-
-	/* A fancy little box ************/
-	vbox = gtk_vbox_new(FALSE, 6);
-	gtk_paned_add2(GTK_PANED(pane), vbox);
+		/* List *************/
+		sw = gtk_scrolled_window_new (NULL, NULL);
+		gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
+		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+		gtk_paned_add1(GTK_PANED(pane), sw);
+		lv->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
+		lv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (lv->treestore));
+		rend = gtk_cell_renderer_text_new();
+		col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL);
+		gtk_tree_view_append_column (GTK_TREE_VIEW(lv->treeview), col);
+		gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (lv->treeview), FALSE);
+		gtk_container_add (GTK_CONTAINER (sw), lv->treeview);
+	
+		populate_log_tree(lv);
+	
+		sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (lv->treeview));
+		g_signal_connect (G_OBJECT (sel), "changed",
+				G_CALLBACK (log_select_cb),
+				lv);
+		g_signal_connect (G_OBJECT(lv->treeview), "row-activated",
+				G_CALLBACK(log_row_activated_cb),
+				lv);
+		gaim_set_accessible_label(lv->treeview, lv->label);
+	
+		/* A fancy little box ************/
+		vbox = gtk_vbox_new(FALSE, 6);
+		gtk_paned_add2(GTK_PANED(pane), vbox);
+	
+		/* Viewer ************/
+		frame = gaim_gtk_create_imhtml(FALSE, &lv->imhtml, NULL);
+		gtk_widget_set_name(lv->imhtml, "gaim_gtklog_imhtml");
+		gtk_widget_set_size_request(lv->imhtml, 320, 200);
+		gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
+		gtk_widget_show(frame);
+	
+		/* Search box **********/
+		hbox = gtk_hbox_new(FALSE, 6);
+		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
+		lv->entry = gtk_entry_new();
+		gtk_box_pack_start(GTK_BOX(hbox), lv->entry, TRUE, TRUE, 0);
+		button = gtk_button_new_from_stock(GTK_STOCK_FIND);
+		gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
+		g_signal_connect(GTK_ENTRY(lv->entry), "activate", G_CALLBACK(search_cb), lv);
+		g_signal_connect(GTK_BUTTON(button), "activate", G_CALLBACK(search_cb), lv);
+		g_signal_connect(GTK_BUTTON(button), "clicked", G_CALLBACK(search_cb), lv);
+	} else {
+		/* No logs were found. */
+		const char *log_preferences = NULL;
+  GtkWidget *label;
 
-	/* Viewer ************/
-	frame = gaim_gtk_create_imhtml(FALSE, &lv->imhtml, NULL);
-	gtk_widget_set_name(lv->imhtml, "gaim_gtklog_imhtml");
-	gtk_widget_set_size_request(lv->imhtml, 320, 200);
-	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
-	gtk_widget_show(frame);
+		if (ht == NULL) {
+			if (!gaim_prefs_get_bool("/core/logging/log_system"))
+				log_preferences = _("System events will only be logged if the <span style=\"italic\">Enable system log preference</span> is set.");
+		} else {
+			if (ht->type == GAIM_LOG_IM) {
+				if (!gaim_prefs_get_bool("/core/logging/log_ims"))
+					log_preferences = _("Instant messages will only be logged if the <span style=\"italic\">Log all instant messages</span> preference is enabled.");
+			} else if (ht->type == GAIM_LOG_CHAT) {
+				if (!gaim_prefs_get_bool("/core/logging/log_chats"))
+					log_preferences = _("Chats will only be logged if the <span style=\"italic\">Log all chats preference</span> is enabled.");
+			}
+		}
 
-	/* Search box **********/
-	hbox = gtk_hbox_new(FALSE, 6);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-	lv->entry = gtk_entry_new();
-	gtk_box_pack_start(GTK_BOX(hbox), lv->entry, TRUE, TRUE, 0);
-	button = gtk_button_new_from_stock(GTK_STOCK_FIND);
-	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-	g_signal_connect(GTK_ENTRY(lv->entry), "activate", G_CALLBACK(search_cb), lv);
-	g_signal_connect(GTK_BUTTON(button), "activate", G_CALLBACK(search_cb), lv);
-	g_signal_connect(GTK_BUTTON(button), "clicked", G_CALLBACK(search_cb), lv);
+		text = g_strdup_printf("\n<span weight=\"bold\">%s</span>%s%s\n",
+				_("No logs were found."),
+				log_preferences ? "\n" : "",
+				log_preferences ? log_preferences : "");
+
+		label = gtk_label_new(NULL);
+
+		gtk_label_set_markup(GTK_LABEL(label), text);
+		gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+		gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), label, FALSE, FALSE, 0);
+		g_free(text);
+	}
 
 	gtk_widget_show_all(lv->window);
+
+	return lv;
+}
+
+void gaim_gtk_log_show(GaimLogType type, const char *screenname, GaimAccount *account) {
+	struct log_viewer_hash_t *ht = g_new0(struct log_viewer_hash_t, 1);
+	GaimGtkLogViewer *lv = NULL;
+	const char *name = screenname;
+	char *title;
+
+	g_return_if_fail(account != NULL);
+	g_return_if_fail(screenname != NULL);
+
+	ht->type = type;
+	ht->screenname = g_strdup(screenname);
+	ht->account = account;
+
+	if (log_viewers == NULL) {
+		log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal);
+	} else if ((lv = g_hash_table_lookup(log_viewers, ht))) {
+		gtk_window_present(GTK_WINDOW(lv->window));
+		g_free(ht);
+		return;
+	}
+
+	if (type == GAIM_LOG_CHAT) {
+		GaimChat *chat;
+
+		chat = gaim_blist_find_chat(account, screenname);
+		if (chat != NULL)
+			name = gaim_chat_get_name(chat);
+
+		title = g_strdup_printf(_("Conversations in %s"), name);
+	} else {
+		GaimBuddy *buddy;
+
+		buddy = gaim_find_buddy(account, screenname);
+		if (buddy != NULL)
+			name = gaim_buddy_get_contact_alias(buddy);
+
+		title = g_strdup_printf(_("Conversations with %s"), name);
+	}
+
+	display_log_viewer(ht, gaim_log_get_logs(type, screenname, account),
+			title, create_prpl_icon(account));
+	g_free(title);
+}
+
+void gaim_gtk_log_show_contact(GaimContact *contact) {
+	struct log_viewer_hash_t *ht = g_new0(struct log_viewer_hash_t, 1);
+	GaimBlistNode *child;
+	GaimGtkLogViewer *lv = NULL;
+	GList *logs = NULL;
+	char *filename;
+	GdkPixbuf *pixbuf;
+	const char *name = NULL;
+	char *title;
+
+	g_return_if_fail(contact != NULL);
+
+	ht->type = GAIM_LOG_IM;
+	ht->contact = contact;
+
+	if (log_viewers == NULL) {
+		log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal);
+	} else if ((lv = g_hash_table_lookup(log_viewers, ht))) {
+		gtk_window_present(GTK_WINDOW(lv->window));
+		g_free(ht);
+		return;
+	}
+
+	for (child = contact->node.child ; child ; child = child->next) {
+		if (!GAIM_BLIST_NODE_IS_BUDDY(child))
+			continue;
+
+		logs = g_list_concat(logs,
+			gaim_log_get_logs(GAIM_LOG_IM, ((GaimBuddy *)child)->name,
+						((GaimBuddy *)child)->account));
+	}
+	logs = g_list_sort(logs, gaim_log_compare);
+
+	filename = g_build_filename(DATADIR, "pixmaps", "gaim", "icons", "online.png", NULL);
+	pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
+	g_free(filename);
+
+	if (contact->alias != NULL)
+		name = contact->alias;
+	else if (contact->priority != NULL)
+		name = gaim_buddy_get_contact_alias(contact->priority);
+
+	title = g_strdup_printf(_("Conversations with %s"), name);
+	display_log_viewer(ht, logs, title, pixbuf);
+	g_free(title);
 }
 
 void gaim_gtk_syslog_show()
 {
-	GtkWidget *hbox, *vbox;
-	GtkCellRenderer *rend;
-	GtkTreeViewColumn *col;
-	GtkTreeSelection *sel;
-	GtkWidget *label, *pane, *sw, *button, *frame;
-	char *text;
 	GList *accounts = NULL;
+	GList *logs = NULL;
 
 	if (syslog_viewer != NULL) {
 		gtk_window_present(GTK_WINDOW(syslog_viewer->window));
 		return;
 	}
 
-	syslog_viewer = g_new0(GaimGtkLogViewer, 1);
+	for(accounts = gaim_accounts_get_all(); accounts != NULL; accounts = accounts->next) {
 
-	for(accounts = gaim_accounts_get_all(); accounts != NULL;
-		accounts = accounts->next) {
-		GList *logs;
 		GaimAccount *account = (GaimAccount *)accounts->data;
-		if(!gaim_find_prpl(gaim_account_get_protocol_id(account)))
+		if(gaim_find_prpl(gaim_account_get_protocol_id(account)) == NULL)
 			continue;
 
 		logs = gaim_log_get_system_logs(account);
-		syslog_viewer->logs = g_list_concat(syslog_viewer->logs, logs);
+		logs = g_list_concat(logs, gaim_log_get_system_logs(account));
 	}
-	syslog_viewer->logs = g_list_sort(syslog_viewer->logs, gaim_log_compare);
-
-	/* Window ***********/
-	syslog_viewer->window = gtk_dialog_new_with_buttons(_("System Log"), NULL, 0,
-						 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
-	gtk_container_set_border_width (GTK_CONTAINER(syslog_viewer->window), 6);
-	gtk_dialog_set_has_separator(GTK_DIALOG(syslog_viewer->window), FALSE);
-	gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(syslog_viewer->window)->vbox), 0);
-	g_signal_connect(G_OBJECT(syslog_viewer->window), "response",
-					 G_CALLBACK(destroy_cb), NULL);
-
-	hbox = gtk_hbox_new(FALSE, 6);
-	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
-	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(syslog_viewer->window)->vbox), hbox,
-					   FALSE, FALSE, 0);
-
-	/* Label ************/
-	label = gtk_label_new(NULL);
-	text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>",
-						   _("System Log"));
-	gtk_label_set_markup(GTK_LABEL(label), text);
-	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
-	g_free(text);
-
-	/* Pane *************/
-	pane = gtk_hpaned_new();
-	gtk_container_set_border_width(GTK_CONTAINER(pane), 6);
-	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(syslog_viewer->window)->vbox), pane,
-					   TRUE, TRUE, 0);
+	logs = g_list_sort(logs, gaim_log_compare);
 
-	/* List *************/
-	sw = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
-	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-	gtk_paned_add1(GTK_PANED(pane), sw);
-	syslog_viewer->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
-	syslog_viewer->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (syslog_viewer->treestore));
-	rend = gtk_cell_renderer_text_new();
-	col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL);
-	gtk_tree_view_append_column (GTK_TREE_VIEW(syslog_viewer->treeview), col);
-	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (syslog_viewer->treeview), FALSE);
-	gtk_container_add (GTK_CONTAINER (sw), syslog_viewer->treeview);
-
-	gtk_widget_set_size_request(syslog_viewer->treeview, 170, 200);
-	populate_log_tree(syslog_viewer);
-
-	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (syslog_viewer->treeview));
-	g_signal_connect (G_OBJECT (sel), "changed",
-			  G_CALLBACK (log_select_cb),
-			  syslog_viewer);
-
-	/* A fancy little box ************/
-	vbox = gtk_vbox_new(FALSE, 6);
-	gtk_paned_add2(GTK_PANED(pane), vbox);
-
-	/* Viewer ************/
-	frame = gaim_gtk_create_imhtml(FALSE, &syslog_viewer->imhtml, NULL);
-	gtk_widget_set_name(syslog_viewer->imhtml, "gaim_gtklog_imhtml");
-	gtk_widget_set_size_request(syslog_viewer->imhtml, 400, 200);
-	gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
-	gtk_widget_show(frame);
-
-	/* Search box **********/
-	hbox = gtk_hbox_new(FALSE, 6);
-	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
-	syslog_viewer->entry = gtk_entry_new();
-	gtk_box_pack_start(GTK_BOX(hbox), syslog_viewer->entry, TRUE, TRUE, 0);
-	button = gtk_button_new_from_stock(GTK_STOCK_FIND);
-	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
-	g_signal_connect(GTK_ENTRY(syslog_viewer->entry), "activate",
-					 G_CALLBACK(search_cb), syslog_viewer);
-	g_signal_connect(GTK_BUTTON(button), "activate",
-					 G_CALLBACK(search_cb), syslog_viewer);
-	g_signal_connect(GTK_BUTTON(button), "clicked",
-					 G_CALLBACK(search_cb), syslog_viewer);
-
-	gtk_widget_show_all(syslog_viewer->window);
+	syslog_viewer = display_log_viewer(NULL, logs, _("System Log"), NULL);
 }
--- a/src/gtklog.h	Mon Mar 07 02:19:09 2005 +0000
+++ b/src/gtklog.h	Mon Mar 07 18:10:45 2005 +0000
@@ -34,21 +34,22 @@
  * A GTK+ Log Viewer.  You can look at logs with it.
  */
 struct _GaimGtkLogViewer {
-	GList *logs;               /**< The list of logs viewed in this viewer   */
-	
-	GtkWidget    *window;      /**< The viewer's window                      */
-	GtkTreeStore *treestore;   /**< The treestore containing said logs       */
-	GtkWidget    *treeview;    /**< The treeview representing said treestore */
-	GtkWidget    *imhtml;      /**< The imhtml to display said logs, which were said
-				    *   before said treestore was said */
-	GtkWidget    *entry;       /**< The search entry, in which search terms are
-				    *   entered                                  */
-	GaimLogReadFlags flags;     /**< The most recently used log flags         */
-	char *search;              /**< The string currently being searched for */
+	GList *logs;                 /**< The list of logs viewed in this viewer   */
+
+	GtkWidget        *window;    /**< The viewer's window                      */
+	GtkTreeStore     *treestore; /**< The treestore containing said logs       */
+	GtkWidget        *treeview;  /**< The treeview representing said treestore */
+	GtkWidget        *imhtml;    /**< The imhtml to display said logs          */
+	GtkWidget        *entry;     /**< The search entry, in which search terms
+	                              *   are entered                              */
+	GaimLogReadFlags flags;      /**< The most recently used log flags         */
+	char             *search;    /**< The string currently being searched for  */
+	GtkWidget        *label;     /**< The label at the top of the log viewer   */
 };
 
 
 
 void gaim_gtk_log_show(GaimLogType type, const char *screenname, GaimAccount *account);
+void gaim_gtk_log_show_contact(GaimContact *contact);
 
 void gaim_gtk_syslog_show();