2 * @file gntnotify.c GNT Notify API
8 * Finch is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
30 #include <gntbutton.h>
34 #include <gntwindow.h>
40 #include "gntnotify.h"
50 notify_msg_window_destroy_cb(GntWidget
*window
, PurpleNotifyMsgType type
)
52 purple_notify_close(type
, window
);
56 finch_notify_message(PurpleNotifyMsgType type
, const char *title
,
57 const char *primary
, const char *secondary
)
59 GntWidget
*window
, *button
;
60 GntTextFormatFlags pf
= 0, sf
= 0;
64 case PURPLE_NOTIFY_MSG_ERROR
:
65 sf
|= GNT_TEXT_FLAG_BOLD
;
66 case PURPLE_NOTIFY_MSG_WARNING
:
67 pf
|= GNT_TEXT_FLAG_UNDERLINE
;
68 case PURPLE_NOTIFY_MSG_INFO
:
69 pf
|= GNT_TEXT_FLAG_BOLD
;
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);
80 gnt_box_add_widget(GNT_BOX(window
),
81 gnt_label_new_with_format(primary
, pf
));
83 button
= gnt_button_new(_("OK"));
87 if (type
== 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 case PURPLE_NOTIFY_FORMATTED
:
94 plain
= purple_markup_strip_html(secondary
);
95 if (gnt_util_parse_xhtml_to_textview(secondary
, GNT_TEXT_VIEW(msg
)))
99 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(msg
), plain
, sf
);
101 gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(msg
), button
);
102 gnt_util_get_text_bound(plain
, &width
, &height
);
103 gnt_widget_set_size(msg
, width
+ 3, height
+ 1);
104 if (plain
!= secondary
)
107 msg
= gnt_label_new_with_format(secondary
, sf
);
109 gnt_box_add_widget(GNT_BOX(window
), msg
);
110 g_object_set_data(G_OBJECT(window
), "info-widget", msg
);
113 gnt_box_add_widget(GNT_BOX(window
), button
);
114 g_signal_connect_swapped(G_OBJECT(button
), "activate",
115 G_CALLBACK(gnt_widget_destroy
), window
);
116 g_signal_connect(G_OBJECT(window
), "destroy",
117 G_CALLBACK(notify_msg_window_destroy_cb
), GINT_TO_POINTER(type
));
119 gnt_widget_show(window
);
123 /* handle is, in all/most occasions, a GntWidget * */
124 static void finch_close_notify(PurpleNotifyType type
, void *handle
)
126 GntWidget
*widget
= handle
;
131 while (widget
->parent
)
132 widget
= widget
->parent
;
134 if (type
== PURPLE_NOTIFY_SEARCHRESULTS
)
135 purple_notify_searchresults_free(g_object_get_data(handle
, "notify-results"));
137 /* This did not seem to be necessary */
138 g_signal_handlers_disconnect_by_func(G_OBJECT(widget
),
139 G_CALLBACK(notify_msg_window_destroy_cb
), GINT_TO_POINTER(type
));
141 gnt_widget_destroy(widget
);
144 static void *finch_notify_formatted(const char *title
, const char *primary
,
145 const char *secondary
, const char *text
)
148 char *t
= g_strdup_printf("<span>%s%s%s</span>",
149 secondary
? secondary
: "",
150 secondary
? "\n" : "",
154 purple_markup_html_to_xhtml(t
, &xhtml
, NULL
);
155 ret
= finch_notify_message(PURPLE_NOTIFY_FORMATTED
, title
, primary
, xhtml
);
164 reset_email_dialog(void)
166 emaildialog
.window
= NULL
;
167 emaildialog
.tree
= NULL
;
171 setup_email_dialog(void)
173 GntWidget
*box
, *tree
, *button
;
174 if (emaildialog
.window
)
177 emaildialog
.window
= box
= gnt_vbox_new(FALSE
);
178 gnt_box_set_toplevel(GNT_BOX(box
), TRUE
);
179 gnt_box_set_title(GNT_BOX(box
), _("Emails"));
180 gnt_box_set_fill(GNT_BOX(box
), FALSE
);
181 gnt_box_set_alignment(GNT_BOX(box
), GNT_ALIGN_MID
);
182 gnt_box_set_pad(GNT_BOX(box
), 0);
184 gnt_box_add_widget(GNT_BOX(box
),
185 gnt_label_new_with_format(_("You have mail!"), GNT_TEXT_FLAG_BOLD
));
187 emaildialog
.tree
= tree
= gnt_tree_new_with_columns(3);
188 gnt_tree_set_column_titles(GNT_TREE(tree
), _("Account"), _("Sender"), _("Subject"));
189 gnt_tree_set_show_title(GNT_TREE(tree
), TRUE
);
190 gnt_tree_set_col_width(GNT_TREE(tree
), 0, 15);
191 gnt_tree_set_col_width(GNT_TREE(tree
), 1, 25);
192 gnt_tree_set_col_width(GNT_TREE(tree
), 2, 25);
194 gnt_box_add_widget(GNT_BOX(box
), tree
);
196 button
= gnt_button_new(_("Close"));
197 gnt_box_add_widget(GNT_BOX(box
), button
);
199 g_signal_connect_swapped(G_OBJECT(button
), "activate", G_CALLBACK(gnt_widget_destroy
), box
);
200 g_signal_connect(G_OBJECT(box
), "destroy", G_CALLBACK(reset_email_dialog
), NULL
);
204 finch_notify_emails(PurpleConnection
*gc
, size_t count
, gboolean detailed
,
205 const char **subjects
, const char **froms
, const char **tos
,
208 PurpleAccount
*account
= purple_connection_get_account(gc
);
209 GString
*message
= g_string_new(NULL
);
218 g_string_append_printf(message
,
219 ngettext("%s (%s) has %d new message.",
220 "%s (%s) has %d new messages.",
222 tos
? *tos
: purple_account_get_username(account
),
223 purple_account_get_protocol_name(account
), (int)count
);
228 gboolean newwin
= (emaildialog
.window
== NULL
);
231 setup_email_dialog();
233 to
= g_strdup_printf("%s (%s)", tos
? *tos
: purple_account_get_username(account
),
234 purple_account_get_protocol_name(account
));
235 gnt_tree_add_row_after(GNT_TREE(emaildialog
.tree
), GINT_TO_POINTER(++key
),
236 gnt_tree_create_row(GNT_TREE(emaildialog
.tree
), to
,
237 froms
? *froms
: "[Unknown sender]",
242 gnt_widget_show(emaildialog
.window
);
244 gnt_window_present(emaildialog
.window
);
248 ret
= finch_notify_message(PURPLE_NOTIFY_EMAIL
, _("New Mail"), _("You have mail!"), message
->str
);
249 g_string_free(message
, TRUE
);
254 finch_notify_email(PurpleConnection
*gc
, const char *subject
, const char *from
,
255 const char *to
, const char *url
)
257 return finch_notify_emails(gc
, 1, subject
!= NULL
,
258 subject
? &subject
: NULL
,
264 /** User information. **/
265 static GHashTable
*userinfo
;
268 userinfo_hash(PurpleAccount
*account
, const char *who
)
271 g_snprintf(key
, sizeof(key
), "%s - %s", purple_account_get_username(account
), purple_normalize(account
, who
));
272 return g_utf8_strup(key
, -1);
276 remove_userinfo(GntWidget
*widget
, gpointer key
)
278 g_hash_table_remove(userinfo
, key
);
282 purple_notify_user_info_get_xhtml(PurpleNotifyUserInfo
*user_info
)
287 text
= g_string_new("<span>");
289 for (l
= purple_notify_user_info_get_entries(user_info
); l
!= NULL
;
291 PurpleNotifyUserInfoEntry
*user_info_entry
= l
->data
;
292 PurpleNotifyUserInfoEntryType type
= purple_notify_user_info_entry_get_type(user_info_entry
);
293 const char *label
= purple_notify_user_info_entry_get_label(user_info_entry
);
294 const char *value
= purple_notify_user_info_entry_get_value(user_info_entry
);
296 /* Handle the label/value pair itself */
297 if (type
== PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER
)
298 g_string_append(text
, "<u>");
300 g_string_append_printf(text
, "<b>%s</b>", label
);
301 g_string_append(text
, "<span>");
303 g_string_append(text
, ": ");
305 char *strip
= purple_markup_strip_html(value
);
306 g_string_append(text
, strip
);
309 g_string_append(text
, "</span>");
310 if (type
== PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER
)
311 g_string_append(text
, "</u>");
312 else if (type
== PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK
)
313 g_string_append(text
, "<HR/>");
314 g_string_append(text
, "<BR/>");
316 g_string_append(text
, "</span>");
318 return g_string_free(text
, FALSE
);
322 finch_notify_userinfo(PurpleConnection
*gc
, const char *who
, PurpleNotifyUserInfo
*user_info
)
327 char *key
= userinfo_hash(purple_connection_get_account(gc
), who
);
329 info
= purple_notify_user_info_get_xhtml(user_info
);
331 ui_handle
= g_hash_table_lookup(userinfo
, key
);
332 if (ui_handle
!= NULL
) {
333 GntTextView
*msg
= GNT_TEXT_VIEW(g_object_get_data(G_OBJECT(ui_handle
), "info-widget"));
334 char *strip
= purple_markup_strip_html(info
);
335 int tvw
, tvh
, width
, height
, ntvw
, ntvh
;
337 while (GNT_WIDGET(ui_handle
)->parent
)
338 ui_handle
= GNT_WIDGET(ui_handle
)->parent
;
339 gnt_widget_get_size(GNT_WIDGET(ui_handle
), &width
, &height
);
340 gnt_widget_get_size(GNT_WIDGET(msg
), &tvw
, &tvh
);
342 gnt_text_view_clear(msg
);
343 if (!gnt_util_parse_xhtml_to_textview(info
, msg
))
344 gnt_text_view_append_text_with_flags(msg
, strip
, GNT_TEXT_FLAG_NORMAL
);
345 gnt_text_view_scroll(msg
, 0);
346 gnt_util_get_text_bound(strip
, &ntvw
, &ntvh
);
350 gnt_screen_resize_widget(GNT_WIDGET(ui_handle
), width
+ MAX(0, ntvw
- tvw
), height
+ MAX(0, ntvh
- tvh
));
354 primary
= g_strdup_printf(_("Info for %s"), who
);
355 ui_handle
= finch_notify_formatted(_("Buddy Information"), primary
, NULL
, info
);
356 g_hash_table_insert(userinfo
, key
, ui_handle
);
358 g_signal_connect(G_OBJECT(ui_handle
), "destroy", G_CALLBACK(remove_userinfo
), key
);
366 notify_button_activated(GntWidget
*widget
, PurpleNotifySearchButton
*b
)
369 PurpleAccount
*account
= g_object_get_data(G_OBJECT(widget
), "notify-account");
370 gpointer data
= g_object_get_data(G_OBJECT(widget
), "notify-data");
372 list
= gnt_tree_get_selection_text_list(GNT_TREE(g_object_get_data(G_OBJECT(widget
), "notify-tree")));
374 b
->callback(purple_account_get_connection(account
), list
, data
);
375 g_list_foreach(list
, (GFunc
)g_free
, NULL
);
380 finch_notify_sr_new_rows(PurpleConnection
*gc
,
381 PurpleNotifySearchResults
*results
, void *data
)
383 GntTree
*tree
= GNT_TREE(data
);
386 /* XXX: Do I need to empty the tree here? */
388 for (o
= results
->rows
; o
; o
= o
->next
)
390 gnt_tree_add_row_after(GNT_TREE(tree
), o
->data
,
391 gnt_tree_create_row_from_list(GNT_TREE(tree
), o
->data
),
397 finch_notify_searchresults(PurpleConnection
*gc
, const char *title
,
398 const char *primary
, const char *secondary
,
399 PurpleNotifySearchResults
*results
, gpointer data
)
401 GntWidget
*window
, *tree
, *box
, *button
;
405 window
= gnt_vbox_new(FALSE
);
406 gnt_box_set_toplevel(GNT_BOX(window
), TRUE
);
407 gnt_box_set_title(GNT_BOX(window
), title
);
408 gnt_box_set_fill(GNT_BOX(window
), TRUE
);
409 gnt_box_set_pad(GNT_BOX(window
), 0);
410 gnt_box_set_alignment(GNT_BOX(window
), GNT_ALIGN_MID
);
413 gnt_box_add_widget(GNT_BOX(window
),
414 gnt_label_new_with_format(primary
, GNT_TEXT_FLAG_BOLD
));
416 gnt_box_add_widget(GNT_BOX(window
),
417 gnt_label_new_with_format(secondary
, GNT_TEXT_FLAG_NORMAL
));
419 columns
= g_list_length(results
->columns
);
420 tree
= gnt_tree_new_with_columns(columns
);
421 gnt_tree_set_show_title(GNT_TREE(tree
), TRUE
);
422 gnt_box_add_widget(GNT_BOX(window
), tree
);
425 for (iter
= results
->columns
; iter
; iter
= iter
->next
)
427 PurpleNotifySearchColumn
*column
= iter
->data
;
428 gnt_tree_set_column_title(GNT_TREE(tree
), i
, column
->title
);
432 box
= gnt_hbox_new(TRUE
);
434 for (iter
= results
->buttons
; iter
; iter
= iter
->next
)
436 PurpleNotifySearchButton
*b
= iter
->data
;
441 case PURPLE_NOTIFY_BUTTON_LABELED
:
444 case PURPLE_NOTIFY_BUTTON_CONTINUE
:
445 text
= _("Continue");
447 case PURPLE_NOTIFY_BUTTON_ADD
:
450 case PURPLE_NOTIFY_BUTTON_INFO
:
453 case PURPLE_NOTIFY_BUTTON_IM
:
456 case PURPLE_NOTIFY_BUTTON_JOIN
:
459 case PURPLE_NOTIFY_BUTTON_INVITE
:
466 button
= gnt_button_new(text
);
467 g_object_set_data(G_OBJECT(button
), "notify-account", purple_connection_get_account(gc
));
468 g_object_set_data(G_OBJECT(button
), "notify-data", data
);
469 g_object_set_data(G_OBJECT(button
), "notify-tree", tree
);
470 g_signal_connect(G_OBJECT(button
), "activate",
471 G_CALLBACK(notify_button_activated
), b
);
473 gnt_box_add_widget(GNT_BOX(box
), button
);
476 gnt_box_add_widget(GNT_BOX(window
), box
);
478 finch_notify_sr_new_rows(gc
, results
, tree
);
480 gnt_widget_show(window
);
481 g_object_set_data(G_OBJECT(window
), "notify-results", results
);
487 finch_notify_uri(const char *url
)
489 return finch_notify_message(PURPLE_NOTIFY_URI
, _("URI"), url
, NULL
);
492 static PurpleNotifyUiOps ops
=
494 finch_notify_message
,
497 finch_notify_formatted
,
498 finch_notify_searchresults
,
499 finch_notify_sr_new_rows
,
500 finch_notify_userinfo
,
502 finch_close_notify
, /* The rest of the notify-uiops return a GntWidget.
503 These widgets should be destroyed from here. */
511 PurpleNotifyUiOps
*finch_notify_get_ui_ops()
516 void finch_notify_init()
518 userinfo
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
521 void finch_notify_uninit()
523 g_hash_table_destroy(userinfo
);