1 /*  $Id$
2  *
3  *  Copyright (C) 2003 Choe Hwanjin(krisna@kldp.org)
4  *  Copyright (c) 2006 Remco den Breeje <remco@sx.mine.nu>
5  *  Copyright (c) 2008 Diego Ongaro <ongardie@gmail.com>
6  *  Copyright (c) 2016 Landry Breuil <landry@xfce.org>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU Library General Public License as published
10  *  by 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 Library General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Library 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 /* local includes */
28 #include <time.h>
29 #include <string.h>
30 
31 /* xfce includes */
32 #include <libxfce4ui/libxfce4ui.h>
33 #include <libxfce4util/libxfce4util.h>
34 #include <libxfce4panel/xfce-panel-plugin.h>
35 
36 #include "datetime.h"
37 #include "datetime-dialog.h"
38 
39 #define PLUGIN_WEBSITE  "https://docs.xfce.org/panel-plugins/xfce4-datetime-plugin"
40 
41 /* Layouts */
42 static const gchar *layout_strs[] = {
43   N_("Date, then time"),
44   N_("Time, then date"),
45   N_("Date only"),
46   N_("Time only")
47 };
48 
49 typedef enum {
50 
51   /* standard format item; string is replaced with an example date or time */
52   DT_COMBOBOX_ITEM_TYPE_STANDARD,
53 
54   /* custom format item; text is translated */
55   DT_COMBOBOX_ITEM_TYPE_CUSTOM,
56 
57   /* inactive separator */
58   DT_COMBOBOX_ITEM_TYPE_SEPARATOR,
59 
60 } dt_combobox_item_type;
61 
62 typedef struct {
63   gchar *item;
64   dt_combobox_item_type type;
65 } dt_combobox_item;
66 
67 /*
68  * Builtin formats are derived from xfce4-panel-clock.patch by Nick Schermer.
69  */
70 static const dt_combobox_item dt_combobox_date[] = {
71   { "%Y-%m-%d",       DT_COMBOBOX_ITEM_TYPE_STANDARD  },
72   { "%Y %B %d",       DT_COMBOBOX_ITEM_TYPE_STANDARD  },
73   { "---",            DT_COMBOBOX_ITEM_TYPE_SEPARATOR },  /* placeholder */
74   { "%m/%d/%Y",       DT_COMBOBOX_ITEM_TYPE_STANDARD  },
75   { "%B %d, %Y",      DT_COMBOBOX_ITEM_TYPE_STANDARD  },
76   { "%b %d, %Y",      DT_COMBOBOX_ITEM_TYPE_STANDARD  },
77   { "%A, %B %d, %Y",  DT_COMBOBOX_ITEM_TYPE_STANDARD  },
78   { "%a, %b %d, %Y",  DT_COMBOBOX_ITEM_TYPE_STANDARD  },
79   { "---",            DT_COMBOBOX_ITEM_TYPE_SEPARATOR },  /* placeholder */
80   { "%d/%m/%Y",       DT_COMBOBOX_ITEM_TYPE_STANDARD  },
81   { "%d %B %Y",       DT_COMBOBOX_ITEM_TYPE_STANDARD  },
82   { "%d %b %Y",       DT_COMBOBOX_ITEM_TYPE_STANDARD  },
83   { "%A, %d %B %Y",   DT_COMBOBOX_ITEM_TYPE_STANDARD  },
84   { "%a, %d %b %Y",   DT_COMBOBOX_ITEM_TYPE_STANDARD  },
85   { "---",            DT_COMBOBOX_ITEM_TYPE_SEPARATOR },  /* placeholder */
86   { N_("Custom..."),  DT_COMBOBOX_ITEM_TYPE_CUSTOM    }
87 };
88 #define DT_COMBOBOX_DATE_COUNT (sizeof(dt_combobox_date)/sizeof(dt_combobox_item))
89 
90 static const dt_combobox_item dt_combobox_time[] = {
91   { "%H:%M",          DT_COMBOBOX_ITEM_TYPE_STANDARD  },
92   { "%H:%M:%S",       DT_COMBOBOX_ITEM_TYPE_STANDARD  },
93   { "---",            DT_COMBOBOX_ITEM_TYPE_SEPARATOR },  /* placeholder */
94   { "%l:%M %P",       DT_COMBOBOX_ITEM_TYPE_STANDARD  },
95   { "%l:%M:%S %P",    DT_COMBOBOX_ITEM_TYPE_STANDARD  },
96   { "---",            DT_COMBOBOX_ITEM_TYPE_SEPARATOR },  /* placeholder */
97   { N_("Custom..."),  DT_COMBOBOX_ITEM_TYPE_CUSTOM    }
98 };
99 #define DT_COMBOBOX_TIME_COUNT (sizeof(dt_combobox_time)/sizeof(dt_combobox_item))
100 
101 /*
102  * Example timestamp to show in the dialog.
103  * Compute with:
104  * date +%s -u -d 'dec 31 1999 23:59:59'
105  */
106 static const time_t example_time_t = 946684799;
107 
108 /*
109  * show and read fonts and inform datetime about it
110  */
datetime_font_selection_cb(GtkWidget * widget,t_datetime * dt)111 static void datetime_font_selection_cb(GtkWidget *widget, t_datetime *dt)
112 {
113   GtkWidget *dialog;
114   gchar *fontname;
115   const gchar *previewtext;
116   gint target, result;
117   gchar *font_name;
118 
119   if(widget == dt->date_font_selector)
120   {
121     target = DATE;
122     fontname = dt->date_font;
123     previewtext = gtk_label_get_text(GTK_LABEL(dt->date_label));
124   }
125   else /*time_font_selector */
126   {
127     target = TIME;
128     fontname = dt->time_font;
129     previewtext = gtk_label_get_text(GTK_LABEL(dt->time_label));
130   }
131 
132   dialog = gtk_font_chooser_dialog_new(_("Select font"),
133                                        GTK_WINDOW(gtk_widget_get_toplevel(widget)));
134   gtk_font_chooser_set_font(GTK_FONT_CHOOSER(dialog),
135                                           fontname);
136 
137   if (G_LIKELY (previewtext != NULL))
138   {
139     gtk_font_chooser_set_preview_text(GTK_FONT_CHOOSER(dialog),
140                                                previewtext);
141   }
142 
143   result = gtk_dialog_run(GTK_DIALOG(dialog));
144   if (result == GTK_RESPONSE_OK || result == GTK_RESPONSE_ACCEPT)
145   {
146     font_name =
147       gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dialog));
148 
149     if (font_name != NULL)
150     {
151       gtk_button_set_label(GTK_BUTTON(widget), font_name);
152 
153       if(target == DATE)
154         datetime_apply_font(dt, font_name, NULL);
155       else
156         datetime_apply_font(dt, NULL, font_name);
157 
158       g_free (font_name);
159     }
160   }
161   gtk_widget_destroy(dialog);
162 }
163 
164 /*
165  * Read layout from combobox and set sensitivity
166  */
167 static void
datetime_layout_changed(GtkComboBox * cbox,t_datetime * dt)168 datetime_layout_changed(GtkComboBox *cbox, t_datetime *dt)
169 {
170   t_layout layout;
171 
172   /* read layout */
173   layout = gtk_combo_box_get_active(cbox);
174 
175   switch(layout)
176   {
177     case LAYOUT_DATE:
178       gtk_widget_show(dt->date_font_hbox);
179       gtk_widget_hide(dt->date_tooltip_label);
180 
181       gtk_widget_hide(dt->time_font_hbox);
182       gtk_widget_show(dt->time_tooltip_label);
183       break;
184 
185     case LAYOUT_TIME:
186       gtk_widget_hide(dt->date_font_hbox);
187       gtk_widget_show(dt->date_tooltip_label);
188 
189       gtk_widget_show(dt->time_font_hbox);
190       gtk_widget_hide(dt->time_tooltip_label);
191       break;
192 
193     default:
194       gtk_widget_show(dt->date_font_hbox);
195       gtk_widget_hide(dt->date_tooltip_label);
196 
197       gtk_widget_show(dt->time_font_hbox);
198       gtk_widget_hide(dt->time_tooltip_label);
199   }
200 
201   datetime_apply_layout(dt, layout);
202   datetime_update(dt);
203 }
204 
205 /*
206  * Row separator for format-comboboxes of date and time
207  * derived from xfce4-panel-clock.patch by Nick Schermer
208  */
209 static gboolean
combo_box_row_separator(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)210 combo_box_row_separator(GtkTreeModel *model,
211                         GtkTreeIter  *iter,
212                         gpointer data)
213 {
214   const dt_combobox_item  *items = (dt_combobox_item *)data;
215   gint                    current;
216   GtkTreePath             *path;
217 
218   path = gtk_tree_model_get_path(model, iter);
219   current = gtk_tree_path_get_indices(path)[0];
220   gtk_tree_path_free(path);
221 
222   return items[current].type == DT_COMBOBOX_ITEM_TYPE_SEPARATOR;
223 }
224 
225 /*
226  * Read date format from combobox and set sensitivity
227  */
228 static void
date_format_changed(GtkComboBox * cbox,t_datetime * dt)229 date_format_changed(GtkComboBox *cbox, t_datetime *dt)
230 {
231   const gint active = gtk_combo_box_get_active(cbox);
232 
233   switch(dt_combobox_date[active].type)
234   {
235     case DT_COMBOBOX_ITEM_TYPE_STANDARD:
236       /* hide custom text entry box and tell datetime which format is selected */
237       gtk_widget_hide(dt->date_format_entry);
238       datetime_apply_format(dt, dt_combobox_date[active].item, NULL);
239       break;
240     case DT_COMBOBOX_ITEM_TYPE_CUSTOM:
241       /* initialize custom text entry box with current format and show the box */
242       gtk_entry_set_text(GTK_ENTRY(dt->date_format_entry), dt->date_format);
243       gtk_widget_show(dt->date_format_entry);
244       break;
245     default:
246       break; /* separators should never be active */
247   }
248 
249   datetime_update(dt);
250 }
251 
252 /*
253  * Read time format from combobox and set sensitivity
254  */
255 static void
time_format_changed(GtkComboBox * cbox,t_datetime * dt)256 time_format_changed(GtkComboBox *cbox, t_datetime *dt)
257 {
258   const gint active = gtk_combo_box_get_active(cbox);
259 
260   switch(dt_combobox_time[active].type)
261   {
262     case DT_COMBOBOX_ITEM_TYPE_STANDARD:
263       /* hide custom text entry box and tell datetime which format is selected */
264       gtk_widget_hide(dt->time_format_entry);
265       datetime_apply_format(dt, NULL, dt_combobox_time[active].item);
266       break;
267     case DT_COMBOBOX_ITEM_TYPE_CUSTOM:
268       /* initialize custom text entry box with current format and show the box */
269       gtk_entry_set_text(GTK_ENTRY(dt->time_format_entry), dt->time_format);
270       gtk_widget_show(dt->time_format_entry);
271       break;
272     default:
273       break; /* separators should never be active */
274   }
275 
276   datetime_update(dt);
277 }
278 
279 /*
280  * read values from date and time entry and inform datetime about it
281  */
282 static gboolean
datetime_entry_change_cb(GtkWidget * widget,GdkEventFocus * ev,t_datetime * dt)283 datetime_entry_change_cb(GtkWidget *widget, GdkEventFocus *ev, t_datetime *dt)
284 {
285   const gchar *format;
286   format = gtk_entry_get_text(GTK_ENTRY(widget));
287   if (format != NULL)
288   {
289     if(widget == dt->date_format_entry)         /* date */
290       datetime_apply_format(dt, format, NULL);
291     else if(widget == dt->time_format_entry)    /* or time */
292       datetime_apply_format(dt, NULL, format);
293   }
294   datetime_update(dt);
295   return FALSE;
296 }
297 
298 /*
299  * user closed the properties dialog
300  */
301 static void
datetime_dialog_response(GtkWidget * dlg,int response,t_datetime * dt)302 datetime_dialog_response(GtkWidget *dlg, int response, t_datetime *dt)
303 {
304   gboolean result;
305 
306   if(dt == NULL)
307     return;
308 
309   if (response == GTK_RESPONSE_HELP)
310   {
311       /* show help */
312       result = g_spawn_command_line_async("exo-open --launch WebBrowser " PLUGIN_WEBSITE, NULL);
313 
314       if (G_UNLIKELY(result == FALSE))
315           g_warning(_("Unable to open the following url: %s"), PLUGIN_WEBSITE);
316   }
317   else
318   {
319     g_object_set_data(G_OBJECT(dt->plugin), "dialog", NULL);
320 
321     gtk_widget_destroy(dlg);
322     datetime_write_rc_file(dt->plugin, dt);
323   }
324 }
325 
326 static GtkWidget *
get_frame_box(const gchar * label,GtkWidget ** container_return)327 get_frame_box (const gchar  *label,
328                GtkWidget   **container_return)
329 {
330   GtkWidget *bin;
331   GtkWidget *frame;
332 
333   frame = xfce_gtk_frame_box_new(label, &bin);
334   gtk_widget_set_margin_top(GTK_WIDGET(bin), 6);
335   gtk_widget_set_margin_start(GTK_WIDGET(bin), 0);
336 
337   G_GNUC_BEGIN_IGNORE_DEPRECATIONS
338   gtk_alignment_set_padding(GTK_ALIGNMENT(bin), 0, 0, 12, 0);
339   G_GNUC_END_IGNORE_DEPRECATIONS
340 
341   *container_return = bin;
342 
343   return frame;
344 }
345 
346 /*
347  * show datetime properties dialog
348  */
349 void
datetime_properties_dialog(XfcePanelPlugin * plugin,t_datetime * datetime)350 datetime_properties_dialog(XfcePanelPlugin *plugin, t_datetime * datetime)
351 {
352   guint i;
353   gchar *str;
354   struct tm *exampletm = gmtime(&example_time_t);
355   GtkWidget *dlg,
356             *frame,
357             *vbox,
358             *hbox,
359             *layout_combobox,
360             *time_combobox,
361             *date_combobox,
362             *label,
363             *button,
364             *entry,
365             *bin;
366   GtkSizeGroup  *sg;
367   gint i_custom; /* index of custom menu item */
368 
369   xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
370 
371   dlg = xfce_titled_dialog_new_with_buttons(_("Datetime"),
372       GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(plugin))),
373       GTK_DIALOG_DESTROY_WITH_PARENT,
374       "gtk-help", GTK_RESPONSE_HELP,
375       "gtk-close", GTK_RESPONSE_OK,
376       NULL);
377 
378   g_object_set_data(G_OBJECT(plugin), "dialog", dlg);
379 
380   gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_CENTER);
381   gtk_window_set_icon_name (GTK_WINDOW (dlg), "xfce4-settings");
382 
383   gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dlg))), 12);
384   gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))), 18);
385 
386   /* size group */
387   sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
388 
389   /*
390    * layout frame
391    */
392   frame = get_frame_box(_("Layout"), &bin);
393   gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))), frame,
394       FALSE, FALSE, 0);
395 
396   /* vbox */
397   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
398   gtk_container_add(GTK_CONTAINER(bin),vbox);
399 
400   /* hbox */
401   hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
402   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
403 
404   /* Format label */
405   label = gtk_label_new(_("Format:"));
406   gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
407   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
408   gtk_size_group_add_widget(sg, label);
409 
410   /* Layout combobox */
411   layout_combobox = gtk_combo_box_text_new();
412   gtk_box_pack_start(GTK_BOX(hbox), layout_combobox, TRUE, TRUE, 0);
413   for(i=0; i < LAYOUT_COUNT; i++)
414     gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(layout_combobox), _(layout_strs[i]));
415   gtk_combo_box_set_active(GTK_COMBO_BOX(layout_combobox), datetime->layout);
416   g_signal_connect(G_OBJECT(layout_combobox), "changed",
417       G_CALLBACK(datetime_layout_changed), datetime);
418 
419   /* show frame */
420   gtk_widget_show_all(frame);
421 
422   /*
423    * Date frame
424    */
425   datetime->date_frame = get_frame_box(_("Date"), &bin);
426   gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))), datetime->date_frame,
427       FALSE, FALSE, 0);
428 
429   /* vbox */
430   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
431   gtk_container_add(GTK_CONTAINER(bin),vbox);
432 
433   /* tooltip label */
434   str = g_markup_printf_escaped("<span style=\"italic\">%s</span>",
435                                 _("The date will appear in a tooltip."));
436   datetime->date_tooltip_label = gtk_label_new(str);
437   g_free(str);
438   gtk_label_set_xalign (GTK_LABEL (datetime->date_tooltip_label), 0.0f);
439   gtk_label_set_use_markup(GTK_LABEL(datetime->date_tooltip_label), TRUE);
440   gtk_box_pack_start(GTK_BOX(vbox), datetime->date_tooltip_label, FALSE, FALSE, 0);
441 
442   /* hbox */
443   datetime->date_font_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
444   gtk_box_pack_start(GTK_BOX(vbox), datetime->date_font_hbox, FALSE, FALSE, 0);
445 
446   /* font label */
447   label = gtk_label_new(_("Font:"));
448   gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
449   gtk_box_pack_start(GTK_BOX(datetime->date_font_hbox), label, FALSE, FALSE, 0);
450   gtk_size_group_add_widget(sg, label);
451 
452   /* font button */
453   button = gtk_button_new_with_label(datetime->date_font);
454   gtk_box_pack_start(GTK_BOX(datetime->date_font_hbox), button, TRUE, TRUE, 0);
455   g_signal_connect(G_OBJECT(button), "clicked",
456       G_CALLBACK(datetime_font_selection_cb), datetime);
457   datetime->date_font_selector = button;
458 
459   /* hbox */
460   hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
461   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
462 
463   /* format label */
464   label = gtk_label_new(_("Format:"));
465   gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
466   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
467   gtk_size_group_add_widget(sg, label);
468 
469   /* format combobox */
470   date_combobox = gtk_combo_box_text_new();
471   gtk_box_pack_start(GTK_BOX(hbox), date_combobox, TRUE, TRUE, 0);
472   i_custom = 0;
473   for(i=0; i < DT_COMBOBOX_DATE_COUNT; i++)
474   {
475     switch(dt_combobox_date[i].type)
476     {
477       case DT_COMBOBOX_ITEM_TYPE_STANDARD:
478         str = datetime_do_utf8strftime(dt_combobox_date[i].item, exampletm);
479         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(date_combobox), str);
480         g_free(str);
481         /* set active
482          * strcmp isn't fast, but it is done only once while opening the dialog
483          */
484         if(strcmp(datetime->date_format, dt_combobox_date[i].item) == 0)
485           gtk_combo_box_set_active(GTK_COMBO_BOX(date_combobox), i);
486         break;
487       case DT_COMBOBOX_ITEM_TYPE_CUSTOM:
488         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(date_combobox), _(dt_combobox_date[i].item));
489         i_custom = i;
490         break;
491       case DT_COMBOBOX_ITEM_TYPE_SEPARATOR: /* placeholder item does not need to be translated */
492         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(date_combobox), dt_combobox_date[i].item);
493         break;
494       default:
495         break;
496     }
497   }
498   /* if no item activated -> activate custom item */
499   if(gtk_combo_box_get_active(GTK_COMBO_BOX(date_combobox)) < 0)
500     gtk_combo_box_set_active(GTK_COMBO_BOX(date_combobox), i_custom);
501   gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(date_combobox),
502                                        combo_box_row_separator,
503                                        (gpointer)dt_combobox_date, NULL);
504   g_signal_connect(G_OBJECT(date_combobox), "changed",
505       G_CALLBACK(date_format_changed), datetime);
506   datetime->date_format_combobox = date_combobox;
507 
508   /* format entry */
509   entry = gtk_entry_new();
510   gtk_entry_set_text(GTK_ENTRY(entry), datetime->date_format);
511   gtk_widget_set_halign (GTK_WIDGET (entry), GTK_ALIGN_END);
512   gtk_box_pack_end(GTK_BOX(vbox), entry, FALSE, FALSE, 0);
513   g_signal_connect (G_OBJECT(entry), "focus-out-event",
514                     G_CALLBACK (datetime_entry_change_cb), datetime);
515   datetime->date_format_entry = entry;
516 
517   gtk_widget_show_all(datetime->date_frame);
518 
519   /*
520    * time frame
521    */
522   datetime->time_frame = get_frame_box(_("Time"), &bin);
523   gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))), datetime->time_frame,
524       FALSE, FALSE, 0);
525 
526   /* vbox */
527   vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
528   gtk_container_add(GTK_CONTAINER(bin), vbox);
529 
530   /* tooltip label */
531   str = g_markup_printf_escaped("<span style=\"italic\">%s</span>",
532                                 _("The time will appear in a tooltip."));
533   datetime->time_tooltip_label = gtk_label_new(str);
534   g_free(str);
535   gtk_label_set_xalign (GTK_LABEL (datetime->time_tooltip_label), 0.0f);
536   gtk_label_set_use_markup(GTK_LABEL(datetime->time_tooltip_label), TRUE);
537   gtk_box_pack_start(GTK_BOX(vbox), datetime->time_tooltip_label, FALSE, FALSE, 0);
538 
539   /* hbox */
540   datetime->time_font_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
541   gtk_box_pack_start(GTK_BOX(vbox), datetime->time_font_hbox, FALSE, FALSE, 0);
542 
543   /* font label */
544   label = gtk_label_new(_("Font:"));
545   gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
546   gtk_box_pack_start(GTK_BOX(datetime->time_font_hbox), label, FALSE, FALSE, 0);
547   gtk_size_group_add_widget(sg, label);
548 
549   /* font button */
550   button = gtk_button_new_with_label(datetime->time_font);
551   gtk_box_pack_start(GTK_BOX(datetime->time_font_hbox), button, TRUE, TRUE, 0);
552   g_signal_connect(G_OBJECT(button), "clicked",
553       G_CALLBACK(datetime_font_selection_cb), datetime);
554   datetime->time_font_selector = button;
555 
556   /* hbox */
557   hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
558   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
559 
560   /* format label */
561   label = gtk_label_new(_("Format:"));
562   gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
563   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
564   gtk_size_group_add_widget(sg, label);
565 
566   /* format combobox */
567   time_combobox = gtk_combo_box_text_new();
568   gtk_box_pack_start(GTK_BOX(hbox), time_combobox, TRUE, TRUE, 0);
569   i_custom = 0;
570   for(i=0; i < DT_COMBOBOX_TIME_COUNT; i++)
571   {
572     switch(dt_combobox_time[i].type)
573     {
574       case DT_COMBOBOX_ITEM_TYPE_STANDARD:
575         str = datetime_do_utf8strftime(dt_combobox_time[i].item, exampletm);
576         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(time_combobox), str);
577         g_free(str);
578         /* set active
579          * strcmp isn't fast, but it is done only once while opening the dialog
580          */
581         if(strcmp(datetime->time_format, dt_combobox_time[i].item) == 0)
582           gtk_combo_box_set_active(GTK_COMBO_BOX(time_combobox), i);
583         break;
584       case DT_COMBOBOX_ITEM_TYPE_CUSTOM:
585         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(time_combobox), _(dt_combobox_time[i].item));
586         i_custom = i;
587         break;
588       case DT_COMBOBOX_ITEM_TYPE_SEPARATOR: /* placeholder item does not need to be translated */
589         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(time_combobox), dt_combobox_time[i].item);
590         break;
591       default:
592         break;
593     }
594   }
595   /* if no item activated -> activate custom item */
596   if(gtk_combo_box_get_active(GTK_COMBO_BOX(time_combobox)) < 0)
597     gtk_combo_box_set_active(GTK_COMBO_BOX(time_combobox), i_custom);
598   gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(time_combobox),
599                                        combo_box_row_separator,
600                                        (gpointer)dt_combobox_time, NULL);
601   g_signal_connect(G_OBJECT(time_combobox), "changed",
602       G_CALLBACK(time_format_changed), datetime);
603   datetime->time_format_combobox = time_combobox;
604 
605   /* format entry */
606   entry = gtk_entry_new();
607   gtk_entry_set_text(GTK_ENTRY(entry), datetime->time_format);
608   gtk_widget_set_halign (GTK_WIDGET (entry), GTK_ALIGN_END);
609   gtk_box_pack_end(GTK_BOX(vbox), entry, FALSE, FALSE, 0);
610   g_signal_connect (G_OBJECT(entry), "focus-out-event",
611                     G_CALLBACK (datetime_entry_change_cb), datetime);
612   datetime->time_format_entry = entry;
613 
614   gtk_widget_show_all(datetime->time_frame);
615 
616   /* We're done! */
617   g_signal_connect(dlg, "response",
618       G_CALLBACK(datetime_dialog_response), datetime);
619 
620   /* set sensitivity for all widgets */
621   datetime_layout_changed(GTK_COMBO_BOX(layout_combobox), datetime);
622   date_format_changed(GTK_COMBO_BOX(date_combobox), datetime);
623   time_format_changed(GTK_COMBO_BOX(time_combobox), datetime);
624 
625   /* show dialog */
626   gtk_widget_show(dlg);
627 }
628 
629