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
, PurpleNotifyType type
)
52 purple_notify_close(type
, window
);
56 finch_notify_common(PurpleNotifyType ntype
, PurpleNotifyMsgType msgtype
,
57 const char *title
, 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
;
67 case PURPLE_NOTIFY_MSG_WARNING
:
68 pf
|= GNT_TEXT_FLAG_UNDERLINE
;
70 case PURPLE_NOTIFY_MSG_INFO
:
71 pf
|= GNT_TEXT_FLAG_BOLD
;
75 window
= gnt_window_box_new(FALSE
, TRUE
);
76 gnt_box_set_title(GNT_BOX(window
), title
);
77 gnt_box_set_fill(GNT_BOX(window
), FALSE
);
78 gnt_box_set_alignment(GNT_BOX(window
), GNT_ALIGN_MID
);
79 gnt_box_set_pad(GNT_BOX(window
), 0);
82 gnt_box_add_widget(GNT_BOX(window
),
83 gnt_label_new_with_format(primary
, pf
));
85 button
= gnt_button_new(_("OK"));
89 if (ntype
== PURPLE_NOTIFY_FORMATTED
) {
90 int width
= -1, height
= -1;
91 char *plain
= (char*)secondary
;
92 msg
= gnt_text_view_new();
93 gnt_text_view_set_flag(GNT_TEXT_VIEW(msg
), GNT_TEXT_VIEW_TOP_ALIGN
| GNT_TEXT_VIEW_NO_SCROLL
);
95 plain
= purple_markup_strip_html(secondary
);
96 if (!gnt_util_parse_xhtml_to_textview(secondary
, GNT_TEXT_VIEW(msg
)))
97 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(msg
), plain
, sf
);
99 gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(msg
), button
);
100 gnt_util_get_text_bound(plain
, &width
, &height
);
101 gnt_widget_set_size(msg
, width
+ 3, height
+ 1);
102 if (plain
!= secondary
)
105 msg
= gnt_label_new_with_format(secondary
, sf
);
107 gnt_box_add_widget(GNT_BOX(window
), msg
);
108 g_object_set_data(G_OBJECT(window
), "info-widget", msg
);
111 gnt_box_add_widget(GNT_BOX(window
), button
);
112 g_signal_connect_swapped(G_OBJECT(button
), "activate",
113 G_CALLBACK(gnt_widget_destroy
), window
);
114 g_signal_connect(G_OBJECT(window
), "destroy",
115 G_CALLBACK(notify_msg_window_destroy_cb
), GINT_TO_POINTER(ntype
));
117 gnt_widget_show(window
);
122 finch_notify_message(PurpleNotifyMsgType type
, const char *title
,
123 const char *primary
, const char *secondary
)
125 return finch_notify_common(PURPLE_NOTIFY_MESSAGE
, type
, title
, primary
,
129 /* handle is, in all/most occasions, a GntWidget * */
130 static void finch_close_notify(PurpleNotifyType type
, void *handle
)
132 GntWidget
*widget
= handle
;
137 while (widget
->parent
)
138 widget
= widget
->parent
;
140 if (type
== PURPLE_NOTIFY_SEARCHRESULTS
)
141 purple_notify_searchresults_free(g_object_get_data(handle
, "notify-results"));
143 /* This did not seem to be necessary */
144 g_signal_handlers_disconnect_by_func(G_OBJECT(widget
),
145 G_CALLBACK(notify_msg_window_destroy_cb
), GINT_TO_POINTER(type
));
147 gnt_widget_destroy(widget
);
150 static void *finch_notify_formatted(const char *title
, const char *primary
,
151 const char *secondary
, const char *text
)
154 char *t
= g_strdup_printf("<span>%s%s%s</span>",
155 secondary
? secondary
: "",
156 secondary
? "\n" : "",
160 purple_markup_html_to_xhtml(t
, &xhtml
, NULL
);
161 ret
= finch_notify_common(PURPLE_NOTIFY_FORMATTED
,
162 PURPLE_NOTIFY_MSG_INFO
, title
, primary
, xhtml
);
171 reset_email_dialog(void)
173 emaildialog
.window
= NULL
;
174 emaildialog
.tree
= NULL
;
178 setup_email_dialog(void)
180 GntWidget
*box
, *tree
, *button
;
181 if (emaildialog
.window
)
184 emaildialog
.window
= box
= gnt_vbox_new(FALSE
);
185 gnt_box_set_toplevel(GNT_BOX(box
), TRUE
);
186 gnt_box_set_title(GNT_BOX(box
), _("Emails"));
187 gnt_box_set_fill(GNT_BOX(box
), FALSE
);
188 gnt_box_set_alignment(GNT_BOX(box
), GNT_ALIGN_MID
);
189 gnt_box_set_pad(GNT_BOX(box
), 0);
191 gnt_box_add_widget(GNT_BOX(box
),
192 gnt_label_new_with_format(_("You have mail!"), GNT_TEXT_FLAG_BOLD
));
194 emaildialog
.tree
= tree
= gnt_tree_new_with_columns(3);
195 gnt_tree_set_column_titles(GNT_TREE(tree
), _("Account"), _("Sender"), _("Subject"));
196 gnt_tree_set_show_title(GNT_TREE(tree
), TRUE
);
197 gnt_tree_set_col_width(GNT_TREE(tree
), 0, 15);
198 gnt_tree_set_col_width(GNT_TREE(tree
), 1, 25);
199 gnt_tree_set_col_width(GNT_TREE(tree
), 2, 25);
201 gnt_box_add_widget(GNT_BOX(box
), tree
);
203 button
= gnt_button_new(_("Close"));
204 gnt_box_add_widget(GNT_BOX(box
), button
);
206 g_signal_connect_swapped(G_OBJECT(button
), "activate", G_CALLBACK(gnt_widget_destroy
), box
);
207 g_signal_connect(G_OBJECT(box
), "destroy", G_CALLBACK(reset_email_dialog
), NULL
);
211 finch_notify_emails(PurpleConnection
*gc
, size_t count
, gboolean detailed
,
212 const char **subjects
, const char **froms
, const char **tos
,
215 PurpleAccount
*account
= purple_connection_get_account(gc
);
216 GString
*message
= g_string_new(NULL
);
225 g_string_append_printf(message
,
226 ngettext("%s (%s) has %d new message.",
227 "%s (%s) has %d new messages.",
229 tos
? *tos
: purple_account_get_username(account
),
230 purple_account_get_protocol_name(account
), (int)count
);
235 gboolean newwin
= (emaildialog
.window
== NULL
);
238 setup_email_dialog();
240 to
= g_strdup_printf("%s (%s)", tos
? *tos
: purple_account_get_username(account
),
241 purple_account_get_protocol_name(account
));
242 gnt_tree_add_row_after(GNT_TREE(emaildialog
.tree
), GINT_TO_POINTER(++key
),
243 gnt_tree_create_row(GNT_TREE(emaildialog
.tree
), to
,
244 froms
? *froms
: "[Unknown sender]",
249 gnt_widget_show(emaildialog
.window
);
251 gnt_window_present(emaildialog
.window
);
255 ret
= finch_notify_common(PURPLE_NOTIFY_EMAIL
, PURPLE_NOTIFY_MSG_INFO
,
256 _("New Mail"), _("You have mail!"), message
->str
);
257 g_string_free(message
, TRUE
);
262 finch_notify_email(PurpleConnection
*gc
, const char *subject
, const char *from
,
263 const char *to
, const char *url
)
265 return finch_notify_emails(gc
, 1, subject
!= NULL
,
266 subject
? &subject
: NULL
,
272 /** User information. **/
273 static GHashTable
*userinfo
;
276 userinfo_hash(PurpleAccount
*account
, const char *who
)
279 g_snprintf(key
, sizeof(key
), "%s - %s", purple_account_get_username(account
), purple_normalize(account
, who
));
280 return g_utf8_strup(key
, -1);
284 remove_userinfo(GntWidget
*widget
, gpointer key
)
286 g_hash_table_remove(userinfo
, key
);
290 purple_notify_user_info_get_xhtml(PurpleNotifyUserInfo
*user_info
)
295 text
= g_string_new("<span>");
297 for (l
= purple_notify_user_info_get_entries(user_info
); l
!= NULL
;
299 PurpleNotifyUserInfoEntry
*user_info_entry
= l
->data
;
300 PurpleNotifyUserInfoEntryType type
= purple_notify_user_info_entry_get_type(user_info_entry
);
301 const char *label
= purple_notify_user_info_entry_get_label(user_info_entry
);
302 const char *value
= purple_notify_user_info_entry_get_value(user_info_entry
);
304 /* Handle the label/value pair itself */
305 if (type
== PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER
)
306 g_string_append(text
, "<u>");
308 g_string_append_printf(text
, "<b>%s</b>", label
);
309 g_string_append(text
, "<span>");
311 g_string_append(text
, ": ");
313 char *strip
= purple_markup_strip_html(value
);
314 g_string_append(text
, strip
);
317 g_string_append(text
, "</span>");
318 if (type
== PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER
)
319 g_string_append(text
, "</u>");
320 else if (type
== PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK
)
321 g_string_append(text
, "<HR/>");
322 g_string_append(text
, "<BR/>");
324 g_string_append(text
, "</span>");
326 return g_string_free(text
, FALSE
);
330 finch_notify_userinfo(PurpleConnection
*gc
, const char *who
, PurpleNotifyUserInfo
*user_info
)
335 char *key
= userinfo_hash(purple_connection_get_account(gc
), who
);
337 info
= purple_notify_user_info_get_xhtml(user_info
);
339 ui_handle
= g_hash_table_lookup(userinfo
, key
);
340 if (ui_handle
!= NULL
) {
341 GntTextView
*msg
= GNT_TEXT_VIEW(g_object_get_data(G_OBJECT(ui_handle
), "info-widget"));
342 char *strip
= purple_markup_strip_html(info
);
343 int tvw
, tvh
, width
, height
, ntvw
, ntvh
;
345 while (GNT_WIDGET(ui_handle
)->parent
)
346 ui_handle
= GNT_WIDGET(ui_handle
)->parent
;
347 gnt_widget_get_size(GNT_WIDGET(ui_handle
), &width
, &height
);
348 gnt_widget_get_size(GNT_WIDGET(msg
), &tvw
, &tvh
);
350 gnt_text_view_clear(msg
);
351 if (!gnt_util_parse_xhtml_to_textview(info
, msg
))
352 gnt_text_view_append_text_with_flags(msg
, strip
, GNT_TEXT_FLAG_NORMAL
);
353 gnt_text_view_scroll(msg
, 0);
354 gnt_util_get_text_bound(strip
, &ntvw
, &ntvh
);
358 gnt_screen_resize_widget(GNT_WIDGET(ui_handle
), width
+ MAX(0, ntvw
- tvw
), height
+ MAX(0, ntvh
- tvh
));
362 primary
= g_strdup_printf(_("Info for %s"), who
);
363 ui_handle
= finch_notify_formatted(_("Buddy Information"), primary
, NULL
, info
);
364 g_hash_table_insert(userinfo
, key
, ui_handle
);
366 g_signal_connect(G_OBJECT(ui_handle
), "destroy", G_CALLBACK(remove_userinfo
), key
);
374 notify_button_activated(GntWidget
*widget
, PurpleNotifySearchButton
*b
)
377 PurpleAccount
*account
= g_object_get_data(G_OBJECT(widget
), "notify-account");
378 gpointer data
= g_object_get_data(G_OBJECT(widget
), "notify-data");
380 list
= gnt_tree_get_selection_text_list(GNT_TREE(g_object_get_data(G_OBJECT(widget
), "notify-tree")));
382 b
->callback(purple_account_get_connection(account
), list
, data
);
383 g_list_foreach(list
, (GFunc
)g_free
, NULL
);
388 finch_notify_sr_new_rows(PurpleConnection
*gc
,
389 PurpleNotifySearchResults
*results
, void *data
)
391 GntTree
*tree
= GNT_TREE(data
);
394 /* XXX: Do I need to empty the tree here? */
396 for (o
= results
->rows
; o
; o
= o
->next
)
398 gnt_tree_add_row_after(GNT_TREE(tree
), o
->data
,
399 gnt_tree_create_row_from_list(GNT_TREE(tree
), o
->data
),
405 finch_notify_searchresults(PurpleConnection
*gc
, const char *title
,
406 const char *primary
, const char *secondary
,
407 PurpleNotifySearchResults
*results
, gpointer data
)
409 GntWidget
*window
, *tree
, *box
, *button
;
413 window
= gnt_vbox_new(FALSE
);
414 gnt_box_set_toplevel(GNT_BOX(window
), TRUE
);
415 gnt_box_set_title(GNT_BOX(window
), title
);
416 gnt_box_set_fill(GNT_BOX(window
), TRUE
);
417 gnt_box_set_pad(GNT_BOX(window
), 0);
418 gnt_box_set_alignment(GNT_BOX(window
), GNT_ALIGN_MID
);
421 gnt_box_add_widget(GNT_BOX(window
),
422 gnt_label_new_with_format(primary
, GNT_TEXT_FLAG_BOLD
));
424 gnt_box_add_widget(GNT_BOX(window
),
425 gnt_label_new_with_format(secondary
, GNT_TEXT_FLAG_NORMAL
));
427 columns
= g_list_length(results
->columns
);
428 tree
= gnt_tree_new_with_columns(columns
);
429 gnt_tree_set_show_title(GNT_TREE(tree
), TRUE
);
430 gnt_box_add_widget(GNT_BOX(window
), tree
);
433 for (iter
= results
->columns
; iter
; iter
= iter
->next
)
435 PurpleNotifySearchColumn
*column
= iter
->data
;
436 gnt_tree_set_column_title(GNT_TREE(tree
), i
, column
->title
);
440 box
= gnt_hbox_new(TRUE
);
442 for (iter
= results
->buttons
; iter
; iter
= iter
->next
)
444 PurpleNotifySearchButton
*b
= iter
->data
;
449 case PURPLE_NOTIFY_BUTTON_LABELED
:
452 case PURPLE_NOTIFY_BUTTON_CONTINUE
:
453 text
= _("Continue");
455 case PURPLE_NOTIFY_BUTTON_ADD
:
458 case PURPLE_NOTIFY_BUTTON_INFO
:
461 case PURPLE_NOTIFY_BUTTON_IM
:
464 case PURPLE_NOTIFY_BUTTON_JOIN
:
467 case PURPLE_NOTIFY_BUTTON_INVITE
:
474 button
= gnt_button_new(text
);
475 g_object_set_data(G_OBJECT(button
), "notify-account", purple_connection_get_account(gc
));
476 g_object_set_data(G_OBJECT(button
), "notify-data", data
);
477 g_object_set_data(G_OBJECT(button
), "notify-tree", tree
);
478 g_signal_connect(G_OBJECT(button
), "activate",
479 G_CALLBACK(notify_button_activated
), b
);
481 gnt_box_add_widget(GNT_BOX(box
), button
);
484 gnt_box_add_widget(GNT_BOX(window
), box
);
486 finch_notify_sr_new_rows(gc
, results
, tree
);
488 gnt_widget_show(window
);
489 g_object_set_data(G_OBJECT(window
), "notify-results", results
);
495 finch_notify_uri(const char *url
)
497 return finch_notify_common(PURPLE_NOTIFY_URI
, PURPLE_NOTIFY_MSG_INFO
,
498 _("URI"), url
, NULL
);
501 static PurpleNotifyUiOps ops
=
503 finch_notify_message
,
506 finch_notify_formatted
,
507 finch_notify_searchresults
,
508 finch_notify_sr_new_rows
,
509 finch_notify_userinfo
,
511 finch_close_notify
, /* The rest of the notify-uiops return a GntWidget.
512 These widgets should be destroyed from here. */
520 PurpleNotifyUiOps
*finch_notify_get_ui_ops()
525 void finch_notify_init()
527 userinfo
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
530 void finch_notify_uninit()
532 g_hash_table_destroy(userinfo
);