Make return clearer
[pidgin-git.git] / finch / gntnotify.c
blob6e36e2115e687b5b85c293701d4bdfe97159b9fa
1 /*
2 * finch
4 * Finch is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
6 * source distribution.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 #include <internal.h>
25 #include <gnt.h>
26 #include <gntbox.h>
27 #include <gntbutton.h>
28 #include <gntlabel.h>
29 #include <gnttree.h>
30 #include <gntutils.h>
31 #include <gntwindow.h>
33 #include "finch.h"
35 #include <util.h>
37 #include "gntnotify.h"
38 #include "debug.h"
40 static struct
42 GntWidget *window;
43 GntWidget *tree;
44 } emaildialog;
46 static void
47 notify_msg_window_destroy_cb(GntWidget *window, PurpleNotifyType type)
49 purple_notify_close(type, window);
52 static void *
53 finch_notify_common(PurpleNotifyType ntype, PurpleNotifyMessageType msgtype,
54 const char *title, const char *primary, const char *secondary,
55 PurpleRequestCommonParameters *cpar)
57 GntWidget *window, *button;
58 GntTextFormatFlags pf = 0, sf = 0;
60 switch (msgtype)
62 case PURPLE_NOTIFY_MSG_ERROR:
63 sf |= GNT_TEXT_FLAG_BOLD;
64 /* fall through */
65 case PURPLE_NOTIFY_MSG_WARNING:
66 pf |= GNT_TEXT_FLAG_UNDERLINE;
67 /* fall through */
68 case PURPLE_NOTIFY_MSG_INFO:
69 pf |= GNT_TEXT_FLAG_BOLD;
70 break;
73 window = gnt_window_box_new(FALSE, TRUE);
74 gnt_box_set_title(GNT_BOX(window), title);
75 gnt_box_set_fill(GNT_BOX(window), FALSE);
76 gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
77 gnt_box_set_pad(GNT_BOX(window), 0);
79 if (primary)
80 gnt_box_add_widget(GNT_BOX(window),
81 gnt_label_new_with_format(primary, pf));
83 button = gnt_button_new(_("OK"));
85 if (secondary) {
86 GntWidget *msg;
87 if (ntype == PURPLE_NOTIFY_FORMATTED) {
88 int width = -1, height = -1;
89 char *plain = (char*)secondary;
90 msg = gnt_text_view_new();
91 gnt_text_view_set_flag(GNT_TEXT_VIEW(msg), GNT_TEXT_VIEW_TOP_ALIGN | GNT_TEXT_VIEW_NO_SCROLL);
93 plain = purple_markup_strip_html(secondary);
94 if (!gnt_util_parse_xhtml_to_textview(secondary, GNT_TEXT_VIEW(msg)))
95 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(msg), plain, sf);
97 gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(msg), button);
98 gnt_util_get_text_bound(plain, &width, &height);
99 gnt_widget_set_size(msg, width + 3, height + 1);
100 if (plain != secondary)
101 g_free(plain);
102 } else {
103 msg = gnt_label_new_with_format(secondary, sf);
105 gnt_box_add_widget(GNT_BOX(window), msg);
106 g_object_set_data(G_OBJECT(window), "info-widget", msg);
109 gnt_box_add_widget(GNT_BOX(window), button);
110 g_signal_connect_swapped(G_OBJECT(button), "activate",
111 G_CALLBACK(gnt_widget_destroy), window);
112 g_signal_connect(G_OBJECT(window), "destroy",
113 G_CALLBACK(notify_msg_window_destroy_cb), GINT_TO_POINTER(ntype));
115 gnt_widget_show(window);
116 return window;
119 /* handle is, in all/most occasions, a GntWidget * */
120 static void finch_close_notify(PurpleNotifyType type, void *handle)
122 GntWidget *widget = handle;
124 if (!widget)
125 return;
127 widget = gnt_widget_get_toplevel(widget);
129 if (type == PURPLE_NOTIFY_SEARCHRESULTS)
130 purple_notify_searchresults_free(g_object_get_data(handle, "notify-results"));
131 #if 1
132 /* This did not seem to be necessary */
133 g_signal_handlers_disconnect_by_func(G_OBJECT(widget),
134 G_CALLBACK(notify_msg_window_destroy_cb), GINT_TO_POINTER(type));
135 #endif
136 gnt_widget_destroy(widget);
139 static void *
140 finch_notify_message(PurpleNotifyMessageType type, const char *title,
141 const char *primary, const char *secondary,
142 PurpleRequestCommonParameters *cpar)
144 return finch_notify_common(PURPLE_NOTIFY_MESSAGE, type, title, primary,
145 secondary, cpar);
148 static void *finch_notify_formatted(const char *title, const char *primary,
149 const char *secondary, const char *text)
151 char *xhtml = NULL;
152 char *t = g_strdup_printf("<span>%s%s%s</span>",
153 secondary ? secondary : "",
154 secondary ? "\n" : "",
155 text ? text : "");
156 void *ret;
158 purple_markup_html_to_xhtml(t, &xhtml, NULL);
159 ret = finch_notify_common(PURPLE_NOTIFY_FORMATTED,
160 PURPLE_NOTIFY_MSG_INFO, title, primary, xhtml, NULL);
162 g_free(t);
163 g_free(xhtml);
165 return ret;
168 static void
169 reset_email_dialog(void)
171 emaildialog.window = NULL;
172 emaildialog.tree = NULL;
175 static void
176 setup_email_dialog(void)
178 GntWidget *box, *tree, *button;
179 if (emaildialog.window)
180 return;
182 emaildialog.window = box = gnt_vbox_new(FALSE);
183 gnt_box_set_toplevel(GNT_BOX(box), TRUE);
184 gnt_box_set_title(GNT_BOX(box), _("Emails"));
185 gnt_box_set_fill(GNT_BOX(box), FALSE);
186 gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID);
187 gnt_box_set_pad(GNT_BOX(box), 0);
189 gnt_box_add_widget(GNT_BOX(box),
190 gnt_label_new_with_format(_("You have mail!"), GNT_TEXT_FLAG_BOLD));
192 emaildialog.tree = tree = gnt_tree_new_with_columns(3);
193 gnt_tree_set_column_titles(GNT_TREE(tree), _("Account"), _("Sender"), _("Subject"));
194 gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
195 gnt_tree_set_col_width(GNT_TREE(tree), 0, 15);
196 gnt_tree_set_col_width(GNT_TREE(tree), 1, 25);
197 gnt_tree_set_col_width(GNT_TREE(tree), 2, 25);
199 gnt_box_add_widget(GNT_BOX(box), tree);
201 button = gnt_button_new(_("Close"));
202 gnt_box_add_widget(GNT_BOX(box), button);
204 g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), box);
205 g_signal_connect(G_OBJECT(box), "destroy", G_CALLBACK(reset_email_dialog), NULL);
208 static void *
209 finch_notify_emails(PurpleConnection *gc, size_t count, gboolean detailed,
210 const char **subjects, const char **froms, const char **tos,
211 const char **urls)
213 PurpleAccount *account = purple_connection_get_account(gc);
214 void *ret = NULL;
215 static int key = 0;
217 if (count == 0)
218 return NULL;
220 if (!detailed) {
221 gchar *message;
222 message = g_strdup_printf(
223 ngettext("%s (%s) has %d new message.",
224 "%s (%s) has %d new messages.", (int)count),
225 tos ? *tos : purple_account_get_username(account),
226 purple_account_get_protocol_name(account), (int)count);
227 ret = finch_notify_common(PURPLE_NOTIFY_EMAIL, PURPLE_NOTIFY_MSG_INFO,
228 _("New Mail"), _("You have mail!"), message,
229 NULL);
230 g_free(message);
231 } else {
232 char *to;
233 gboolean newwin = (emaildialog.window == NULL);
235 if (newwin)
236 setup_email_dialog();
238 to = g_strdup_printf("%s (%s)", tos ? *tos : purple_account_get_username(account),
239 purple_account_get_protocol_name(account));
240 gnt_tree_add_row_after(GNT_TREE(emaildialog.tree), GINT_TO_POINTER(++key),
241 gnt_tree_create_row(GNT_TREE(emaildialog.tree), to,
242 froms ? *froms : "[Unknown sender]",
243 *subjects),
244 NULL, NULL);
245 g_free(to);
246 if (newwin)
247 gnt_widget_show(emaildialog.window);
248 else
249 gnt_window_present(emaildialog.window);
250 ret = NULL;
253 return ret;
256 static void *
257 finch_notify_email(PurpleConnection *gc, const char *subject, const char *from,
258 const char *to, const char *url)
260 return finch_notify_emails(gc, 1, subject != NULL,
261 subject ? &subject : NULL,
262 from ? &from : NULL,
263 to ? &to : NULL,
264 url ? &url : NULL);
267 /** User information. **/
268 static GHashTable *userinfo;
270 static char *
271 userinfo_hash(PurpleAccount *account, const char *who)
273 char key[256];
274 g_snprintf(key, sizeof(key), "%s - %s", purple_account_get_username(account), purple_normalize(account, who));
275 return g_utf8_strup(key, -1);
278 static void
279 remove_userinfo(GntWidget *widget, gpointer key)
281 g_hash_table_remove(userinfo, key);
284 static char *
285 purple_notify_user_info_get_xhtml(PurpleNotifyUserInfo *user_info)
287 GList *l;
288 GString *text;
290 text = g_string_new("<span>");
292 for (l = purple_notify_user_info_get_entries(user_info)->head; l != NULL;
293 l = l->next) {
294 PurpleNotifyUserInfoEntry *user_info_entry = l->data;
295 PurpleNotifyUserInfoEntryType type = purple_notify_user_info_entry_get_entry_type(user_info_entry);
296 const char *label = purple_notify_user_info_entry_get_label(user_info_entry);
297 const char *value = purple_notify_user_info_entry_get_value(user_info_entry);
299 /* Handle the label/value pair itself */
300 if (type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER)
301 g_string_append(text, "<u>");
302 if (label)
303 g_string_append_printf(text, "<b>%s</b>", label);
304 g_string_append(text, "<span>");
305 if (label && value)
306 g_string_append(text, ": ");
307 if (value) {
308 char *strip = purple_markup_strip_html(value);
309 g_string_append(text, strip);
310 g_free(strip);
312 g_string_append(text, "</span>");
313 if (type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER)
314 g_string_append(text, "</u>");
315 else if (type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK)
316 g_string_append(text, "<HR/>");
317 g_string_append(text, "<BR/>");
319 g_string_append(text, "</span>");
321 return g_string_free(text, FALSE);
324 static void *
325 finch_notify_userinfo(PurpleConnection *gc, const char *who, PurpleNotifyUserInfo *user_info)
327 char *primary;
328 char *info;
329 void *ui_handle;
330 char *key = userinfo_hash(purple_connection_get_account(gc), who);
332 info = purple_notify_user_info_get_xhtml(user_info);
334 ui_handle = g_hash_table_lookup(userinfo, key);
335 if (ui_handle != NULL) {
336 GntTextView *msg = GNT_TEXT_VIEW(g_object_get_data(G_OBJECT(ui_handle), "info-widget"));
337 char *strip = purple_markup_strip_html(info);
338 int tvw, tvh, width, height, ntvw, ntvh;
339 GntWidget *window;
341 ui_handle = window = gnt_widget_get_toplevel(GNT_WIDGET(ui_handle));
342 gnt_widget_get_size(window, &width, &height);
343 gnt_widget_get_size(GNT_WIDGET(msg), &tvw, &tvh);
345 gnt_text_view_clear(msg);
346 if (!gnt_util_parse_xhtml_to_textview(info, msg))
347 gnt_text_view_append_text_with_flags(msg, strip, GNT_TEXT_FLAG_NORMAL);
348 gnt_text_view_scroll(msg, 0);
349 gnt_util_get_text_bound(strip, &ntvw, &ntvh);
350 ntvw += 3;
351 ntvh++;
353 gnt_screen_resize_widget(window, width + MAX(0, ntvw - tvw), height + MAX(0, ntvh - tvh));
354 g_free(strip);
355 g_free(key);
356 } else {
357 primary = g_strdup_printf(_("Info for %s"), who);
358 ui_handle = finch_notify_formatted(_("Buddy Information"), primary, NULL, info);
359 g_hash_table_insert(userinfo, key, ui_handle);
360 g_free(primary);
361 g_signal_connect(G_OBJECT(ui_handle), "destroy", G_CALLBACK(remove_userinfo), key);
364 g_free(info);
365 return ui_handle;
368 static void
369 notify_button_activated(GntWidget *widget, PurpleNotifySearchButton *b)
371 GList *list = NULL;
372 PurpleAccount *account = g_object_get_data(G_OBJECT(widget), "notify-account");
373 gpointer data = g_object_get_data(G_OBJECT(widget), "notify-data");
375 list = gnt_tree_get_selection_text_list(GNT_TREE(g_object_get_data(G_OBJECT(widget), "notify-tree")));
377 b->callback(purple_account_get_connection(account), list, data);
378 g_list_free_full(list, g_free);
381 static void
382 finch_notify_sr_new_rows(PurpleConnection *gc,
383 PurpleNotifySearchResults *results, void *data)
385 GntWindow *window = GNT_WINDOW(data);
386 GntTree *tree = GNT_TREE(g_object_get_data(G_OBJECT(window), "tree-widget"));
387 GList *o;
388 GntTreeRow *prev = NULL;
390 gnt_tree_remove_all(GNT_TREE(tree));
392 for (o = results->rows; o; o = o->next)
394 gnt_tree_add_row_after(GNT_TREE(tree), o->data,
395 gnt_tree_create_row_from_list(GNT_TREE(tree), o->data),
396 NULL, prev);
397 prev = o->data;
401 static void
402 notify_sr_destroy_cb(GntWidget *window, void *data)
404 purple_notify_close(PURPLE_NOTIFY_SEARCHRESULTS, window);
407 static void *
408 finch_notify_searchresults(PurpleConnection *gc, const char *title,
409 const char *primary, const char *secondary,
410 PurpleNotifySearchResults *results, gpointer data)
412 GntWidget *window, *tree, *box, *button;
413 GList *iter;
414 int columns, i;
416 window = gnt_vbox_new(FALSE);
417 gnt_box_set_toplevel(GNT_BOX(window), TRUE);
418 gnt_box_set_title(GNT_BOX(window), title);
419 gnt_box_set_fill(GNT_BOX(window), TRUE);
420 gnt_box_set_pad(GNT_BOX(window), 0);
421 gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
423 if (primary)
424 gnt_box_add_widget(GNT_BOX(window),
425 gnt_label_new_with_format(primary, GNT_TEXT_FLAG_BOLD));
426 if (secondary)
427 gnt_box_add_widget(GNT_BOX(window),
428 gnt_label_new_with_format(secondary, GNT_TEXT_FLAG_NORMAL));
430 columns = g_list_length(results->columns);
431 tree = gnt_tree_new_with_columns(columns);
432 gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
433 gnt_box_add_widget(GNT_BOX(window), tree);
435 i = 0;
436 for (iter = results->columns; iter; iter = iter->next)
438 PurpleNotifySearchColumn *column = iter->data;
439 gnt_tree_set_column_title(GNT_TREE(tree), i, purple_notify_searchresult_column_get_title(column));
441 if (!purple_notify_searchresult_column_is_visible(column))
442 gnt_tree_set_column_visible(GNT_TREE(tree), i, FALSE);
443 i++;
446 box = gnt_hbox_new(TRUE);
448 for (iter = results->buttons; iter; iter = iter->next)
450 PurpleNotifySearchButton *b = iter->data;
451 const char *text;
453 switch (b->type)
455 case PURPLE_NOTIFY_BUTTON_LABELED:
456 text = b->label;
457 break;
458 case PURPLE_NOTIFY_BUTTON_CONTINUE:
459 text = _("Continue");
460 break;
461 case PURPLE_NOTIFY_BUTTON_ADD:
462 text = _("Add");
463 break;
464 case PURPLE_NOTIFY_BUTTON_INFO:
465 text = _("Info");
466 break;
467 case PURPLE_NOTIFY_BUTTON_IM:
468 text = _("IM");
469 break;
470 case PURPLE_NOTIFY_BUTTON_JOIN:
471 text = _("Join");
472 break;
473 case PURPLE_NOTIFY_BUTTON_INVITE:
474 text = _("Invite");
475 break;
476 default:
477 text = _("(none)");
480 button = gnt_button_new(text);
481 g_object_set_data(G_OBJECT(button), "notify-account", purple_connection_get_account(gc));
482 g_object_set_data(G_OBJECT(button), "notify-data", data);
483 g_object_set_data(G_OBJECT(button), "notify-tree", tree);
484 g_signal_connect(G_OBJECT(button), "activate",
485 G_CALLBACK(notify_button_activated), b);
487 gnt_box_add_widget(GNT_BOX(box), button);
490 gnt_box_add_widget(GNT_BOX(window), box);
491 g_signal_connect(G_OBJECT(tree), "destroy",
492 G_CALLBACK(notify_sr_destroy_cb), NULL);
494 g_object_set_data(G_OBJECT(window), "tree-widget", tree);
495 finch_notify_sr_new_rows(gc, results, window);
497 g_signal_connect(G_OBJECT(window), "destroy",
498 G_CALLBACK(notify_msg_window_destroy_cb), GINT_TO_POINTER(PURPLE_NOTIFY_SEARCHRESULTS));
500 gnt_widget_show(window);
501 g_object_set_data(G_OBJECT(window), "notify-results", results);
503 return window;
506 static void *
507 finch_notify_uri(const char *url)
509 return finch_notify_common(PURPLE_NOTIFY_URI, PURPLE_NOTIFY_MSG_INFO,
510 _("URI"), url, NULL, NULL);
513 static PurpleNotifyUiOps ops =
515 finch_notify_message,
516 finch_notify_email,
517 finch_notify_emails,
518 finch_notify_formatted,
519 finch_notify_searchresults,
520 finch_notify_sr_new_rows,
521 finch_notify_userinfo,
522 finch_notify_uri,
523 finch_close_notify, /* The rest of the notify-uiops return a GntWidget.
524 These widgets should be destroyed from here. */
525 NULL,
526 NULL,
527 NULL,
528 NULL
532 PurpleNotifyUiOps *finch_notify_get_ui_ops()
534 return &ops;
537 void finch_notify_init()
539 userinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
542 void finch_notify_uninit()
544 g_hash_table_destroy(userinfo);