Mercurial > pidgin
annotate src/gtklog.c @ 8473:12fe38c195a6
[gaim-migrate @ 9206]
" You can once again show how evil you are by typing >:)
and getting it to render in spite of escaped HTML.
This patch changes around the parsing code to catch
smileys before eating just any HTML entity we bump into
on the street. We try to catch entities at the
beginning of smileys first, and if we're sure they're
not smileys, then we eat them for breakfast. The patch
also deals with eating any subsequent entities that may
appear in any smileys (like :-&) so we don't end up
with trailing leftovers. This patch description is
making me hungry.
FYI, I know this gtkimhtml is supposed to be not gaim
dependent, but both the gaim_* functions that were
preexisting and newly used in gtkimhtml code are all
non-gaim dependent utility functions from util.c, so I felt
their use was justified and acceptable." --Kevin Stange
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Fri, 19 Mar 2004 17:34:33 +0000 |
parents | 4971193f761d |
children | 7dcd6f26e4a7 |
rev | line source |
---|---|
7432 | 1 /** |
2 * @file gtklog.c GTK+ Log viewer | |
3 * @ingroup gtkui | |
4 * | |
5 * gaim | |
6 * | |
8046 | 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. | |
7537
083427fd8ba8
[gaim-migrate @ 8150]
Christian Hammond <chipx86@chipx86.com>
parents:
7535
diff
changeset
|
10 * |
7432 | 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 | |
28 #include "account.h" | |
29 #include "util.h" | |
30 #include "gtkblist.h" | |
31 #include "gtkimhtml.h" | |
32 #include "gtklog.h" | |
33 #include "gtkutils.h" | |
34 #include "log.h" | |
35 | |
36 static GHashTable *log_viewers = NULL; | |
7535 | 37 static void populate_log_tree(GaimGtkLogViewer *lv); |
7432 | 38 |
39 struct log_viewer_hash_t { | |
40 char *screenname; | |
41 GaimAccount *account; | |
42 }; | |
43 | |
7440 | 44 static guint log_viewer_hash(gconstpointer data) |
7432 | 45 { |
7440 | 46 const struct log_viewer_hash_t *viewer = data; |
7432 | 47 return g_str_hash(viewer->screenname) + g_str_hash(gaim_account_get_username(viewer->account)); |
7440 | 48 |
7432 | 49 } |
50 | |
7440 | 51 static gint log_viewer_equal(gconstpointer y, gconstpointer z) |
7432 | 52 { |
7440 | 53 const struct log_viewer_hash_t *a, *b; |
7432 | 54 int ret; |
7440 | 55 char *normal; |
56 | |
57 a = y; | |
58 b = z; | |
59 | |
60 normal = g_strdup(gaim_normalize(a->account, a->screenname)); | |
61 ret = (a->account == b->account) && | |
62 !strcmp(normal, gaim_normalize(b->account, b->screenname)); | |
7432 | 63 g_free(normal); |
64 return ret; | |
65 } | |
66 | |
7535 | 67 static void search_cb(GtkWidget *button, GaimGtkLogViewer *lv) |
68 { | |
69 const char *search_term = gtk_entry_get_text(GTK_ENTRY(lv->entry)); | |
70 GList *logs; | |
71 GdkCursor *cursor = gdk_cursor_new(GDK_WATCH); | |
72 | |
73 if (lv->search) | |
74 g_free(lv->search); | |
75 | |
76 gtk_tree_store_clear(lv->treestore); | |
77 if (strlen(search_term) == 0) {/* reset the tree */ | |
78 populate_log_tree(lv); | |
79 lv->search = NULL; | |
7537
083427fd8ba8
[gaim-migrate @ 8150]
Christian Hammond <chipx86@chipx86.com>
parents:
7535
diff
changeset
|
80 gtk_imhtml_search_clear(GTK_IMHTML(lv->imhtml)); |
7535 | 81 return; |
82 } | |
83 | |
84 lv->search = g_strdup(search_term); | |
85 | |
86 gdk_window_set_cursor(lv->window->window, cursor); | |
87 while (gtk_events_pending()) | |
88 gtk_main_iteration(); | |
89 gdk_cursor_unref(cursor); | |
90 | |
91 for (logs = lv->logs; logs != NULL; logs = logs->next) { | |
92 char *read = gaim_log_read((GaimLog*)logs->data, NULL); | |
93 if (gaim_strcasestr(read, search_term)) { | |
94 GtkTreeIter iter; | |
95 GaimLog *log = logs->data; | |
96 char title[64]; | |
7676 | 97 char *title_utf8; /* temporary variable for utf8 conversion */ |
7535 | 98 strftime(title, sizeof(title), "%c", localtime(&log->time)); |
7676 | 99 title_utf8 = gaim_utf8_try_convert(title); |
100 strncpy(title, title_utf8, sizeof(title)); | |
101 g_free(title_utf8); | |
7535 | 102 gtk_tree_store_append (lv->treestore, &iter, NULL); |
103 gtk_tree_store_set(lv->treestore, &iter, | |
104 0, title, | |
105 1, log, -1); | |
106 } | |
107 } | |
108 | |
109 | |
110 cursor = gdk_cursor_new(GDK_LEFT_PTR); | |
111 gdk_window_set_cursor(lv->window->window, cursor); | |
112 gdk_cursor_unref(cursor); | |
113 } | |
114 | |
7454 | 115 static gboolean destroy_cb(GtkWidget *w, gint resp, struct log_viewer_hash_t *ht) { |
116 GaimGtkLogViewer *lv = g_hash_table_lookup(log_viewers, ht); | |
117 | |
118 g_hash_table_remove(log_viewers, ht); | |
119 g_free(ht->screenname); | |
120 g_free(ht); | |
7535 | 121 while (lv->logs) { |
7533 | 122 GaimLog *log = lv->logs->data; |
7535 | 123 GList *logs2; |
7685 | 124 gaim_log_free(log); |
7535 | 125 logs2 = lv->logs->next; |
126 g_list_free_1(lv->logs); | |
127 lv->logs = logs2; | |
7533 | 128 } |
7535 | 129 if (lv->search) |
130 g_free(lv->search); | |
7533 | 131 g_free(lv); |
7454 | 132 gtk_widget_destroy(w); |
133 | |
134 return TRUE; | |
135 } | |
136 | |
137 static void log_select_cb(GtkTreeSelection *sel, GaimGtkLogViewer *viewer) { | |
7432 | 138 GtkTreeIter iter; |
139 GValue val = { 0, }; | |
140 GtkTreeModel *model = GTK_TREE_MODEL(viewer->treestore); | |
141 GaimLog *log = NULL; | |
142 GaimLogReadFlags flags; | |
143 char *read = NULL; | |
144 char time[64]; | |
145 | |
146 char *title; | |
7676 | 147 char *title_utf8; /* temporary variable for utf8 conversion */ |
7432 | 148 |
149 if (! gtk_tree_selection_get_selected (sel, &model, &iter)) | |
150 return; | |
151 gtk_tree_model_get_value (model, &iter, 1, &val); | |
152 log = g_value_get_pointer(&val); | |
153 g_value_unset(&val); | |
154 | |
155 if (!log) | |
156 return; | |
157 | |
158 read = gaim_log_read(log, &flags); | |
159 viewer->flags = flags; | |
160 strftime(time, sizeof(time), "%c", localtime(&log->time)); | |
161 title = g_strdup_printf("%s - %s", log->name, time); | |
7676 | 162 title_utf8 = gaim_utf8_try_convert(title); |
163 g_free(title); | |
164 title = title_utf8; | |
7432 | 165 gtk_window_set_title(GTK_WINDOW(viewer->window), title); |
166 gtk_imhtml_clear(GTK_IMHTML(viewer->imhtml)); | |
167 gtk_imhtml_append_text(GTK_IMHTML(viewer->imhtml), read, | |
168 GTK_IMHTML_NO_COMMENTS | GTK_IMHTML_NO_TITLE | GTK_IMHTML_NO_SCROLL | | |
169 ((flags & GAIM_LOG_READ_NO_NEWLINE) ? GTK_IMHTML_NO_NEWLINE : 0)); | |
7535 | 170 |
171 if (viewer->search) | |
7537
083427fd8ba8
[gaim-migrate @ 8150]
Christian Hammond <chipx86@chipx86.com>
parents:
7535
diff
changeset
|
172 gtk_imhtml_search_find(GTK_IMHTML(viewer->imhtml), viewer->search); |
7535 | 173 |
7432 | 174 g_free(read); |
175 g_free(title); | |
176 } | |
177 | |
178 /* I want to make this smarter, but haven't come up with a cool algorithm to do so, yet. | |
179 * I want the tree to be divided into groups like "Today," "Yesterday," "Last week," | |
180 * "August," "2002," etc. based on how many conversation took place in each subdivision. | |
181 * | |
182 * For now, I'll just make it a flat list. | |
183 */ | |
184 static void populate_log_tree(GaimGtkLogViewer *lv) | |
185 /* Logs are made from trees in real life. | |
186 This is a tree made from logs */ | |
187 { | |
7440 | 188 char title[64]; |
7676 | 189 char *title_utf8; /* temporary variable for utf8 conversion */ |
7432 | 190 GtkTreeIter iter; |
191 GList *logs = lv->logs; | |
192 while (logs) { | |
193 GaimLog *log = logs->data; | |
194 strftime(title, sizeof(title), "%c", localtime(&log->time)); | |
7676 | 195 title_utf8 = gaim_utf8_try_convert(title); |
196 strncpy(title, title_utf8, sizeof(title)); | |
197 g_free(title_utf8); | |
7432 | 198 gtk_tree_store_append (lv->treestore, &iter, NULL); |
199 gtk_tree_store_set(lv->treestore, &iter, | |
200 0, title, | |
201 1, log, -1); | |
202 logs = logs->next; | |
203 } | |
204 } | |
205 | |
206 void gaim_gtk_log_show(const char *screenname, GaimAccount *account) { | |
207 /* if (log_viewers && g_hash_table */ | |
208 GtkWidget *hbox, *vbox; | |
209 GdkPixbuf *pixbuf, *scale; | |
210 GtkCellRenderer *rend; | |
211 GtkTreeViewColumn *col; | |
212 GaimGtkLogViewer *lv = NULL; | |
213 GtkTreeSelection *sel; | |
214 GtkWidget *icon, *label, *pane, *sw, *button; | |
215 GList *logs; | |
216 char *text; | |
7436 | 217 struct log_viewer_hash_t *ht = g_new0(struct log_viewer_hash_t, 1); |
218 | |
7432 | 219 ht->screenname = g_strdup(screenname); |
220 ht->account = account; | |
221 | |
222 if (!log_viewers) { | |
223 log_viewers = g_hash_table_new(log_viewer_hash, log_viewer_equal); | |
224 } else if ((lv = g_hash_table_lookup(log_viewers, ht))) { | |
225 gtk_window_present(GTK_WINDOW(lv->window)); | |
226 return; | |
227 } | |
228 | |
229 lv = g_new0(GaimGtkLogViewer, 1); | |
7485 | 230 lv->logs = logs = gaim_log_get_logs(screenname, account); |
7432 | 231 g_hash_table_insert(log_viewers, ht, lv); |
232 | |
233 /* Window ***********/ | |
234 lv->window = gtk_dialog_new_with_buttons(screenname, NULL, 0, | |
235 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); | |
236 gtk_container_set_border_width (GTK_CONTAINER(lv->window), 6); | |
237 gtk_dialog_set_has_separator(GTK_DIALOG(lv->window), FALSE); | |
238 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(lv->window)->vbox), 0); | |
7454 | 239 g_signal_connect(G_OBJECT(lv->window), "response", |
240 G_CALLBACK(destroy_cb), ht); | |
241 | |
7432 | 242 hbox = gtk_hbox_new(FALSE, 6); |
243 gtk_container_set_border_width(GTK_CONTAINER(hbox), 6); | |
244 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), hbox, FALSE, FALSE, 0); | |
245 | |
246 /* Icon *************/ | |
247 pixbuf = create_prpl_icon(account); | |
248 scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR); | |
249 icon = gtk_image_new_from_pixbuf(scale); | |
250 gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0); | |
251 g_object_unref(G_OBJECT(pixbuf)); | |
252 g_object_unref(G_OBJECT(scale)); | |
253 | |
254 /* Label ************/ | |
255 label = gtk_label_new(NULL); | |
256 text = g_strdup_printf("<span size='larger' weight='bold'>%s %s</span>", | |
257 _("Conversations with"), screenname); | |
258 gtk_label_set_markup(GTK_LABEL(label), text); | |
259 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
260 g_free(text); | |
261 | |
262 /* Pane *************/ | |
263 pane = gtk_hpaned_new(); | |
264 gtk_container_set_border_width(GTK_CONTAINER(pane), 6); | |
265 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(lv->window)->vbox), pane, TRUE, TRUE, 0); | |
266 | |
267 /* List *************/ | |
268 sw = gtk_scrolled_window_new (NULL, NULL); | |
269 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN); | |
270 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); | |
271 gtk_paned_add1(GTK_PANED(pane), sw); | |
272 lv->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); | |
273 lv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (lv->treestore)); | |
274 rend = gtk_cell_renderer_text_new(); | |
275 col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL); | |
276 gtk_tree_view_append_column (GTK_TREE_VIEW(lv->treeview), col); | |
277 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (lv->treeview), FALSE); | |
278 gtk_container_add (GTK_CONTAINER (sw), lv->treeview); | |
279 | |
280 gtk_widget_set_size_request(lv->treeview, 170, 200); | |
281 populate_log_tree(lv); | |
282 | |
283 sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (lv->treeview)); | |
284 g_signal_connect (G_OBJECT (sel), "changed", | |
7454 | 285 G_CALLBACK (log_select_cb), |
7432 | 286 lv); |
287 | |
288 /* Viewer ************/ | |
289 vbox = gtk_vbox_new(FALSE, 6); | |
290 gtk_paned_add2(GTK_PANED(pane), vbox); | |
291 sw = gtk_scrolled_window_new(NULL, NULL); | |
292 gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 0); | |
293 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); | |
294 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); | |
295 lv->imhtml = gtk_imhtml_new(NULL, NULL); | |
296 gtk_container_add(GTK_CONTAINER(sw), lv->imhtml); | |
297 gaim_setup_imhtml(lv->imhtml); | |
298 gtk_widget_set_size_request(lv->imhtml, 320, 200); | |
299 | |
300 /* Search box **********/ | |
301 hbox = gtk_hbox_new(FALSE, 6); | |
302 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); | |
303 lv->entry = gtk_entry_new(); | |
304 gtk_box_pack_start(GTK_BOX(hbox), lv->entry, TRUE, TRUE, 0); | |
305 button = gtk_button_new_from_stock(GTK_STOCK_FIND); | |
7535 | 306 g_signal_connect (G_OBJECT (button), "pressed", |
307 G_CALLBACK (search_cb), | |
308 lv); | |
7432 | 309 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); |
8137 | 310 gaim_set_accessible_label (lv->treeview, label); |
7432 | 311 |
312 gtk_widget_show_all(lv->window); | |
313 } |