Mercurial > pidgin
annotate src/gtklog.c @ 7786:203a18e56dc6
[gaim-migrate @ 8431]
* Documentation is good. Not that I have any idea if any of my
documentation works, because I haven't checked... I totally made up
@note, but it sure seems reasonable to me.
* A couple of stringref utility functions which seem useful in any
case, like len and cmp.
* I'm going ahead and pushing a stringref creation function which
creates a zero-refcount stringref into CVS... Nothing uses it yet,
but I think that it is useful even in the absence of major stringref
conversion ... because it's garbage collected! If no one refs it
before the next iteration of the mainloop, it will be freed ... if
it is ref'd, of course, it will have to be freed normally by an
unref at some later point.
committer: Tailor Script <tailor@pidgin.im>
author | Ethan Blanton <elb@pidgin.im> |
---|---|
date | Sun, 07 Dec 2003 16:28:34 +0000 |
parents | 9e122b8f564f |
children | fa6395637e2c |
rev | line source |
---|---|
7432 | 1 /** |
2 * @file gtklog.c GTK+ Log viewer | |
3 * @ingroup gtkui | |
4 * | |
5 * gaim | |
6 * | |
7 * Copyright (C) 2003 Error of Ruto | |
7537
083427fd8ba8
[gaim-migrate @ 8150]
Christian Hammond <chipx86@chipx86.com>
parents:
7535
diff
changeset
|
8 * |
7432 | 9 * This program is free software; you can redistribute it and/or modify |
10 * it under the terms of the GNU General Public License as published by | |
11 * the Free Software Foundation; either version 2 of the License, or | |
12 * (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU General Public License | |
20 * along with this program; if not, write to the Free Software | |
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 */ | |
23 | |
24 #include "gtkinternal.h" | |
25 | |
26 #include "account.h" | |
27 #include "util.h" | |
28 #include "gtkblist.h" | |
29 #include "gtkimhtml.h" | |
30 #include "gtklog.h" | |
31 #include "gtkutils.h" | |
32 #include "log.h" | |
33 | |
34 static GHashTable *log_viewers = NULL; | |
7535 | 35 static void populate_log_tree(GaimGtkLogViewer *lv); |
7432 | 36 |
37 struct log_viewer_hash_t { | |
38 char *screenname; | |
39 GaimAccount *account; | |
40 }; | |
41 | |
7440 | 42 static guint log_viewer_hash(gconstpointer data) |
7432 | 43 { |
7440 | 44 const struct log_viewer_hash_t *viewer = data; |
7432 | 45 return g_str_hash(viewer->screenname) + g_str_hash(gaim_account_get_username(viewer->account)); |
7440 | 46 |
7432 | 47 } |
48 | |
7440 | 49 static gint log_viewer_equal(gconstpointer y, gconstpointer z) |
7432 | 50 { |
7440 | 51 const struct log_viewer_hash_t *a, *b; |
7432 | 52 int ret; |
7440 | 53 char *normal; |
54 | |
55 a = y; | |
56 b = z; | |
57 | |
58 normal = g_strdup(gaim_normalize(a->account, a->screenname)); | |
59 ret = (a->account == b->account) && | |
60 !strcmp(normal, gaim_normalize(b->account, b->screenname)); | |
7432 | 61 g_free(normal); |
62 return ret; | |
63 } | |
64 | |
7535 | 65 static void search_cb(GtkWidget *button, GaimGtkLogViewer *lv) |
66 { | |
67 const char *search_term = gtk_entry_get_text(GTK_ENTRY(lv->entry)); | |
68 GList *logs; | |
69 GdkCursor *cursor = gdk_cursor_new(GDK_WATCH); | |
70 | |
71 if (lv->search) | |
72 g_free(lv->search); | |
73 | |
74 gtk_tree_store_clear(lv->treestore); | |
75 if (strlen(search_term) == 0) {/* reset the tree */ | |
76 populate_log_tree(lv); | |
77 lv->search = NULL; | |
7537
083427fd8ba8
[gaim-migrate @ 8150]
Christian Hammond <chipx86@chipx86.com>
parents:
7535
diff
changeset
|
78 gtk_imhtml_search_clear(GTK_IMHTML(lv->imhtml)); |
7535 | 79 return; |
80 } | |
81 | |
82 lv->search = g_strdup(search_term); | |
83 | |
84 gdk_window_set_cursor(lv->window->window, cursor); | |
85 while (gtk_events_pending()) | |
86 gtk_main_iteration(); | |
87 gdk_cursor_unref(cursor); | |
88 | |
89 for (logs = lv->logs; logs != NULL; logs = logs->next) { | |
90 char *read = gaim_log_read((GaimLog*)logs->data, NULL); | |
91 if (gaim_strcasestr(read, search_term)) { | |
92 GtkTreeIter iter; | |
93 GaimLog *log = logs->data; | |
94 char title[64]; | |
7676 | 95 char *title_utf8; /* temporary variable for utf8 conversion */ |
7535 | 96 strftime(title, sizeof(title), "%c", localtime(&log->time)); |
7676 | 97 title_utf8 = gaim_utf8_try_convert(title); |
98 strncpy(title, title_utf8, sizeof(title)); | |
99 g_free(title_utf8); | |
7535 | 100 gtk_tree_store_append (lv->treestore, &iter, NULL); |
101 gtk_tree_store_set(lv->treestore, &iter, | |
102 0, title, | |
103 1, log, -1); | |
104 } | |
105 } | |
106 | |
107 | |
108 cursor = gdk_cursor_new(GDK_LEFT_PTR); | |
109 gdk_window_set_cursor(lv->window->window, cursor); | |
110 gdk_cursor_unref(cursor); | |
111 } | |
112 | |
7454 | 113 static gboolean destroy_cb(GtkWidget *w, gint resp, struct log_viewer_hash_t *ht) { |
114 GaimGtkLogViewer *lv = g_hash_table_lookup(log_viewers, ht); | |
115 | |
116 g_hash_table_remove(log_viewers, ht); | |
117 g_free(ht->screenname); | |
118 g_free(ht); | |
7535 | 119 while (lv->logs) { |
7533 | 120 GaimLog *log = lv->logs->data; |
7535 | 121 GList *logs2; |
7685 | 122 gaim_log_free(log); |
7535 | 123 logs2 = lv->logs->next; |
124 g_list_free_1(lv->logs); | |
125 lv->logs = logs2; | |
7533 | 126 } |
7535 | 127 if (lv->search) |
128 g_free(lv->search); | |
7533 | 129 g_free(lv); |
7454 | 130 gtk_widget_destroy(w); |
131 | |
132 return TRUE; | |
133 } | |
134 | |
135 static void log_select_cb(GtkTreeSelection *sel, GaimGtkLogViewer *viewer) { | |
7432 | 136 GtkTreeIter iter; |
137 GValue val = { 0, }; | |
138 GtkTreeModel *model = GTK_TREE_MODEL(viewer->treestore); | |
139 GaimLog *log = NULL; | |
140 GaimLogReadFlags flags; | |
141 char *read = NULL; | |
142 char time[64]; | |
143 | |
144 char *title; | |
7676 | 145 char *title_utf8; /* temporary variable for utf8 conversion */ |
7432 | 146 |
147 if (! gtk_tree_selection_get_selected (sel, &model, &iter)) | |
148 return; | |
149 gtk_tree_model_get_value (model, &iter, 1, &val); | |
150 log = g_value_get_pointer(&val); | |
151 g_value_unset(&val); | |
152 | |
153 if (!log) | |
154 return; | |
155 | |
156 read = gaim_log_read(log, &flags); | |
157 viewer->flags = flags; | |
158 strftime(time, sizeof(time), "%c", localtime(&log->time)); | |
159 title = g_strdup_printf("%s - %s", log->name, time); | |
7676 | 160 title_utf8 = gaim_utf8_try_convert(title); |
161 g_free(title); | |
162 title = title_utf8; | |
7432 | 163 gtk_window_set_title(GTK_WINDOW(viewer->window), title); |
164 gtk_imhtml_clear(GTK_IMHTML(viewer->imhtml)); | |
165 gtk_imhtml_append_text(GTK_IMHTML(viewer->imhtml), read, | |
166 GTK_IMHTML_NO_COMMENTS | GTK_IMHTML_NO_TITLE | GTK_IMHTML_NO_SCROLL | | |
167 ((flags & GAIM_LOG_READ_NO_NEWLINE) ? GTK_IMHTML_NO_NEWLINE : 0)); | |
7535 | 168 |
169 if (viewer->search) | |
7537
083427fd8ba8
[gaim-migrate @ 8150]
Christian Hammond <chipx86@chipx86.com>
parents:
7535
diff
changeset
|
170 gtk_imhtml_search_find(GTK_IMHTML(viewer->imhtml), viewer->search); |
7535 | 171 |
7432 | 172 g_free(read); |
173 g_free(title); | |
174 } | |
175 | |
176 /* I want to make this smarter, but haven't come up with a cool algorithm to do so, yet. | |
177 * I want the tree to be divided into groups like "Today," "Yesterday," "Last week," | |
178 * "August," "2002," etc. based on how many conversation took place in each subdivision. | |
179 * | |
180 * For now, I'll just make it a flat list. | |
181 */ | |
182 static void populate_log_tree(GaimGtkLogViewer *lv) | |
183 /* Logs are made from trees in real life. | |
184 This is a tree made from logs */ | |
185 { | |
7440 | 186 char title[64]; |
7676 | 187 char *title_utf8; /* temporary variable for utf8 conversion */ |
7432 | 188 GtkTreeIter iter; |
189 GList *logs = lv->logs; | |
190 while (logs) { | |
191 GaimLog *log = logs->data; | |
192 strftime(title, sizeof(title), "%c", localtime(&log->time)); | |
7676 | 193 title_utf8 = gaim_utf8_try_convert(title); |
194 strncpy(title, title_utf8, sizeof(title)); | |
195 g_free(title_utf8); | |
7432 | 196 gtk_tree_store_append (lv->treestore, &iter, NULL); |
197 gtk_tree_store_set(lv->treestore, &iter, | |
198 0, title, | |
199 1, log, -1); | |
200 logs = logs->next; | |
201 } | |
202 } | |
203 | |
204 void gaim_gtk_log_show(const char *screenname, GaimAccount *account) { | |
205 /* if (log_viewers && g_hash_table */ | |
206 GtkWidget *hbox, *vbox; | |
207 GdkPixbuf *pixbuf, *scale; | |
208 GtkCellRenderer *rend; | |
209 GtkTreeViewColumn *col; | |
210 GaimGtkLogViewer *lv = NULL; | |
211 GtkTreeSelection *sel; | |
212 GtkWidget *icon, *label, *pane, *sw, *button; | |
213 GList *logs; | |
214 char *text; | |
7436 | 215 struct log_viewer_hash_t *ht = g_new0(struct log_viewer_hash_t, 1); |
216 | |
7432 | 217 ht->screenname = g_strdup(screenname); |
218 ht->account = account; | |
219 | |
220 if (!log_viewers) { | |
221 log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal); | |
222 } else if ((lv = g_hash_table_lookup(log_viewers, ht))) { | |
223 gtk_window_present(GTK_WINDOW(lv->window)); | |
224 return; | |
225 } | |
226 | |
227 lv = g_new0(GaimGtkLogViewer, 1); | |
7485 | 228 lv->logs = logs = gaim_log_get_logs(screenname, account); |
7432 | 229 g_hash_table_insert(log_viewers, ht, lv); |
230 | |
231 /* Window ***********/ | |
232 lv->window = gtk_dialog_new_with_buttons(screenname, NULL, 0, | |
233 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); | |
234 gtk_container_set_border_width (GTK_CONTAINER(lv->window), 6); | |
235 gtk_dialog_set_has_separator(GTK_DIALOG(lv->window), FALSE); | |
236 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(lv->window)->vbox), 0); | |
7454 | 237 g_signal_connect(G_OBJECT(lv->window), "response", |
238 G_CALLBACK(destroy_cb), ht); | |
239 | |
7432 | 240 hbox = gtk_hbox_new(FALSE, 6); |
241 gtk_container_set_border_width(GTK_CONTAINER(hbox), 6); | |
242 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), hbox, FALSE, FALSE, 0); | |
243 | |
244 /* Icon *************/ | |
245 pixbuf = create_prpl_icon(account); | |
246 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); | |
247 icon = gtk_image_new_from_pixbuf(scale); | |
248 gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0); | |
249 g_object_unref(G_OBJECT(pixbuf)); | |
250 g_object_unref(G_OBJECT(scale)); | |
251 | |
252 /* Label ************/ | |
253 label = gtk_label_new(NULL); | |
254 text = g_strdup_printf("<span size='larger' weight='bold'>%s %s</span>", | |
255 _("Conversations with"), screenname); | |
256 gtk_label_set_markup(GTK_LABEL(label), text); | |
257 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
258 g_free(text); | |
259 | |
260 /* Pane *************/ | |
261 pane = gtk_hpaned_new(); | |
262 gtk_container_set_border_width(GTK_CONTAINER(pane), 6); | |
263 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), pane, TRUE, TRUE, 0); | |
264 | |
265 /* List *************/ | |
266 sw = gtk_scrolled_window_new (NULL, NULL); | |
267 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); | |
268 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); | |
269 gtk_paned_add1(GTK_PANED(pane), sw); | |
270 lv->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); | |
271 lv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (lv->treestore)); | |
272 rend = gtk_cell_renderer_text_new(); | |
273 col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL); | |
274 gtk_tree_view_append_column (GTK_TREE_VIEW(lv->treeview), col); | |
275 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (lv->treeview), FALSE); | |
276 gtk_container_add (GTK_CONTAINER (sw), lv->treeview); | |
277 | |
278 gtk_widget_set_size_request(lv->treeview, 170, 200); | |
279 populate_log_tree(lv); | |
280 | |
281 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (lv->treeview)); | |
282 g_signal_connect (G_OBJECT (sel), "changed", | |
7454 | 283 G_CALLBACK (log_select_cb), |
7432 | 284 lv); |
285 | |
286 /* Viewer ************/ | |
287 vbox = gtk_vbox_new(FALSE, 6); | |
288 gtk_paned_add2(GTK_PANED(pane), vbox); | |
289 sw = gtk_scrolled_window_new(NULL, NULL); | |
290 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); | |
291 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); | |
292 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); | |
293 lv->imhtml = gtk_imhtml_new(NULL, NULL); | |
294 gtk_container_add(GTK_CONTAINER(sw), lv->imhtml); | |
295 gaim_setup_imhtml(lv->imhtml); | |
296 gtk_widget_set_size_request(lv->imhtml, 320, 200); | |
297 | |
298 /* Search box **********/ | |
299 hbox = gtk_hbox_new(FALSE, 6); | |
300 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); | |
301 lv->entry = gtk_entry_new(); | |
302 gtk_box_pack_start(GTK_BOX(hbox), lv->entry, TRUE, TRUE, 0); | |
303 button = gtk_button_new_from_stock(GTK_STOCK_FIND); | |
7535 | 304 g_signal_connect (G_OBJECT (button), "pressed", |
305 G_CALLBACK (search_cb), | |
306 lv); | |
7432 | 307 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); |
308 | |
309 gtk_widget_show_all(lv->window); | |
310 } |