[gthumb/ext] added a time selector widget for choosing dates



commit d827fd708858c5d9883e431a58beca1c31b84ebb
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sun Oct 25 20:41:09 2009 +0100

    added a time selector widget for choosing dates

 extensions/comments/data/ui/edit-comment-page.ui |    3 +-
 extensions/comments/gth-edit-comment-page.c      |   40 ++-
 extensions/desktop_background/callbacks.c        |    1 -
 gthumb/Makefile.am                               |    2 +
 gthumb/gth-time-selector.c                       |  507 ++++++++++++++++++++++
 gthumb/gth-time-selector.h                       |   68 +++
 gthumb/gth-time.c                                |   46 ++-
 gthumb/gth-time.h                                |    4 +
 8 files changed, 649 insertions(+), 22 deletions(-)
---
diff --git a/extensions/comments/data/ui/edit-comment-page.ui b/extensions/comments/data/ui/edit-comment-page.ui
index 683f166..4d6d617 100644
--- a/extensions/comments/data/ui/edit-comment-page.ui
+++ b/extensions/comments/data/ui/edit-comment-page.ui
@@ -103,7 +103,7 @@
       </packing>
     </child>
     <child>
-      <object class="GtkVBox" id="date_datetime_container">
+      <object class="GtkVBox" id="date_selector_container">
         <property name="visible">True</property>
         <property name="orientation">vertical</property>
         <property name="spacing">6</property>
@@ -152,6 +152,7 @@
       <packing>
         <property name="top_attach">4</property>
         <property name="bottom_attach">5</property>
+        <property name="x_options">GTK_FILL</property>
         <property name="y_options">GTK_FILL</property>
       </packing>
     </child>
diff --git a/extensions/comments/gth-edit-comment-page.c b/extensions/comments/gth-edit-comment-page.c
index 8798f08..1a8d2c9 100644
--- a/extensions/comments/gth-edit-comment-page.c
+++ b/extensions/comments/gth-edit-comment-page.c
@@ -48,7 +48,7 @@ struct _GthEditCommentPagePrivate {
 	GthFileData *file_data;
 	GtkBuilder  *builder;
 	GtkWidget   *date_combobox;
-	GtkWidget   *date_datetime;
+	GtkWidget   *date_selector;
 	GtkWidget   *tags_entry;
 };
 
@@ -88,13 +88,13 @@ gth_edit_comment_page_real_set_file (GthEditMetadataPage *base,
 	metadata = (GthMetadata *) g_file_info_get_attribute_object (file_data->info, "Embedded::Image::DateTime");
 	if (metadata != NULL) {
 		gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->date_combobox), FOLLOWING_DATE);
-		gtk_entry_set_text (GTK_ENTRY (self->priv->date_datetime), gth_metadata_get_formatted (metadata));
-		/*gtk_widget_set_sensitive (self->priv->date_datetime, TRUE);*/
+		gth_time_selector_set_exif_date (GTH_TIME_SELECTOR (self->priv->date_selector), gth_metadata_get_formatted (metadata));
+		/*gtk_widget_set_sensitive (self->priv->date_selector, TRUE);*/
 	}
 	else {
 		gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->date_combobox), NO_DATE);
-		gtk_entry_set_text (GTK_ENTRY (self->priv->date_datetime), "");
-		/*gtk_widget_set_sensitive (self->priv->date_datetime, FALSE);*/
+		gth_time_selector_set_exif_date (GTH_TIME_SELECTOR (self->priv->date_selector), "");
+		/*gtk_widget_set_sensitive (self->priv->date_selector, FALSE);*/
 	}
 
 	tags = (GthStringList *) g_file_info_get_attribute_object (file_data->info, "Embedded::Image::Keywords");
@@ -127,6 +127,8 @@ gth_edit_comment_page_real_update_info (GthEditMetadataPage *base,
 	char               **tagv;
 	GList               *tags;
 	GthStringList       *string_list;
+	GthDateTime         *date_time;
+	char                *exif_date;
 
 	self = GTH_EDIT_COMMENT_PAGE (base);
 
@@ -156,13 +158,17 @@ gth_edit_comment_page_real_update_info (GthEditMetadataPage *base,
 
 	/* date */
 
+	date_time = gth_datetime_new ();
+	gth_time_selector_get_value (GTH_TIME_SELECTOR (self->priv->date_selector), date_time);
+	exif_date = gth_datetime_to_exif_date (date_time);
 	metadata = g_object_new (GTH_TYPE_METADATA,
 				 "id", "Embedded::Image::Date",
-				 "raw", gtk_entry_get_text (GTK_ENTRY (self->priv->date_datetime)),
-				 "formatted", gtk_entry_get_text (GTK_ENTRY (self->priv->date_datetime)),
+				 "raw", exif_date,
+				 "formatted", exif_date,
 				 NULL);
 	g_file_info_set_attribute_object (self->priv->file_data->info, "Embedded::Image::Date", G_OBJECT (metadata));
 	g_object_unref (metadata);
+	gth_datetime_free (date_time);
 
 	/* tags */
 
@@ -174,6 +180,7 @@ gth_edit_comment_page_real_update_info (GthEditMetadataPage *base,
 	string_list = gth_string_list_new (tags);
 	g_file_info_set_attribute_object (self->priv->file_data->info, "Embedded::Image::Keywords", G_OBJECT (string_list));
 
+	g_free (exif_date);
 	g_object_unref (string_list);
 	g_strfreev (tagv);
 	g_list_free (tags);
@@ -216,6 +223,8 @@ get_date_from_option (GthEditCommentPage *self,
 		      DateOption          option)
 {
 	GTimeVal     timeval;
+	GthDateTime *date_time;
+	char        *exif_date;
 	const char  *date;
 	GthMetadata *metadata;
 
@@ -225,7 +234,12 @@ get_date_from_option (GthEditCommentPage *self,
 	case NO_DATE:
 		return g_strdup ("");
 	case FOLLOWING_DATE:
-		_g_time_val_from_exif_date (gtk_entry_get_text (GTK_ENTRY (self->priv->date_datetime)), &timeval);
+		date_time = gth_datetime_new ();
+		gth_time_selector_get_value (GTH_TIME_SELECTOR (self->priv->date_selector), date_time);
+		exif_date = gth_datetime_to_exif_date (&date_time);
+		_g_time_val_from_exif_date (exif_date, &timeval);
+		g_free (exif_date);
+		gth_datetime_free (date_time);
 		break;
 	case CURRENT_DATE:
 		g_get_current_time (&timeval);
@@ -266,7 +280,7 @@ date_combobox_changed_cb (GtkComboBox *widget,
 	char               *value;
 
 	value = get_date_from_option (self, gtk_combo_box_get_active (widget));
-	gtk_entry_set_text (GTK_ENTRY (self->priv->date_datetime), value);
+	gth_time_selector_set_exif_date (GTH_TIME_SELECTOR (self->priv->date_selector), value);
 
 	g_free (value);
 }
@@ -295,16 +309,16 @@ gth_edit_comment_page_init (GthEditCommentPage *self)
   				     _("Do not modify"),
   				     NULL);
   	gtk_widget_show (self->priv->date_combobox);
-  	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("date_combobox_container")), self->priv->date_combobox, FALSE, FALSE, 0);
+  	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("date_combobox_container")), self->priv->date_combobox, TRUE, TRUE, 0);
 
   	g_signal_connect (self->priv->date_combobox,
 			  "changed",
 			  G_CALLBACK (date_combobox_changed_cb),
 			  self);
 
-  	self->priv->date_datetime = gtk_entry_new ();
-  	gtk_widget_show (self->priv->date_datetime);
-  	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("date_datetime_container")), self->priv->date_datetime, FALSE, FALSE, 0);
+  	self->priv->date_selector = gth_time_selector_new ();
+  	gtk_widget_show (self->priv->date_selector);
+  	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("date_selector_container")), self->priv->date_selector, FALSE, FALSE, 0);
 
   	self->priv->tags_entry = gth_tags_entry_new ();
   	gtk_widget_show (self->priv->tags_entry);
diff --git a/extensions/desktop_background/callbacks.c b/extensions/desktop_background/callbacks.c
index aa945d2..7ab6f6d 100644
--- a/extensions/desktop_background/callbacks.c
+++ b/extensions/desktop_background/callbacks.c
@@ -24,7 +24,6 @@
 #include <config.h>
 #include <glib/gi18n.h>
 #include <glib-object.h>
-#include <gdk/gdkkeysyms.h>
 #include <gthumb.h>
 #include "actions.h"
 
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index f687bb9..f51c75a 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -95,6 +95,7 @@ PUBLIC_HEADER_FILES = 					\
 	gth-test-simple.h				\
 	gth-thumb-loader.h				\
 	gth-time.h					\
+	gth-time-selector.h				\
 	gth-toggle-menu-tool-button.h			\
 	gth-toolbox.h					\
 	gth-uri-list.h					\
@@ -213,6 +214,7 @@ gthumb_SOURCES = 					\
 	gth-test-simple.c				\
 	gth-thumb-loader.c				\
 	gth-time.c					\
+	gth-time-selector.c				\
 	gth-toggle-menu-tool-button.c			\
 	gth-toolbox.c					\
 	gth-uri-list.c					\
diff --git a/gthumb/gth-time-selector.c b/gthumb/gth-time-selector.c
new file mode 100644
index 0000000..c331a1a
--- /dev/null
+++ b/gthumb/gth-time-selector.c
@@ -0,0 +1,507 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#define _XOPEN_SOURCE /* glibc2 needs this */
+#include <time.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include "gth-time-selector.h"
+
+
+enum {
+	CHANGED,
+	LAST_SIGNAL
+};
+
+
+struct _GthTimeSelectorPrivate
+{
+	GthDateTime *date_time;
+	GtkWidget   *date_entry;
+	GtkWidget   *calendar_button;
+	GtkWidget   *calendar;
+	GtkWidget   *calendar_popup;
+	GtkWidget   *time_combo_box;
+};
+
+
+static GtkHBoxClass *parent_class = NULL;
+static guint gth_time_selector_signals[LAST_SIGNAL] = { 0 };
+
+
+static void
+gth_time_selector_finalize (GObject *object)
+{
+	GthTimeSelector *self;
+
+	self = GTH_TIME_SELECTOR (object);
+
+	gtk_widget_destroy (self->priv->calendar_popup);
+	gth_datetime_free (self->priv->date_time);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+gth_time_selector_class_init (GthTimeSelectorClass *class)
+{
+	GObjectClass   *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GthTimeSelectorPrivate));
+
+	object_class = (GObjectClass*) class;
+	object_class->finalize = gth_time_selector_finalize;
+
+	gth_time_selector_signals[CHANGED] =
+		g_signal_new ("changed",
+			      G_TYPE_FROM_CLASS (class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GthTimeSelectorClass, changed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
+}
+
+
+static void
+gth_time_selector_init (GthTimeSelector *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_TIME_SELECTOR, GthTimeSelectorPrivate);
+	self->priv->date_time = gth_datetime_new ();
+}
+
+
+static void
+hide_calendar_popup (GthTimeSelector *self)
+{
+	gtk_grab_remove (self->priv->calendar_popup);
+	gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+	gdk_pointer_ungrab (GDK_CURRENT_TIME);
+	gtk_widget_hide (self->priv->calendar_popup);
+
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->calendar_button), FALSE);
+}
+
+
+static void
+show_calendar_popup (GthTimeSelector *self)
+{
+	int x, y, width, height;
+
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->calendar_button), TRUE);
+
+	gdk_window_get_position (gtk_widget_get_window (GTK_WIDGET (self)), &x, &y);
+	x += self->priv->date_entry->allocation.x;
+	y += self->priv->date_entry->allocation.y;
+	width = self->priv->date_entry->allocation.width;
+	height = self->priv->date_entry->allocation.height;
+	gtk_window_move (GTK_WINDOW (self->priv->calendar_popup), x, y + height + 1);
+	gtk_widget_show (self->priv->calendar_popup);
+
+	gdk_keyboard_grab (gtk_widget_get_window (self->priv->calendar_popup), TRUE, GDK_CURRENT_TIME);
+	gtk_grab_add (self->priv->calendar_popup);
+	gdk_pointer_grab (gtk_widget_get_window (self->priv->calendar_popup),
+			  TRUE,
+			  (GDK_BUTTON_PRESS_MASK
+			   | GDK_BUTTON_RELEASE_MASK
+			   | GDK_POINTER_MOTION_HINT_MASK
+			   | GDK_BUTTON_MOTION_MASK
+			   | GDK_EXTENSION_EVENTS_ALL),
+			  NULL,
+			  NULL,
+			  GDK_CURRENT_TIME);
+	gtk_widget_grab_focus (self->priv->calendar);
+}
+
+
+static void
+calendar_button_toggled_cb (GtkToggleButton *button,
+			    gpointer         user_data)
+{
+	GthTimeSelector *self = user_data;
+
+	if (gtk_toggle_button_get_active (button))
+		show_calendar_popup (self);
+	else
+		hide_calendar_popup (self);
+}
+
+
+static void
+update_date_from_view (GthTimeSelector *self)
+{
+	struct tm tm;
+
+	strptime (gtk_entry_get_text (GTK_ENTRY (self->priv->date_entry)), "%x", &tm);
+	strptime (gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (self->priv->time_combo_box)))), "%X", &tm);
+	gth_datetime_from_struct_tm (self->priv->date_time, &tm);
+}
+
+
+static void
+update_view_from_data (GthTimeSelector *self)
+{
+	GtkWidget *entry;
+
+	if (gth_datetime_valid (self->priv->date_time)) {
+		char *text;
+
+		text = gth_datetime_strftime (self->priv->date_time, "%x");
+		gtk_entry_set_text (GTK_ENTRY (self->priv->date_entry), text);
+
+		entry = gtk_bin_get_child (GTK_BIN (self->priv->time_combo_box));
+		text = gth_datetime_strftime (self->priv->date_time, "%X");
+		gtk_entry_set_text (GTK_ENTRY (entry), text);
+	}
+	else {
+		gtk_entry_set_text (GTK_ENTRY (self->priv->date_entry), "");
+
+		entry = gtk_bin_get_child (GTK_BIN (self->priv->time_combo_box));
+		gtk_entry_set_text (GTK_ENTRY (entry), "");
+	}
+}
+
+
+static void
+today_button_clicked_cb (GtkButton *button,
+			 gpointer   user_data)
+{
+	GthTimeSelector *self = user_data;
+	GTimeVal         timeval;
+
+	update_date_from_view (self);
+	g_get_current_time (&timeval);
+	g_date_set_time_val (self->priv->date_time->date, &timeval);
+	update_view_from_data (self);
+	hide_calendar_popup (self);
+}
+
+
+static void
+now_button_clicked_cb (GtkButton *button,
+			 gpointer   user_data)
+{
+	GthTimeSelector *self = user_data;
+	GTimeVal         timeval;
+	struct tm       *tm;
+	time_t           secs;
+
+	update_date_from_view (self);
+	g_get_current_time (&timeval);
+	g_date_set_time_val (self->priv->date_time->date, &timeval);
+
+	secs = timeval.tv_sec;
+	tm = localtime (&secs);
+	gth_time_set_hms (self->priv->date_time->time, tm->tm_hour, tm->tm_min, tm->tm_sec, timeval.tv_usec);
+
+	update_view_from_data (self);
+	hide_calendar_popup (self);
+}
+
+
+static gboolean
+calendar_day_selected_double_click_cb (GtkCalendar *calendar,
+				       gpointer     user_data)
+{
+	GthTimeSelector *self = user_data;
+	guint            y, m, d;
+
+	update_date_from_view (self);
+	gtk_calendar_get_date (GTK_CALENDAR (self->priv->calendar), &y, &m, &d);
+	g_date_set_dmy (self->priv->date_time->date, d, m + 1, y);
+	update_view_from_data (self);
+	hide_calendar_popup (self);
+
+	return FALSE;
+}
+
+
+
+static gboolean
+calendar_day_selected_cb (GtkCalendar *calendar,
+		          gpointer     user_data)
+{
+	GthTimeSelector *self = user_data;
+	guint            y, m, d;
+
+	update_date_from_view (self);
+	gtk_calendar_get_date (GTK_CALENDAR (self->priv->calendar), &y, &m, &d);
+	g_date_set_dmy (self->priv->date_time->date, d, m + 1, y);
+	update_view_from_data (self);
+
+	return FALSE;
+}
+
+
+static gboolean
+calendar_popup_button_press_event_cb (GtkWidget      *widget,
+				      GdkEventButton *event,
+				      gpointer        user_data)
+{
+	GthTimeSelector *self = user_data;
+	GdkRectangle     popup_area;
+
+	gdk_window_get_geometry (gtk_widget_get_window (self->priv->calendar_popup),
+				 &popup_area.x,
+				 &popup_area.y,
+				 &popup_area.width,
+				 &popup_area.height,
+				 NULL);
+
+	/*g_print ("(%.0f, %.0f) <==> (%d, %d)[%d, %d]\n", event->x_root, event->y_root,  popup_area.x,  popup_area.y, popup_area.width, popup_area.height);*/
+
+	if ((event->x_root < popup_area.x)
+	    || (event->x_root > popup_area.x + popup_area.width)
+	    || (event->y_root < popup_area.y)
+	    || (event->y_root > popup_area.y + popup_area.height))
+	{
+		hide_calendar_popup (self);
+	}
+
+	return FALSE;
+}
+
+
+static gboolean
+calendar_popup_key_press_event_cb (GtkWidget   *widget,
+				   GdkEventKey *event,
+				   gpointer     user_data)
+{
+	GthTimeSelector *self = user_data;
+
+	switch (event->keyval) {
+	case GDK_Escape:
+		hide_calendar_popup (self);
+		break;
+
+	default:
+		break;
+	}
+
+	return FALSE;
+}
+
+
+static void
+gth_time_selector_changed (GthTimeSelector *self)
+{
+	g_signal_emit (self, gth_time_selector_signals[CHANGED], 0);
+}
+
+
+static void
+gth_time_selector_construct (GthTimeSelector *self)
+{
+	GtkWidget   *frame;
+	GtkWidget   *box;
+	GtkWidget   *button_box;
+	GtkWidget   *button;
+	GthDateTime *dt;
+	guint8       h;
+
+	g_object_set (self, "spacing", 6, NULL);
+
+	box = gtk_hbox_new (FALSE, 0);
+	gtk_widget_show (box);
+	gtk_box_pack_start (GTK_BOX (self), box, FALSE, FALSE, 0);
+
+	self->priv->date_entry = gtk_entry_new ();
+	gtk_entry_set_width_chars (GTK_ENTRY (self->priv->date_entry), 15);
+	gtk_editable_set_editable (GTK_EDITABLE (self->priv->date_entry), TRUE);
+	gtk_widget_show (self->priv->date_entry);
+	gtk_box_pack_start (GTK_BOX (box), self->priv->date_entry, FALSE, FALSE, 0);
+
+	self->priv->calendar_button = gtk_toggle_button_new ();
+	gtk_container_add (GTK_CONTAINER (self->priv->calendar_button), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE));
+	gtk_widget_show_all (self->priv->calendar_button);
+	gtk_box_pack_start (GTK_BOX (box), self->priv->calendar_button, FALSE, FALSE, 0);
+	g_signal_connect (self->priv->calendar_button,
+				  "toggled",
+				  G_CALLBACK (calendar_button_toggled_cb),
+				  self);
+
+	self->priv->calendar_popup = gtk_window_new (GTK_WINDOW_POPUP);
+	g_signal_connect (self->priv->calendar_popup,
+			  "button-press-event",
+			  G_CALLBACK (calendar_popup_button_press_event_cb),
+			  self);
+	g_signal_connect (self->priv->calendar_popup,
+			  "key-press-event",
+			  G_CALLBACK (calendar_popup_key_press_event_cb),
+			  self);
+
+	frame = gtk_frame_new (NULL);
+	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
+	gtk_widget_show (frame);
+	gtk_container_add (GTK_CONTAINER (self->priv->calendar_popup), frame);
+
+	box = gtk_vbox_new (FALSE, 6);
+	gtk_container_set_border_width (GTK_CONTAINER (box), 6);
+	gtk_widget_show (box);
+	gtk_container_add (GTK_CONTAINER (frame), box);
+
+	self->priv->calendar = gtk_calendar_new ();
+	gtk_widget_show (self->priv->calendar);
+	gtk_box_pack_start (GTK_BOX (box), self->priv->calendar, FALSE, FALSE, 0);
+	g_signal_connect (self->priv->calendar,
+			  "day-selected-double-click",
+			  G_CALLBACK (calendar_day_selected_double_click_cb),
+			  self);
+	g_signal_connect (self->priv->calendar,
+			  "day-selected",
+			  G_CALLBACK (calendar_day_selected_cb),
+			  self);
+
+	button_box = gtk_hbox_new (TRUE, 6);
+	gtk_widget_show (button_box);
+	gtk_box_pack_start (GTK_BOX (box), button_box, FALSE, FALSE, 0);
+
+	button = gtk_button_new_with_label (_("Today"));
+	gtk_widget_show (button);
+	gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
+	g_signal_connect (button,
+			  "clicked",
+			  G_CALLBACK (today_button_clicked_cb),
+			  self);
+
+	button = gtk_button_new_with_label (_("Now"));
+	gtk_widget_show (button);
+	gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
+	g_signal_connect (button,
+			  "clicked",
+			  G_CALLBACK (now_button_clicked_cb),
+			  self);
+
+	self->priv->time_combo_box = gtk_combo_box_entry_new_text ();
+	gtk_entry_set_width_chars (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (self->priv->time_combo_box))), 10);
+	gtk_widget_show (self->priv->time_combo_box);
+	gtk_box_pack_start (GTK_BOX (self), self->priv->time_combo_box, FALSE, FALSE, 0);
+
+	dt = gth_datetime_new ();
+	g_date_set_dmy (dt->date, 1, 1, 2000);
+	for (h = 0; h < 24; h++) {
+		char *text;
+
+		gth_time_set_hms (dt->time, h, 0, 0, 0);
+		text = gth_datetime_strftime (dt, "%X");
+		gtk_combo_box_append_text (GTK_COMBO_BOX (self->priv->time_combo_box), text);
+		g_free (text);
+
+		gth_time_set_hms (dt->time, h, 30, 0, 0);
+		text = gth_datetime_strftime (dt, "%X");
+		gtk_combo_box_append_text (GTK_COMBO_BOX (self->priv->time_combo_box), text);
+		g_free (text);
+	}
+
+	g_signal_connect_swapped (self->priv->date_entry,
+				  "notify::text",
+				  G_CALLBACK (gth_time_selector_changed),
+				  self);
+	g_signal_connect_swapped (self->priv->time_combo_box,
+				  "changed",
+				  G_CALLBACK (gth_time_selector_changed),
+				  self);
+
+	gth_datetime_free (dt);
+}
+
+
+GType
+gth_time_selector_get_type (void)
+{
+	static GType type = 0;
+
+	if (! type) {
+		GTypeInfo type_info = {
+			sizeof (GthTimeSelectorClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_time_selector_class_init,
+			NULL,
+			NULL,
+			sizeof (GthTimeSelector),
+			0,
+			(GInstanceInitFunc) gth_time_selector_init
+		};
+
+		type = g_type_register_static (GTK_TYPE_HBOX,
+					       "GthTimeSelector",
+					       &type_info,
+					       0);
+	}
+
+	return type;
+}
+
+
+GtkWidget *
+gth_time_selector_new (void)
+{
+	GtkWidget *widget;
+
+	widget = GTK_WIDGET (g_object_new (GTH_TYPE_TIME_SELECTOR, NULL));
+	gth_time_selector_construct (GTH_TIME_SELECTOR (widget));
+
+	return widget;
+}
+
+
+void
+gth_time_selector_set_value (GthTimeSelector *self,
+			     GthDateTime     *date_time)
+{
+	*self->priv->date_time->date = *date_time->date;
+	*self->priv->date_time->time = *date_time->time;
+	update_view_from_data (self);
+}
+
+
+void
+gth_time_selector_set_exif_date (GthTimeSelector *self,
+				 const char      *exif_date)
+{
+	GthDateTime *date_time;
+
+	date_time = gth_datetime_new ();
+	if (! gth_datetime_from_exif_date (date_time, exif_date))
+		gth_datetime_clear (date_time);
+	gth_time_selector_set_value (self, date_time);
+
+	gth_datetime_free (date_time);
+}
+
+
+void
+gth_time_selector_get_value (GthTimeSelector *self,
+			     GthDateTime     *date_time)
+{
+	g_return_if_fail (date_time != NULL);
+
+	update_date_from_view (self);
+	*date_time->date = *self->priv->date_time->date;
+	*date_time->time = *self->priv->date_time->time;
+}
diff --git a/gthumb/gth-time-selector.h b/gthumb/gth-time-selector.h
new file mode 100644
index 0000000..fd4ffe6
--- /dev/null
+++ b/gthumb/gth-time-selector.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2009 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTH_TIME_SELECTOR_H
+#define GTH_TIME_SELECTOR_H
+
+#include <gtk/gtkhbox.h>
+#include "gth-time.h"
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_TIME_SELECTOR         (gth_time_selector_get_type ())
+#define GTH_TIME_SELECTOR(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GTH_TYPE_TIME_SELECTOR, GthTimeSelector))
+#define GTH_TIME_SELECTOR_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GTH_TYPE_TIME_SELECTOR, GthTimeSelectorClass))
+#define GTH_IS_TIME_SELECTOR(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTH_TYPE_TIME_SELECTOR))
+#define GTH_IS_TIME_SELECTOR_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GTH_TYPE_TIME_SELECTOR))
+#define GTH_TIME_SELECTOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GTH_TYPE_TIME_SELECTOR, GthTimeSelectorClass))
+
+typedef struct _GthTimeSelector         GthTimeSelector;
+typedef struct _GthTimeSelectorPrivate  GthTimeSelectorPrivate;
+typedef struct _GthTimeSelectorClass    GthTimeSelectorClass;
+
+struct _GthTimeSelector
+{
+	GtkHBox __parent;
+	GthTimeSelectorPrivate *priv;
+};
+
+struct _GthTimeSelectorClass
+{
+	GtkHBoxClass __parent_class;
+
+	/* -- Signals -- */
+
+	void  (* changed) (GthTimeSelector *time_selector);
+};
+
+GType         gth_time_selector_get_type       (void) G_GNUC_CONST;
+GtkWidget *   gth_time_selector_new            (void);
+void          gth_time_selector_set_value      (GthTimeSelector *self,
+					        GthDateTime     *date_time);
+void          gth_time_selector_set_exif_date  (GthTimeSelector *self,
+					        const char      *exif_date);
+void          gth_time_selector_get_value      (GthTimeSelector *self,
+						GthDateTime     *date_time);
+
+G_END_DECLS
+
+#endif /* GTH_TIME_SELECTOR_H */
diff --git a/gthumb/gth-time.c b/gthumb/gth-time.c
index 3a00ba2..f29ebce 100644
--- a/gthumb/gth-time.c
+++ b/gthumb/gth-time.c
@@ -103,6 +103,21 @@ gth_datetime_free (GthDateTime *dt)
 }
 
 
+void
+gth_datetime_clear (GthDateTime *dt)
+{
+	gth_time_clear (dt->time);
+	g_date_clear (dt->date, 1);
+}
+
+
+gboolean
+gth_datetime_valid (GthDateTime *dt)
+{
+	return gth_time_valid (dt->time) && g_date_valid (dt->date);
+}
+
+
 gboolean
 gth_datetime_from_exif_date (GthDateTime *dt,
 			     const char  *exif_date)
@@ -190,16 +205,33 @@ gth_datetime_from_exif_date (GthDateTime *dt,
 }
 
 
+gboolean
+gth_datetime_from_struct_tm (GthDateTime *dt,
+			     struct tm   *tm)
+{
+	if (tm->tm_hour < 0) {
+		gth_datetime_clear (dt);
+	}
+	else {
+		gth_time_set_hms (dt->time, tm->tm_hour, tm->tm_min, tm->tm_sec, 0);
+		g_date_set_dmy (dt->date, tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+	}
+}
+
+
 char *
 gth_datetime_to_exif_date (GthDateTime *dt)
 {
-	return g_strdup_printf ("%4d:%02d:%02d %02d:%02d:%02d",
-				g_date_get_year (dt->date),
-				g_date_get_month (dt->date),
-				g_date_get_day (dt->date),
-				dt->time->hour,
-				dt->time->min,
-				dt->time->sec);
+	if (gth_datetime_valid (dt))
+		return g_strdup_printf ("%4d:%02d:%02d %02d:%02d:%02d",
+					g_date_get_year (dt->date),
+					g_date_get_month (dt->date),
+					g_date_get_day (dt->date),
+					dt->time->hour,
+					dt->time->min,
+					dt->time->sec);
+	else
+		return g_strdup ("");
 }
 
 
diff --git a/gthumb/gth-time.h b/gthumb/gth-time.h
index 92f3f5c..9370cdb 100644
--- a/gthumb/gth-time.h
+++ b/gthumb/gth-time.h
@@ -51,8 +51,12 @@ void          gth_time_set_hms 		   (GthTime     *time,
 				 	    guint        usec);
 GthDateTime * gth_datetime_new             (void);
 void          gth_datetime_free            (GthDateTime *dt);
+void          gth_datetime_clear           (GthDateTime *dt);
+gboolean      gth_datetime_valid           (GthDateTime *dt);
 gboolean      gth_datetime_from_exif_date  (GthDateTime *dt,
 					    const char  *exif_date);
+gboolean      gth_datetime_from_struct_tm  (GthDateTime *dt,
+					    struct tm   *tm);
 char *        gth_datetime_to_exif_date    (GthDateTime *dt);
 void          gth_datetime_to_struct_tm    (GthDateTime *dt,
 					    struct tm   *tm);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]