1 /*
2  * Osmo - a handy personal organizer
3  *
4  * Copyright (C) 2007-2009 Tomasz Maka <pasp@users.sourceforge.net>
5  *               2007-2009 Piotr Maka <silloz@users.sourceforge.net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #include "about.h"
23 #include "i18n.h"
24 #include "options_prefs.h"
25 #include "stock_icons.h"
26 #include "utils_gui.h"
27 
28 static void     display_license         (GUI *appGUI);
29 static void     display_help            (GUI *appGUI);
30 static void     add_credits_section     (const gchar *section_title, OsmoCreditEntry *credits,
31                                          guint32 n_credits, GUI *appGUI);
32 static void     display_about           (GUI *appGUI);
33 static void     about_switch_buttons    (gboolean left, GUI *appGUI);
34 static void     button_released_cb      (GtkButton *button, GUI *appGUI);
35 static void     gui_create_about        (GtkWidget *vbox_top, GUI *appGUI);
36 
37 static OsmoCreditEntry credits_programming[] = {
38     { NULL, "Tomasz Mąka", "pasp@users.sourceforge.net" },
39     { NULL, "Piotr Mąka", "silloz@users.sourceforge.net" }
40 };
41 
42 static OsmoCreditEntry credits_graphics[] = {
43     { NULL, "Maja Kocoń", "http://pinky-babble.org" }
44 };
45 
46 static OsmoCreditEntry credits_contributors[] = {
47     { NULL, "Markus Dahms", "mad@automagically.de" },
48     { NULL, "Nacho Alonso González", "nacho.alonso.gonzalez@gmail.com" },
49     { NULL, "Maxim Gordienko", "mgordienko@users.sourceforge.net" }
50 };
51 
52 static OsmoCreditEntry credits_translators[] = {
53     { "bg",     "Borislav Totev", "btotev@hotmail.com" },
54     { "ca",     "Roger Adell", "roger.adell@gmail.com" },
55     { "cs",     "Jaroslav Lichtblau", "dragonlord@seznam.cz" },
56     { "da",     "Joakim Seeberg", "joak@users.sourceforge.net" },       /* da */
57     { NULL,     "Joe Hansen", "joedalton2@yahoo.dk" },                  /* da */
58     { "de",     "Markus Dahms", "mad@automagically.de" },               /* de */
59     { NULL,     "Mario Blättermann", "mariobl@gnome.org" },             /* de */
60     { NULL,     "Roland Siegbert", "roland.siegbert@gmail.com" },       /* de */
61     { "el",     "Konstantinos Tsakaloglou", "tsakf@yahoo.com" },
62     { "en_GB",  "Steve Cook (Yorvyk)", "yorvik.ubunto@googlemail.com" },
63     { "es",     "Nacho Alonso González", "nacho.alonso.gonzalez@gmail.com" },
64     { "fi",     "Toivo Miettinen", "toivo.miettinen@panuma.fi" },
65     { "fr",     "Jean-Jacques Moulinier", "postmaster@moulinier.net" }, /* fr */
66     { NULL,     "Rémi Roupsard", "remi.roupsard@gmail.com"},            /* fr */
67     { NULL,     "Lylliann Essandre", "lylambda@gmail.com"},             /* fr */
68     { "gl",     "Miguel Anxo Bouzada", "mbouzada@gmail.com"},           /* gl */
69     { NULL,     "xesusmosquera", "xesusmosquera@gmail.com"},            /* gl */
70     { "gl_ES",  "Miguel Anxo Bouzada", "mbouzada@gmail.com"},           /* gl_ES */
71     { NULL,     "xesusmosquera", "xesusmosquera@gmail.com"},            /* gl_ES */
72 	{ "he",     "Hebrew", "Hebrew@transifex"},
73     { "hu",     "Peter Polonkai", "polesz@nedudu.hu" },
74     { "it",     "Bautz", "bautz@email.com" },                           /* it */
75     { NULL,     "Calogero Bonasia", "kbonasia@gmail.com" },             /* it */
76     { "ja",     "Norihiro Yoneda", "aoba@avis.ne.jp" },
77     { "lt",     "Vaidotas Kazla", "joshas@gmail.com" },                 /* lt */
78 	{ NULL,     "Moo", "Moo@transifex" },                               /* lt */
79     { "nl",     "Tiger!P", "tigerp@tigerp.net" },
80     { "pl",     "Piotr Mąka", "silloz@users.sourceforge.net" },
81     { "pt",     "Bruno Miguel", "brunoalexandremiguel@gmail.com" },
82     { "pt_BR",  "Átila Camurça", "camurca.home@gmail.com" },            /* pt_BR */
83     { NULL,     "Alexandro Casanova", "shorterfire@gmail.com" },        /* pt_BR */
84     { "ro",     "Alexandru Gavriș", "alexandrugavrish@gmail.com" },     /* ro */
85     { "ru",     "Vyacheslav A. Trishkin", "dedovsk@mail.ru" },          /* ru */
86     { NULL,     "Alexander Vozhennikov", "vodka_ploho@mail.ru" },       /* ru */
87     { NULL,     "Sergey Panasenko", "nitay@users.sourceforge.net" },    /* ru */
88     { NULL,     "Dmitry Korzhevin", "dkorzhevin@lsupport.net" },        /* ru */
89 	{ "sr",     "Саша Петровић", "salepetronije@gmail.com" },           /* sr */
90     { "sv",     "Niklas Grahn", "terra.unknown@yahoo.com" },
91     { "te",     "Praveen Illa", "mail2ipn@gmail.com" },
92     { "tr",     "Hasan Yılmaz", "hasanyilmaz@users.sourceforge.net" },
93     { "uk",     "Sergey Panasenko", "nitay@users.sourceforge.net" },    /* uk */
94     { NULL,     "Dmitry Korzhevin", "dkorzhevin@lsupport.net" },        /* uk */
95     { NULL,     "Yury Bulka", "yurkobb@gmail.com" },                    /* uk */
96     { "ur",     "Muhammad Ali Makki", "makkiabufaris@aol.com" },        /* ur */
97     { "ur_PK",  "Muhammad Ali Makki", "makkiabufaris@aol.com" },        /* ur_pk */
98     { "zh_CN",  "Sasaqqdan", "sasaqqdan@gmail.com" },                   /* zh_cn */
99     { NULL,     "Darcsis", "darcsis@gmail.com" }                        /* zh_cn */
100 };
101 
102 /* ========================================================================== */
103 
104 static void
close_window(GtkWidget * widget,GtkWidget * window)105 close_window (GtkWidget *widget, GtkWidget *window)
106 {
107     gtk_widget_destroy (window);
108 }
109 
110 /* ========================================================================== */
111 
112 static gint
key_press(GtkWidget * widget,GdkEventKey * event,GUI * appGUI)113 key_press (GtkWidget *widget, GdkEventKey *event, GUI *appGUI)
114 {
115     switch (event->keyval) {
116 
117         case GDK_KEY_Escape:
118             close_window (NULL, widget);
119             return TRUE;
120 
121         case GDK_KEY_Page_Down:
122             about_switch_buttons (FALSE, appGUI);
123             return TRUE;
124 
125         case GDK_KEY_Page_Up:
126             about_switch_buttons (TRUE, appGUI);
127             return TRUE;
128 
129     }
130 
131     return FALSE;
132 }
133 
134 /* ========================================================================== */
135 
136 GtkWidget *
opt_create_about_window(GUI * appGUI)137 opt_create_about_window (GUI *appGUI)
138 {
139     GtkWidget *window, *vbox_top;
140     GtkWidget *hbuttonbox, *button_close;
141 
142     window = utl_gui_create_window (_("About"), 510, 600, appGUI);
143     gtk_widget_set_events (window, GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
144     g_signal_connect (G_OBJECT (window), "key_press_event", G_CALLBACK (key_press), appGUI);
145 
146     vbox_top = gtk_box_new (GTK_ORIENTATION_VERTICAL, VBOX_SPACING);
147     gtk_container_add (GTK_CONTAINER (window), vbox_top);
148 
149     gui_create_about (vbox_top, appGUI);
150 
151     /* Close button */
152     hbuttonbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
153     gtk_box_pack_start (GTK_BOX (vbox_top), hbuttonbox, FALSE, TRUE, 0);
154     gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
155     gtk_box_set_spacing (GTK_BOX (hbuttonbox), HBOX_SPACING);
156 
157     button_close = gtk_button_new_with_mnemonic(_("_Close"));
158     gtk_container_add (GTK_CONTAINER (hbuttonbox), button_close);
159     gtk_widget_set_can_default (button_close, TRUE);
160     g_signal_connect (G_OBJECT (button_close), "clicked", G_CALLBACK (close_window), window);
161     gtk_widget_grab_focus (button_close);
162 
163     gtk_widget_show_all (vbox_top);
164 
165     return window;
166 }
167 
168 /* ========================================================================== */
169 
170 static void
display_license(GUI * appGUI)171 display_license (GUI *appGUI)
172 {
173     const gchar license_text[] = {
174         "\nThis program is free software; you can redistribute it and/or modify "
175         "it under the terms of the GNU General Public License as published by "
176         "the Free Software Foundation; either version 2 of the License, or "
177         "(at your option) any later version."
178         "\n\n"
179         "This program is distributed in the hope that it will be useful, "
180         "but WITHOUT ANY WARRANTY; without even the implied warranty of "
181         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the "
182         "GNU General Public License for more details."
183         "\n\n"
184         "You should have received a copy of the GNU General Public License "
185         "along with this program; if not, write to the Free Software "
186         "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA."
187     };
188 
189     utl_gui_clear_text_buffer (appGUI->about_entry_buffer, &appGUI->about_entry_iter);
190     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, license_text, -1);
191     gtk_widget_grab_focus (GTK_WIDGET (appGUI->scrolled_window));
192 }
193 
194 /* ========================================================================== */
195 
196 static void
display_help(GUI * appGUI)197 display_help (GUI *appGUI)
198 {
199     const gchar *general_keys_text[] = {
200         N_("Ctrl+PageUp"),            N_("switch to previous tab"),
201         N_("Ctrl+PageDn"),            N_("switch to next tab"),
202         "Alt+1...6, F1-F4",           N_("switch to selected page"),
203         "F5",                         N_("show options window"),
204         "F6",                         N_("show about window"),
205         "F11",                        N_("toggle fullscreen mode"),
206         N_("PageUp/PageDn"),          N_("switch page in options and about tab"),
207         "Ctrl+q",                     N_("exit")
208     };
209 
210     const gchar *calendar_keys_text[] = {
211         N_("Space"),                  N_("select current date"),
212         N_("Ctrl+Space"),             N_("toggle personal data visibility"),
213         N_("Arrows"),                 N_("change day"),
214         N_("Ctrl+Up/Down"),           N_("scroll the contents in the day info panel"),
215         N_("PageUp/PageDn"),          N_("change month"),
216         N_("Home/End"),               N_("change year"),
217         "a",                          N_("toggle calendars for the previous and next month"),
218         "b",                          N_("day notes browser"),
219         "c",                          N_("assign background color to day note"),
220         "d",                          N_("date calculator"),
221         "f",                          N_("show full-year calendar"),
222         "g",                          N_("jump to date"),
223         N_("Delete"),                 N_("remove day note")
224     };
225 
226     const gchar *calendar_editor_keys_text[] = {
227         N_("Alt+Arrows"),             N_("change day"),
228         N_("Esc"),                    N_("close editor"),
229         "Ctrl+b",                     N_("toggle bold"),
230         "Ctrl+i",                     N_("toggle italic"),
231         "Ctrl+u",                     N_("toggle underline"),
232         "Ctrl+t",                     N_("toggle strikethrough"),
233         "Ctrl+m",                     N_("toggle highlight")
234     };
235 
236     const gchar *calendar_fy_keys_text[] = {
237         N_("Arrows Up/Down"),         N_("change year"),
238         "F1",                         N_("toggle alternative view"),
239         "F2",                         N_("year info"),
240         "F3",                         N_("set current year"),
241         N_("Esc"),                    N_("close full-year calendar")
242     };
243 
244 #ifdef TASKS_ENABLED
245     const gchar *tasks_keys_text[] = {
246         N_("Alt+a, Insert"),          N_("add task"),
247         N_("Alt+e, Ctrl+Enter"),      N_("edit task"),
248         N_("Alt+r, Delete"),          N_("remove task"),
249         "Ctrl+h",                     N_("toggle hidden tasks"),
250         "Ctrl+l",                     N_("activate search field"),
251         N_("Left, Right"),            N_("change category filter"),
252         N_("Esc"),                    N_("close task info panel")
253     };
254 #endif  /* TASKS_ENABLED */
255 
256 #ifdef CONTACTS_ENABLED
257     const gchar *contacts_keys_text[] = {
258         N_("Insert"),                 N_("add contact"),
259         N_("Ctrl+Enter"),             N_("edit contact"),
260         N_("Delete"),                 N_("remove contact"),
261         "Ctrl+l",                     N_("activate search field"),
262         N_("Ctrl+Up/Down"),           N_("change search mode"),
263         N_("Esc"),                    N_("close contact details panel")
264     };
265 #endif  /* CONTACTS_ENABLED */
266 
267 #ifdef NOTES_ENABLED
268     const gchar *notes_selector_keys_text[] = {
269         N_("Enter"),                  N_("open note"),
270         N_("Insert"),                 N_("add note"),
271         N_("Delete"),                 N_("remove note"),
272         N_("Ctrl+Enter"),             N_("edit note name and category"),
273         "Ctrl+l",                     N_("activate search field"),
274         N_("Left, Right"),            N_("change category filter")
275     };
276 
277 const gchar *notes_editor_keys_text[] = {
278         "Ctrl+w",                     N_("close note editor"),
279         "Ctrl+s",                     N_("save note"),
280         "Ctrl+f",                     N_("find text"),
281         "Ctrl+b",                     N_("toggle bold"),
282         "Ctrl+i",                     N_("toggle italic"),
283         "Ctrl+u",                     N_("toggle underline"),
284         "Ctrl+t",                     N_("toggle strikethrough"),
285         "Ctrl+m",                     N_("toggle highlight"),
286         "Ctrl+n",                     N_("clear selection attributes"),
287         "Ctrl+o",                     N_("open URLs"),
288         "Ctrl+.",                     N_("show document statistics")
289     };
290 #endif  /* NOTES_ENABLED */
291 
292     gchar *str;
293     gint i;
294 
295     utl_gui_clear_text_buffer (appGUI->about_entry_buffer, &appGUI->about_entry_iter);
296 
297     str = g_strdup_printf ("\n%s\n\n", _("OSMO was designed keeping in mind the user convenience, so there are many key shortcuts. Here is the full list:"));
298     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
299     g_free (str);
300 
301     /* ============================== */
302 
303     str = g_strdup_printf ("* %s\n", _("General"));
304     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1, "bold", NULL);
305     g_free (str);
306 
307     for (i = 0; i < G_N_ELEMENTS (general_keys_text) / 2; i++) {
308         str = g_strdup_printf ("\t<%s> - %s\n", gettext (general_keys_text[i*2]), gettext (general_keys_text[i*2+1]));
309         gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
310         g_free (str);
311     }
312     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
313 
314     /* ============================== */
315 
316     str = g_strdup_printf ("* %s\n", _("Calendar"));
317     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1, "bold", NULL);
318     g_free (str);
319 
320     for (i = 0; i < G_N_ELEMENTS (calendar_keys_text) / 2; i++) {
321         str = g_strdup_printf ("\t<%s> - %s\n", gettext (calendar_keys_text[i*2]), gettext (calendar_keys_text[i*2+1]));
322         gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
323         g_free (str);
324     }
325 
326     str = g_strdup_printf ("\t%s:\n", _("Note editor"));
327     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1, "bold", NULL);
328     g_free (str);
329 
330     for (i = 0; i < G_N_ELEMENTS (calendar_editor_keys_text) / 2; i++) {
331         str = g_strdup_printf ("\t<%s> - %s\n", gettext (calendar_editor_keys_text[i*2]), gettext (calendar_editor_keys_text[i*2+1]));
332         gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
333         g_free (str);
334     }
335 
336     str = g_strdup_printf ("\t%s:\n", _("Full-year calendar"));
337     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1, "bold", NULL);
338     g_free (str);
339 
340     for (i = 0; i < G_N_ELEMENTS (calendar_fy_keys_text) / 2; i++) {
341         str = g_strdup_printf ("\t<%s> - %s\n", gettext (calendar_fy_keys_text[i*2]), gettext (calendar_fy_keys_text[i*2+1]));
342         gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
343         g_free (str);
344     }
345 
346     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
347 
348     /* ============================== */
349 
350 #ifdef TASKS_ENABLED
351     str = g_strdup_printf ("* %s\n", _("Tasks"));
352     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1, "bold", NULL);
353     g_free (str);
354 
355     for (i = 0; i < G_N_ELEMENTS (tasks_keys_text) / 2; i++) {
356         str = g_strdup_printf ("\t<%s> - %s\n", gettext (tasks_keys_text[i*2]), gettext (tasks_keys_text[i*2+1]));
357         gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
358         g_free (str);
359     }
360     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
361 #endif  /* TASKS_ENABLED */
362 
363     /* ============================== */
364 
365 #ifdef CONTACTS_ENABLED
366     str = g_strdup_printf ("* %s\n", _("Contacts"));
367     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1, "bold", NULL);
368     g_free (str);
369 
370     for (i = 0; i < G_N_ELEMENTS (contacts_keys_text) / 2; i++) {
371         str = g_strdup_printf ("\t<%s> - %s\n", gettext (contacts_keys_text[i*2]), gettext (contacts_keys_text[i*2+1]));
372         gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
373         g_free (str);
374     }
375     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
376 #endif  /* CONTACTS_ENABLED */
377 
378     /* ============================== */
379 
380 #ifdef NOTES_ENABLED
381     str = g_strdup_printf ("* %s\n", _("Notes"));
382     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1, "bold", NULL);
383     g_free (str);
384 
385     str = g_strdup_printf ("\t%s:\n", _("Selector"));
386     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1, "bold", NULL);
387     g_free (str);
388 
389     for (i = 0; i < G_N_ELEMENTS (notes_selector_keys_text) / 2; i++) {
390         str = g_strdup_printf ("\t<%s> - %s\n", gettext (notes_selector_keys_text[i*2]), gettext (notes_selector_keys_text[i*2+1]));
391         gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
392         g_free (str);
393     }
394 
395     str = g_strdup_printf ("\t%s:\n", _("Editor"));
396     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1, "bold", NULL);
397     g_free (str);
398 
399     for (i = 0; i < G_N_ELEMENTS (notes_editor_keys_text) / 2; i++) {
400         str = g_strdup_printf ("\t<%s> - %s\n", gettext (notes_editor_keys_text[i*2]), gettext (notes_editor_keys_text[i*2+1]));
401         gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
402         g_free (str);
403     }
404     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
405 #endif  /* NOTES_ENABLED */
406 
407     gtk_widget_grab_focus (GTK_WIDGET (appGUI->scrolled_window));
408 }
409 
410 /* ========================================================================== */
411 
412 static void
add_credits_section(const gchar * section_title,OsmoCreditEntry * credits,guint32 n_credits,GUI * appGUI)413 add_credits_section (const gchar *section_title, OsmoCreditEntry *credits, guint32 n_credits, GUI *appGUI)
414 {
415     gint32 i, j, d;
416     gchar *s;
417 
418     s = g_strdup_printf ("\n %s:\n", section_title);
419     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer,
420                                               &appGUI->about_entry_iter, s, -1, "bold", NULL);
421     g_free (s);
422 
423     for (i = 0; i < n_credits; i++) {
424 
425         if (credits[i].tag) {
426             if(strlen(credits[i].tag) > 2) {
427                 s = g_strdup_printf ("  [%s]", credits[i].tag);
428             } else {
429                 s = g_strdup_printf ("  [%s]   ", credits[i].tag);
430             }
431         } else {
432             s = g_strdup ("         ");
433         }
434 
435         gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer,
436                                                   &appGUI->about_entry_iter, s, -1, "fixed", NULL);
437         g_free (s);
438 
439         s = g_strdup_printf ("  %s <", credits[i].name);
440         gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, s, -1);
441         g_free (s);
442 
443 		j = d = 0;
444 		while (credits[i].email[j] != '\0')
445 			if (credits[i].email[j++] == '.') d++;
446 
447 		if (d == 0) {
448             gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, credits[i].email, -1);
449 		} else {
450 			utl_gui_url_insert_link (&appGUI->about_links_list,
451 									 &appGUI->about_link_index, appGUI->about_textview,
452 									 &appGUI->about_entry_iter, config.link_color, NULL, credits[i].email, FALSE, appGUI);
453 		}
454 
455         gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, ">\n", -1);
456     }
457 }
458 
459 /* ========================================================================== */
460 
461 static void
display_about(GUI * appGUI)462 display_about (GUI *appGUI)
463 {
464     gchar *str;
465 
466     utl_gui_url_remove_links (&appGUI->about_links_list, &appGUI->about_link_index);
467     utl_gui_clear_text_buffer (appGUI->about_entry_buffer, &appGUI->about_entry_iter);
468 
469     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
470     str = g_strdup_printf ("%s\n", _("A handy personal organizer"));
471     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer,
472                                               &appGUI->about_entry_iter, str, -1, "big", "center", NULL);
473     g_free (str);
474     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
475 
476     utl_gui_url_insert_link (&appGUI->about_links_list, &appGUI->about_link_index,
477                              appGUI->about_textview, &appGUI->about_entry_iter, config.link_color,
478                              NULL, OSMO_WEBSITE, TRUE, appGUI);
479     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
480 
481 #ifndef REPRODUCIBLE_BUILD
482     str = g_strdup_printf ("\n(%s %s, %s)\n\n", _("compiled on"), __DATE__, __TIME__);
483     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer,
484                                               &appGUI->about_entry_iter, str, -1, "center", "italic", NULL);
485     g_free (str);
486 #endif
487 
488     add_credits_section (_("Programming"), credits_programming, G_N_ELEMENTS (credits_programming), appGUI);
489     add_credits_section (_("Graphics"), credits_graphics, G_N_ELEMENTS (credits_graphics), appGUI);
490     add_credits_section (_("Contributors"), credits_contributors, G_N_ELEMENTS (credits_contributors), appGUI);
491     add_credits_section (_("Translators"), credits_translators, G_N_ELEMENTS (credits_translators), appGUI);
492 
493     /* Links */
494 
495     str = g_strdup_printf ("\n %s:\n", _("Mailing lists"));
496     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer,
497                                               &appGUI->about_entry_iter, str, -1, "bold", NULL);
498     g_free (str);
499 
500     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\t      ", -1);
501     utl_gui_url_insert_link (&appGUI->about_links_list, &appGUI->about_link_index,
502                              appGUI->about_textview, &appGUI->about_entry_iter, config.link_color,
503                              NULL, MAILING_LIST, FALSE, appGUI);
504     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
505 
506     str = g_strdup_printf ("\n %s:\n", _("Bug tracker"));
507     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer,
508                                               &appGUI->about_entry_iter, str, -1, "bold", NULL);
509     g_free (str);
510 
511     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\t      ", -1);
512     utl_gui_url_insert_link (&appGUI->about_links_list, &appGUI->about_link_index,
513                              appGUI->about_textview, &appGUI->about_entry_iter, config.link_color,
514                              NULL, BUG_TRACKER, FALSE, appGUI);
515     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
516 
517     str = g_strdup_printf ("\n %s:\n", _("Feature requests"));
518     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer,
519                                               &appGUI->about_entry_iter, str, -1, "bold", NULL);
520     g_free (str);
521 
522     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\t      ", -1);
523     utl_gui_url_insert_link (&appGUI->about_links_list, &appGUI->about_link_index,
524                              appGUI->about_textview, &appGUI->about_entry_iter, config.link_color,
525                              NULL, FEATURE_REQUESTS, FALSE, appGUI);
526     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, "\n", -1);
527 
528 
529     /* Available modules */
530 
531     str = g_strdup_printf ("\n %s:\n", _("Available modules"));
532     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer,
533                                               &appGUI->about_entry_iter, str, -1, "bold", NULL);
534     g_free (str);
535 
536     str = g_strdup_printf ("     [+]\t%s\n", _("Calendar"));
537     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
538     g_free (str);
539 
540 #ifdef TASKS_ENABLED
541     str = g_strdup_printf ("     [+]\t%s\n", _("Tasks"));
542 #else
543     str = g_strdup_printf ("     [-]\t%s\n", _("Tasks"));
544 #endif  /* TASKS_ENABLED */
545     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
546     g_free (str);
547 
548 #ifdef CONTACTS_ENABLED
549     str = g_strdup_printf ("     [+]\t%s\n", _("Contacts"));
550 #else
551     str = g_strdup_printf ("     [-]\t%s\n", _("Contacts"));
552 #endif  /* CONTACTS_ENABLED */
553     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
554     g_free (str);
555 
556 #ifdef NOTES_ENABLED
557     str = g_strdup_printf ("     [+]\t%s\n", _("Notes"));
558 #else
559     str = g_strdup_printf ("     [-]\t%s\n", _("Notes"));
560 #endif  /* NOTES_ENABLED */
561     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
562     g_free (str);
563 
564 
565     /* Compiled-in features */
566 
567     str = g_strdup_printf ("\n %s:\n", _("Compiled-in features"));
568     gtk_text_buffer_insert_with_tags_by_name (appGUI->about_entry_buffer,
569                                               &appGUI->about_entry_iter, str, -1, "bold", NULL);
570     g_free (str);
571 
572 #ifdef HAVE_LIBICAL
573     str = g_strdup_printf ("     [+]\t%s (libical)\n", _("iCalendar support"));
574 #else
575     str = g_strdup_printf ("     [-]\t%s (libical)\n", _("iCalendar support"));
576 #endif  /* HAVE_LIBICAL */
577     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
578     g_free (str);
579 
580 #ifdef HAVE_LIBGRINGOTTS
581     str = g_strdup_printf ("     [+]\t%s (libgringotts)\n", _("Encrypted notes support"));
582 #else
583     str = g_strdup_printf ("     [-]\t%s (libgringotts)\n", _("Encrypted notes support"));
584 #endif  /* HAVE_LIBGRINGOTTS */
585     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
586     g_free (str);
587 
588 #if defined(BACKUP_SUPPORT) && defined(HAVE_LIBGRINGOTTS)
589     str = g_strdup_printf ("     [+]\t%s (libarchive + libgringotts)\n", _("Backup support"));
590 #else
591     str = g_strdup_printf ("     [-]\t%s (libarchive + libgringotts)\n", _("Backup support"));
592 #endif  /* BACKUP_SUPPORT && HAVE_LIBGRINGOTTS */
593     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
594     g_free (str);
595 
596 #ifdef PRINTING_SUPPORT
597     str = g_strdup_printf ("     [+]\t%s\n", _("Printing support"));
598 #else
599     str = g_strdup_printf ("     [-]\t%s\n", _("Printing support"));
600 #endif  /* PRINTING_SUPPORT */
601     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
602     g_free (str);
603 
604 #ifdef HAVE_GSPELL
605     str = g_strdup_printf ("     [+]\t%s (gspell)\n", _("Spell checker support"));
606 #else
607     str = g_strdup_printf ("     [-]\t%s (gspell)\n", _("Spell checker support"));
608 #endif  /* HAVE_GSPELL */
609     gtk_text_buffer_insert (appGUI->about_entry_buffer, &appGUI->about_entry_iter, str, -1);
610     g_free (str);
611 
612     gtk_widget_grab_focus (GTK_WIDGET (appGUI->scrolled_window));
613 }
614 
615 /* ========================================================================== */
616 
617 static void
about_switch_buttons(gboolean left,GUI * appGUI)618 about_switch_buttons (gboolean left, GUI *appGUI)
619 {
620     if (left == TRUE && appGUI->about_counter > 0) {
621         --appGUI->about_counter;
622     } else if (left == FALSE && appGUI->about_counter < 2) {
623         appGUI->about_counter++;
624     }
625 
626     if (appGUI->about_counter == 0){
627         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (appGUI->about_radiobutton), TRUE);
628         g_signal_emit_by_name (G_OBJECT (appGUI->about_radiobutton), "released");
629     } else if (appGUI->about_counter == 1) {
630         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (appGUI->help_radiobutton), TRUE);
631         g_signal_emit_by_name (G_OBJECT (appGUI->help_radiobutton), "released");
632     } else {
633         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (appGUI->license_radiobutton), TRUE);
634         g_signal_emit_by_name (G_OBJECT (appGUI->license_radiobutton), "released");
635     }
636 }
637 
638 /* ========================================================================== */
639 
640 static void
button_released_cb(GtkButton * button,GUI * appGUI)641 button_released_cb (GtkButton *button, GUI *appGUI)
642 {
643     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->about_radiobutton)) == TRUE) {
644 
645         display_about (appGUI);
646         appGUI->about_counter = 0;
647 
648     } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->help_radiobutton)) == TRUE) {
649 
650         display_help (appGUI);
651         appGUI->about_counter = 1;
652 
653     } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (appGUI->license_radiobutton)) == TRUE) {
654 
655         display_license (appGUI);
656         appGUI->about_counter = 2;
657 
658     }
659 }
660 
661 /* ========================================================================== */
662 
663 void
gui_create_about(GtkWidget * vbox_top,GUI * appGUI)664 gui_create_about (GtkWidget *vbox_top, GUI *appGUI)
665 {
666     GtkWidget *vbox = NULL;
667     GtkWidget *label;
668     GtkWidget *hseparator;
669     GtkWidget *logo_area;
670     GdkPixbuf *logo;
671     GtkWidget *viewport;
672     GtkWidget *hbuttonbox = NULL;
673     GSList    *radiobutton_group = NULL;
674     gchar *str, *filename;
675 
676     appGUI->about_counter = 0;
677     appGUI->about_vbox = GTK_BOX (vbox_top);
678 
679     logo_area = gtk_image_new ();
680     gtk_widget_show (logo_area);
681     gtk_box_pack_start (GTK_BOX (vbox_top), logo_area, FALSE, TRUE, 0);
682 
683 /*
684  * http://stackoverflow.com/questions/3781520/how-to-test-if-preprocessor-symbol-is-defined-but-has-no-value
685  */
686 #define DO_EXPAND(VAL)  VAL ## 1
687 #define EXPAND(VAL)     DO_EXPAND(VAL)
688 
689 #if (EXPAND(REPO) == 1)
690     str = g_strdup_printf ("%s %s", _("version"), VERSION);
691 #else
692     #define xstr(a) str(a)
693     #define str(a) #a
694     str = g_strdup_printf ("%s (%s)", _("GIT version"), xstr(REVISION));
695 #endif
696 
697     label = gtk_label_new (str);
698     g_free (str);
699     gtk_widget_show (label);
700     gtk_box_pack_start (GTK_BOX (vbox_top), label, FALSE, TRUE, 4);
701 
702     filename = g_strdup_printf(PIXMAPSDIR G_DIR_SEPARATOR_S "osmo_logo.png");
703     logo = gdk_pixbuf_new_from_file(filename, NULL);
704     g_free(filename);
705 
706     gtk_image_set_from_pixbuf(GTK_IMAGE(logo_area), logo);
707     g_object_unref(logo);
708     /*--------------------------------------------------------------------------*/
709 
710     vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
711     gtk_widget_show (vbox);
712     gtk_box_pack_start (GTK_BOX (vbox_top), vbox, FALSE, TRUE, 0);
713 
714     hseparator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
715     gtk_widget_show (hseparator);
716     gtk_box_pack_start (GTK_BOX (vbox), hseparator, FALSE, TRUE, 0);
717 
718 	hbuttonbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
719 	gtk_widget_show (hbuttonbox);
720 	gtk_box_pack_start (GTK_BOX (vbox), hbuttonbox, FALSE, TRUE, 0);
721 	gtk_widget_set_halign(hbuttonbox, GTK_ALIGN_CENTER);
722 	gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
723 
724 	appGUI->about_radiobutton = utl_gui_icon_label_radio_button (_("About"), OSMO_STOCK_ABOUT, GTK_ICON_SIZE_LARGE_TOOLBAR);
725 	gtk_container_add (GTK_CONTAINER (hbuttonbox), appGUI->about_radiobutton);
726     gtk_widget_show (appGUI->about_radiobutton);
727 
728     gtk_button_set_relief (GTK_BUTTON (appGUI->about_radiobutton), GTK_RELIEF_NONE);
729     gtk_widget_set_can_focus (appGUI->about_radiobutton, FALSE);
730     gtk_radio_button_set_group (GTK_RADIO_BUTTON (appGUI->about_radiobutton), radiobutton_group);
731     radiobutton_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (appGUI->about_radiobutton));
732     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (appGUI->about_radiobutton), TRUE);
733     gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (appGUI->about_radiobutton), FALSE);
734 
735     g_signal_connect (G_OBJECT (appGUI->about_radiobutton), "released",
736                       G_CALLBACK (button_released_cb), appGUI);
737 
738 	appGUI->help_radiobutton = utl_gui_icon_label_radio_button (_("Key shortcuts"), OSMO_STOCK_HELP, GTK_ICON_SIZE_LARGE_TOOLBAR);
739 	gtk_container_add (GTK_CONTAINER (hbuttonbox), appGUI->help_radiobutton);
740     gtk_widget_show (appGUI->help_radiobutton);
741     gtk_button_set_relief (GTK_BUTTON (appGUI->help_radiobutton), GTK_RELIEF_NONE);
742     gtk_widget_set_can_focus (appGUI->help_radiobutton, FALSE);
743     gtk_radio_button_set_group (GTK_RADIO_BUTTON (appGUI->help_radiobutton), radiobutton_group);
744     radiobutton_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (appGUI->help_radiobutton));
745     gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (appGUI->help_radiobutton), FALSE);
746 
747     g_signal_connect (G_OBJECT (appGUI->help_radiobutton), "released",
748                       G_CALLBACK (button_released_cb), appGUI);
749 
750 	appGUI->license_radiobutton = utl_gui_icon_label_radio_button (_("License"), OSMO_STOCK_LICENSE, GTK_ICON_SIZE_LARGE_TOOLBAR);
751 	gtk_container_add (GTK_CONTAINER (hbuttonbox), appGUI->license_radiobutton);
752     gtk_widget_show (appGUI->license_radiobutton);
753     gtk_button_set_relief (GTK_BUTTON (appGUI->license_radiobutton), GTK_RELIEF_NONE);
754     gtk_widget_set_can_focus (appGUI->license_radiobutton, FALSE);
755     gtk_radio_button_set_group (GTK_RADIO_BUTTON (appGUI->license_radiobutton), radiobutton_group);
756     radiobutton_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (appGUI->license_radiobutton));
757     gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (appGUI->license_radiobutton), FALSE);
758 
759     g_signal_connect (G_OBJECT (appGUI->license_radiobutton), "released",
760                       G_CALLBACK (button_released_cb), appGUI);
761 
762     hseparator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
763     gtk_widget_show (hseparator);
764     gtk_box_pack_start (GTK_BOX (vbox), hseparator, FALSE, TRUE, 0);
765 
766     /*--------------------------------------------------------------------------*/
767 
768     appGUI->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
769     gtk_box_pack_start (GTK_BOX (vbox_top), appGUI->scrolled_window, TRUE, TRUE, 0);
770     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (appGUI->scrolled_window),
771                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
772     gtk_widget_show (appGUI->scrolled_window);
773 
774     viewport = gtk_viewport_new (NULL, NULL);
775     gtk_widget_show (viewport);
776     gtk_container_set_border_width (GTK_CONTAINER (viewport), 0);
777     gtk_container_add (GTK_CONTAINER (appGUI->scrolled_window), viewport);
778 
779     appGUI->about_entry_buffer = gtk_text_buffer_new (NULL);
780     gtk_text_buffer_get_iter_at_offset (appGUI->about_entry_buffer, &appGUI->about_entry_iter, 0);
781     gtk_text_buffer_create_tag (appGUI->about_entry_buffer, "fixed", "family", "monospace", NULL);
782     gtk_text_buffer_create_tag (appGUI->about_entry_buffer, "bold", "weight", PANGO_WEIGHT_ULTRABOLD, NULL);
783     gtk_text_buffer_create_tag (appGUI->about_entry_buffer, "big", "size", 16 * PANGO_SCALE, NULL);
784     gtk_text_buffer_create_tag (appGUI->about_entry_buffer, "italic", "style", PANGO_STYLE_ITALIC, NULL);
785     gtk_text_buffer_create_tag (appGUI->about_entry_buffer, "center", "justification", GTK_JUSTIFY_CENTER, NULL);
786     gtk_text_buffer_get_iter_at_offset (appGUI->about_entry_buffer, &appGUI->about_entry_iter, 0);
787 
788     appGUI->about_textview = gtk_text_view_new_with_buffer (appGUI->about_entry_buffer);
789     gtk_container_set_border_width (GTK_CONTAINER (appGUI->about_textview), 1);
790     gtk_text_view_set_editable (GTK_TEXT_VIEW (appGUI->about_textview), FALSE);
791     gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (appGUI->about_textview), FALSE);
792     gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (appGUI->about_textview), GTK_WRAP_WORD);
793     gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (appGUI->about_textview), 2);
794     gtk_text_view_set_left_margin (GTK_TEXT_VIEW (appGUI->about_textview), 6);
795     gtk_text_view_set_right_margin (GTK_TEXT_VIEW (appGUI->about_textview), 6);
796     gtk_widget_show (appGUI->about_textview);
797     gtk_container_add (GTK_CONTAINER (viewport), appGUI->about_textview);
798 
799     utl_gui_url_setup (&appGUI->about_links_list, &appGUI->about_link_index, appGUI->about_textview, appGUI);
800 
801     display_about (appGUI);
802 }
803 
804 /* ========================================================================== */
805 
806