Prevent an unlikely crash during RSSyl feed properties save.
[claws.git] / src / plugins / rssyl / rssyl_feed_props.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2004 Hiroyuki Yamamoto
4  * This file (C) 2005 Andrej Kacian <andrej@kacian.sk>
5  *
6  * - Plugin preferences
7  *
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.
12  *
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.
17  *
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26
27 /* Global includes */
28 #include <glib.h>
29 #include <glib/gi18n.h>
30 #include <gdk/gdkkeysyms.h>
31
32 /* Claws Mail includes */
33 #include <mainwindow.h>
34 #include <prefs_gtk.h>
35
36 /* Local includes */
37 #include "rssyl.h"
38 #include "rssyl_feed.h"
39 #include "rssyl_feed_props.h"
40 #include "rssyl_prefs.h"
41 #include "rssyl_update_feed.h"
42
43 static void rssyl_gtk_prop_store(RFolderItem *ritem)
44 {
45         gchar *url, *auth_user, *auth_pass;
46         gint x, old_ri, old_fetch_comments;
47         gboolean use_default_ri = FALSE, keep_old = FALSE;
48         FolderItem *item;
49
50         g_return_if_fail(ritem != NULL);
51         g_return_if_fail(ritem->feedprop != NULL);
52         g_return_if_fail(ritem->url != NULL);
53
54         url = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->url));
55
56         if( strlen(url) && strcmp(ritem->url, url)) {
57                 if( ritem->url ) {
58                         rssyl_passwd_set(ritem, NULL);
59                         g_free(ritem->url);
60                 }
61                 ritem->url = g_strdup(url);
62         }
63
64         ritem->auth->type = gtk_combo_box_get_active(GTK_COMBO_BOX(ritem->feedprop->auth_type));
65
66         auth_user = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->auth_username));
67         if (auth_user != NULL) {
68                 if (ritem->auth->username) {
69                         g_free(ritem->auth->username);
70                 }
71                 ritem->auth->username = g_strdup(auth_user);
72         }
73
74         auth_pass = (gchar *)gtk_entry_get_text(GTK_ENTRY(ritem->feedprop->auth_password));
75         rssyl_passwd_set(ritem, auth_pass);
76
77         use_default_ri = gtk_toggle_button_get_active(
78                         GTK_TOGGLE_BUTTON(ritem->feedprop->default_refresh_interval));
79         ritem->default_refresh_interval = use_default_ri;
80         debug_print("store: default refresh interval is %s\n",
81                         ( use_default_ri ? "ON" : "OFF" ) );
82
83         /* Use default if checkbutton is set */
84         if( use_default_ri )
85                 x = rssyl_prefs_get()->refresh;
86         else
87                 x = gtk_spin_button_get_value_as_int(
88                                 GTK_SPIN_BUTTON(ritem->feedprop->refresh_interval) );
89
90         old_ri = ritem->refresh_interval;
91         ritem->refresh_interval = x;
92
93         /* Set timer for next automatic refresh, if needed. */
94         if( x > 0 ) {
95                 if( old_ri != x || ritem->refresh_id == 0 ) {
96                         debug_print("RSSyl: GTK - refresh interval changed to %d , updating "
97                                         "timeout\n", ritem->refresh_interval);
98                         rssyl_feed_start_refresh_timeout(ritem);
99                 }
100         } else
101                 ritem->refresh_id = 0;
102
103         old_fetch_comments = ritem->fetch_comments;
104         ritem->fetch_comments = gtk_toggle_button_get_active(
105                         GTK_TOGGLE_BUTTON(ritem->feedprop->fetch_comments));
106
107         if (!old_fetch_comments && ritem->fetch_comments) {
108                 /* reset the RFolderItem's mtime to be sure we get all 
109                  * available comments */
110                  ritem->item.mtime = 0;
111         }
112         
113         ritem->fetch_comments_max_age = gtk_spin_button_get_value_as_int(
114                         GTK_SPIN_BUTTON(ritem->feedprop->fetch_comments_max_age));
115
116         keep_old = gtk_toggle_button_get_active(
117                         GTK_TOGGLE_BUTTON(ritem->feedprop->keep_old));
118         ritem->keep_old = keep_old;
119
120         ritem->silent_update =
121                 gtk_combo_box_get_active(GTK_COMBO_BOX(ritem->feedprop->silent_update));
122
123         ritem->write_heading = gtk_toggle_button_get_active(
124                         GTK_TOGGLE_BUTTON(ritem->feedprop->write_heading));
125
126         ritem->ignore_title_rename = gtk_toggle_button_get_active(
127                         GTK_TOGGLE_BUTTON(ritem->feedprop->ignore_title_rename));
128
129         ritem->ssl_verify_peer = gtk_toggle_button_get_active(
130                         GTK_TOGGLE_BUTTON(ritem->feedprop->ssl_verify_peer));
131
132         /* Store updated properties */
133         item = &ritem->item;
134         item->folder->klass->item_get_xml(item->folder, item);
135 }
136
137 static gboolean
138 rssyl_feedprop_togglebutton_toggled_cb(GtkToggleButton *tb,
139                 gpointer data)
140 {
141         gboolean active = gtk_toggle_button_get_active(tb);
142         RFeedProp *feedprop = (RFeedProp *)data;
143         GtkWidget *sb = NULL;
144
145         if( (GtkWidget *)tb == feedprop->default_refresh_interval ) {
146                 active = !active;
147                 sb = feedprop->refresh_interval;
148         } else if( (GtkWidget *)tb == feedprop->fetch_comments ) {
149                 sb = feedprop->fetch_comments_max_age;
150         }
151
152         g_return_val_if_fail(sb != NULL, FALSE);
153
154         gtk_widget_set_sensitive(sb, active);
155
156         return FALSE;
157 }
158
159 static void
160 rssyl_feedprop_auth_type_changed_cb(GtkComboBox *cb, gpointer data)
161 {
162         RFeedProp *feedprop = (RFeedProp *)data;
163         gboolean enable = (FEED_AUTH_NONE != gtk_combo_box_get_active(cb));
164         gtk_widget_set_sensitive(GTK_WIDGET(feedprop->auth_username), enable);
165         gtk_widget_set_sensitive(GTK_WIDGET(feedprop->auth_password), enable);
166 }
167
168 static gboolean
169 rssyl_props_cancel_cb(GtkWidget *widget, gpointer data)
170 {
171         RFolderItem *ritem = (RFolderItem *)data;
172
173         debug_print("RSSyl: Cancel pressed\n");
174
175         gtk_widget_destroy(ritem->feedprop->window);
176
177         return FALSE;
178 }
179
180 static gboolean
181 rssyl_props_ok_cb(GtkWidget *widget, gpointer data)
182 {
183         RFolderItem *ritem = (RFolderItem *)data;
184
185         debug_print("RSSyl: OK pressed\n");
186         rssyl_gtk_prop_store(ritem);
187
188         gtk_widget_destroy(ritem->feedprop->window);
189
190         return FALSE;
191 }
192
193 static gboolean
194 rssyl_props_trim_cb(GtkWidget *widget, gpointer data)
195 {
196         RFolderItem *ritem = (RFolderItem *)data;
197         gboolean k = ritem->keep_old;
198
199         if( k )
200                 ritem->keep_old = FALSE;
201
202         rssyl_update_feed(ritem, FALSE);
203
204         if( k )
205                 ritem->keep_old = TRUE;
206
207         return FALSE;
208 }
209
210 static gboolean
211 rssyl_props_key_press_cb(GtkWidget *widget, GdkEventKey *event,
212                 gpointer data)
213 {
214         if (event) {
215                 switch (event->keyval) {
216                         case GDK_Escape:
217                                 rssyl_props_cancel_cb(widget, data);
218                                 return TRUE;
219                         case GDK_Return:
220                         case GDK_KP_Enter:
221                                 rssyl_props_ok_cb(widget, data);
222                                 return TRUE;
223                         default:
224                                 break;
225                 }
226         }
227
228         return FALSE;
229 }
230
231 void rssyl_gtk_prop(RFolderItem *ritem)
232 {
233         MainWindow *mainwin = mainwindow_get_mainwindow();
234         RFeedProp *feedprop;
235         GtkWidget *vbox, *frame, *label, *hbox,
236                 *inner_vbox, *auth_hbox, *auth_user_label, *auth_pass_label,
237                 *bbox, *cancel_button, *cancel_align,
238                 *cancel_hbox, *cancel_image, *cancel_label, *ok_button, *ok_align,
239                 *ok_hbox, *ok_image, *ok_label, *trim_button, *silent_update_label;
240         GtkObject *adj;
241         gint refresh;
242
243         g_return_if_fail(ritem != NULL);
244
245         feedprop = g_new0(RFeedProp, 1);
246
247         /**** Create required widgets ****/
248
249         /* Window */
250         feedprop->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
251
252         /* URL entry */
253         feedprop->url = gtk_entry_new();
254         gtk_entry_set_text(GTK_ENTRY(feedprop->url), ritem->url);
255
256         /* URL auth type combo */
257 #if !GTK_CHECK_VERSION(2, 24, 0)
258         feedprop->auth_type = gtk_combo_box_new_text();
259         gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->auth_type),
260 #else
261         feedprop->auth_type = gtk_combo_box_text_new();
262         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->auth_type),
263 #endif
264                         _("No authentication"));
265 #if !GTK_CHECK_VERSION(2, 24, 0)
266         gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->auth_type),
267 #else
268         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->auth_type),
269 #endif
270                         _("HTTP Basic authentication"));
271         gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->auth_type),
272                         ritem->auth->type);
273
274         /* Auth username */
275         feedprop->auth_username = gtk_entry_new();
276         gtk_entry_set_text(GTK_ENTRY(feedprop->auth_username),
277                         ritem->auth->username);
278
279         /* Auth password */
280         feedprop->auth_password = gtk_entry_new();
281         gtk_entry_set_visibility(GTK_ENTRY(feedprop->auth_password), FALSE);
282         gchar *pwd = rssyl_passwd_get(ritem);
283         gtk_entry_set_text(GTK_ENTRY(feedprop->auth_password), pwd);
284         if (pwd != NULL) {
285                 memset(pwd, 0, strlen(pwd));
286                 g_free(pwd);
287         }
288
289         /* "Use default refresh interval" checkbutton */
290         feedprop->default_refresh_interval = gtk_check_button_new_with_mnemonic(
291                         _("Use default refresh interval"));
292         gtk_toggle_button_set_active(
293                         GTK_TOGGLE_BUTTON(feedprop->default_refresh_interval),
294                         ritem->default_refresh_interval);
295
296         if( ritem->refresh_interval >= 0 && !ritem->default_refresh_interval )
297                 refresh = ritem->refresh_interval;
298         else
299                 refresh = rssyl_prefs_get()->refresh;
300
301         /* "Keep old items" checkbutton */
302         feedprop->keep_old = gtk_check_button_new_with_mnemonic(
303                         _("Keep old items"));
304         gtk_toggle_button_set_active(
305                         GTK_TOGGLE_BUTTON(feedprop->keep_old),
306                         ritem->keep_old);
307
308         /* "Trim" button */
309         trim_button = gtk_button_new_with_mnemonic(_("_Trim"));
310         gtk_widget_set_tooltip_text(trim_button,
311                         _("Update feed, deleting items which are no longer in the source feed"));
312
313         feedprop->fetch_comments = gtk_check_button_new_with_mnemonic(
314                         _("Fetch comments if possible"));
315         gtk_toggle_button_set_active(
316                         GTK_TOGGLE_BUTTON(feedprop->fetch_comments),
317                         ritem->fetch_comments);
318
319         /* Fetch comments max age spinbutton */
320         adj = gtk_adjustment_new(ritem->fetch_comments_max_age,
321                         -1, 100000, 1, 10, 0);
322         feedprop->fetch_comments_max_age = gtk_spin_button_new(GTK_ADJUSTMENT(adj),
323                         1, 0);
324
325         /* Refresh interval spinbutton */
326         adj = gtk_adjustment_new(refresh,
327                         0, 100000, 10, 100, 0);
328         feedprop->refresh_interval = gtk_spin_button_new(GTK_ADJUSTMENT(adj),
329                         1, 0);
330
331         /* Silent update - combobox */
332 #if !GTK_CHECK_VERSION(2, 24, 0)
333         feedprop->silent_update = gtk_combo_box_new_text();
334         gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
335 #else
336         feedprop->silent_update = gtk_combo_box_text_new();
337         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
338 #endif
339                         _("Always mark it as new"));
340 #if !GTK_CHECK_VERSION(2, 24, 0)
341         gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
342 #else
343         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
344 #endif
345                         _("Only mark it as new if its text has changed"));
346 #if !GTK_CHECK_VERSION(2, 24, 0)
347         gtk_combo_box_append_text(GTK_COMBO_BOX(feedprop->silent_update),
348 #else
349         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(feedprop->silent_update),
350 #endif
351                         _("Never mark it as new"));
352         gtk_combo_box_set_active(GTK_COMBO_BOX(feedprop->silent_update),
353                         ritem->silent_update);
354
355         feedprop->write_heading = gtk_check_button_new_with_mnemonic(
356                         _("Add item title to the top of message"));
357         gtk_toggle_button_set_active(
358                         GTK_TOGGLE_BUTTON(feedprop->write_heading),
359                         ritem->write_heading);
360
361         /* Ignore title rename - checkbox */
362         feedprop->ignore_title_rename = gtk_check_button_new_with_mnemonic(
363                         _("Ignore title rename"));
364         gtk_toggle_button_set_active(
365                         GTK_TOGGLE_BUTTON(feedprop->ignore_title_rename),
366                         ritem->ignore_title_rename);
367         gtk_widget_set_tooltip_text(feedprop->ignore_title_rename,
368                         _("Enable this to keep current folder name, even if feed author changes title of the feed."));
369
370         /* Verify SSL peer certificate */
371         feedprop->ssl_verify_peer = gtk_check_button_new_with_label(
372                         _("Verify SSL certificate validity"));
373         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(feedprop->ssl_verify_peer),
374                         ritem->ssl_verify_peer);
375
376         /* === Now pack all the widgets */
377         vbox = gtk_vbox_new(FALSE, 5);
378         gtk_container_add(GTK_CONTAINER(feedprop->window), vbox);
379         gtk_container_set_border_width(GTK_CONTAINER(feedprop->window), 10);
380
381         inner_vbox = gtk_vbox_new(FALSE, 7);
382         gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->url, FALSE, FALSE, 0);
383         gtk_entry_set_activates_default(GTK_ENTRY(feedprop->url), TRUE);
384
385         /* Auth combo + user (label + entry) + pass (label + entry) */
386         auth_hbox = gtk_hbox_new(FALSE, 7);
387         gtk_box_pack_start(GTK_BOX(auth_hbox), feedprop->auth_type, FALSE, FALSE, 0);
388         g_signal_connect(G_OBJECT(feedprop->auth_type), "changed",
389                         G_CALLBACK(rssyl_feedprop_auth_type_changed_cb),
390                         (gpointer) feedprop);
391         g_signal_emit_by_name(G_OBJECT(feedprop->auth_type), "changed");
392         auth_user_label = gtk_label_new(_("User name"));
393         gtk_box_pack_start(GTK_BOX(auth_hbox), auth_user_label, FALSE, FALSE, 0);
394         gtk_box_pack_start(GTK_BOX(auth_hbox), feedprop->auth_username, FALSE, FALSE, 0);
395         auth_pass_label = gtk_label_new(_("Password"));
396         gtk_box_pack_start(GTK_BOX(auth_hbox), auth_pass_label, FALSE, FALSE, 0);
397         gtk_box_pack_start(GTK_BOX(auth_hbox), feedprop->auth_password, FALSE, FALSE, 0);
398         gtk_box_pack_start(GTK_BOX(inner_vbox), auth_hbox, FALSE, FALSE, 0);
399
400         /* Verify SSL peer certificate - checkbutton */
401         gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->ssl_verify_peer, FALSE, FALSE, 0);
402         /* Ignore title rename - checkbutton */
403         gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->ignore_title_rename, FALSE, FALSE, 0);
404
405         PACK_FRAME (vbox, frame, _("Source URL"));
406         gtk_container_set_border_width(GTK_CONTAINER(inner_vbox), 7);
407         gtk_container_add(GTK_CONTAINER(frame), inner_vbox);
408
409         inner_vbox = gtk_vbox_new(FALSE, 7);
410         /* Fetch comments - checkbutton */
411         g_signal_connect(G_OBJECT(feedprop->fetch_comments), "toggled",
412                         G_CALLBACK(rssyl_feedprop_togglebutton_toggled_cb),
413                         (gpointer)feedprop);
414         gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->fetch_comments, FALSE, FALSE, 0);
415
416         hbox = gtk_hbox_new(FALSE, 7);
417         /* Fetch comments max age - label */
418         label = gtk_label_new(_("Fetch comments on posts aged less than"));
419         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
420         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
421         /* Fetch comments max age - spinbutton */
422         gtk_widget_set_sensitive(feedprop->fetch_comments_max_age,
423                         ritem->fetch_comments);
424         gtk_box_pack_start(GTK_BOX(hbox), feedprop->fetch_comments_max_age, FALSE, FALSE, 0);
425         /* Fetch comments max age - units label */
426         label = gtk_label_new(g_strconcat(_("day(s)"), "<small>    ",
427                                 _("Set to -1 to fetch all comments"), "</small>", NULL));
428         gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
429         gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
430         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
431         gtk_box_pack_start(GTK_BOX(inner_vbox), hbox, FALSE, FALSE, 0);
432
433         PACK_FRAME (vbox, frame, _("Comments"));
434         gtk_container_set_border_width(GTK_CONTAINER(inner_vbox), 7);
435         gtk_container_add(GTK_CONTAINER(frame), inner_vbox);
436
437         inner_vbox = gtk_vbox_new(FALSE, 7);
438         hbox = gtk_hbox_new(FALSE, 7);
439         /* Write heading - checkbox */
440         gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->write_heading, FALSE, FALSE, 0);
441         /* Keep old items - checkbutton */
442         gtk_box_pack_start(GTK_BOX(hbox), feedprop->keep_old, FALSE, FALSE, 0);
443         /* 'Trim' - button */
444         gtk_box_pack_start(GTK_BOX(hbox), trim_button, FALSE, FALSE, 0);
445         g_signal_connect(G_OBJECT(trim_button), "clicked",
446                         G_CALLBACK(rssyl_props_trim_cb), ritem);
447         gtk_box_pack_start(GTK_BOX(inner_vbox), hbox, FALSE, FALSE, 0);
448
449         hbox = gtk_hbox_new(FALSE, 7);
450         /* Silent update - label */
451         silent_update_label = gtk_label_new(_("If an item changes"));
452         gtk_box_pack_start(GTK_BOX(hbox), silent_update_label, FALSE, FALSE, 0);
453         gtk_box_pack_start(GTK_BOX(hbox), feedprop->silent_update, FALSE, FALSE, 0);
454         gtk_box_pack_start(GTK_BOX(inner_vbox), hbox, FALSE, FALSE, 0);
455
456         PACK_FRAME (vbox, frame, _("Items"));
457         gtk_container_set_border_width(GTK_CONTAINER(inner_vbox), 7);
458         gtk_container_add(GTK_CONTAINER(frame), inner_vbox);
459
460         inner_vbox = gtk_vbox_new(FALSE, 7);
461         /* Use default refresh interval - checkbutton */
462         gtk_box_pack_start(GTK_BOX(inner_vbox), feedprop->default_refresh_interval, FALSE, FALSE, 0);
463         g_signal_connect(G_OBJECT(feedprop->default_refresh_interval), "toggled",
464                         G_CALLBACK(rssyl_feedprop_togglebutton_toggled_cb),
465                         (gpointer)feedprop);
466
467         hbox = gtk_hbox_new(FALSE, 7);
468         /* Refresh interval - label */
469         label = gtk_label_new(_("Refresh interval"));
470         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
471         /* Refresh interval - spinbutton */
472         gtk_widget_set_sensitive(feedprop->refresh_interval,
473                         !ritem->default_refresh_interval);
474         gtk_box_pack_start(GTK_BOX(hbox), feedprop->refresh_interval, FALSE, FALSE, 0);
475         /* Refresh interval - units label */
476         label = gtk_label_new(g_strconcat(_("minute(s)"), "<small>    ",
477                         _("Set to 0 to disable automatic refreshing for this feed"),
478                         "</small>", NULL));
479         gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
480         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
481         gtk_box_pack_start(GTK_BOX(inner_vbox), hbox, FALSE, FALSE, 0);
482
483         PACK_FRAME (vbox, frame, _("Refresh"));
484         gtk_container_set_border_width(GTK_CONTAINER(inner_vbox), 7);
485         gtk_container_add(GTK_CONTAINER(frame), inner_vbox);
486
487         /* Buttonbox */
488         bbox = gtk_hbutton_box_new();
489         gtk_container_set_border_width(GTK_CONTAINER(bbox), 5);
490         gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
491         gtk_box_set_spacing(GTK_BOX(bbox), 5);
492         gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
493
494         /* Cancel button */
495         cancel_button = gtk_button_new();
496         gtk_container_add(GTK_CONTAINER(bbox), cancel_button);
497
498         cancel_align = gtk_alignment_new(0.5, 0.5, 0, 0);
499         gtk_container_add(GTK_CONTAINER(cancel_button), cancel_align);
500
501         cancel_hbox = gtk_hbox_new(FALSE, 2);
502         gtk_container_add(GTK_CONTAINER(cancel_align), cancel_hbox);
503
504         cancel_image = gtk_image_new_from_stock(GTK_STOCK_CANCEL,
505                         GTK_ICON_SIZE_BUTTON);
506         gtk_box_pack_start(GTK_BOX(cancel_hbox), cancel_image, FALSE, FALSE, 0);
507
508         cancel_label = gtk_label_new_with_mnemonic(_("_Cancel"));
509         gtk_box_pack_end(GTK_BOX(cancel_hbox), cancel_label, FALSE, FALSE, 0);
510
511         g_signal_connect(G_OBJECT(cancel_button), "clicked",
512                         G_CALLBACK(rssyl_props_cancel_cb), ritem);
513
514         /* OK button */
515         ok_button = gtk_button_new();
516         gtk_container_add(GTK_CONTAINER(bbox), ok_button);
517         GTK_WIDGET_SET_FLAGS(ok_button, GTK_CAN_DEFAULT );
518
519         ok_align = gtk_alignment_new(0.5, 0.5, 0, 0);
520         gtk_container_add(GTK_CONTAINER(ok_button), ok_align);
521
522         ok_hbox = gtk_hbox_new(FALSE, 2);
523         gtk_container_add(GTK_CONTAINER(ok_align), ok_hbox);
524
525         ok_image = gtk_image_new_from_stock(GTK_STOCK_OK,
526                         GTK_ICON_SIZE_BUTTON);
527         gtk_box_pack_start(GTK_BOX(ok_hbox), ok_image, FALSE, FALSE, 0);
528
529         ok_label = gtk_label_new_with_mnemonic(_("_OK"));
530         gtk_box_pack_end(GTK_BOX(ok_hbox), ok_label, FALSE, FALSE, 0);
531
532         g_signal_connect(G_OBJECT(ok_button), "clicked",
533                         G_CALLBACK(rssyl_props_ok_cb), ritem);
534
535         /* Set some misc. stuff */
536         gtk_window_set_title(GTK_WINDOW(feedprop->window),
537                         g_strdup(_("Set feed properties")) );
538         gtk_window_set_modal(GTK_WINDOW(feedprop->window), TRUE);
539         gtk_window_set_transient_for(GTK_WINDOW(feedprop->window),
540                         GTK_WINDOW(mainwin->window) );
541
542         /* Attach callbacks to handle Enter and Escape keys */
543         g_signal_connect(G_OBJECT(feedprop->window), "key_press_event",
544                         G_CALLBACK(rssyl_props_key_press_cb), ritem);
545
546         /* ...and voila! */
547         gtk_widget_show_all(feedprop->window);
548         gtk_widget_grab_default(ok_button);
549
550         /* Unselect the text in URL entry */
551         gtk_editable_select_region(GTK_EDITABLE(feedprop->url), 0, 0);
552
553         ritem->feedprop = feedprop;
554 }