[gthumb: 2/4] [change_date] added the change_date task



commit e49a52df8f0afbf32f7d95af3f11edace1e08103
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Fri Feb 5 20:26:30 2010 +0100

    [change_date] added the change_date task

 extensions/change_date/Makefile.am            |    2 +
 extensions/change_date/data/ui/change-date.ui |  260 ++++++++++++++++++-
 extensions/change_date/dlg-change-date.c      |  167 ++++++++++++-
 extensions/change_date/gth-change-date-task.c |  348 +++++++++++++++++++++++++
 extensions/change_date/gth-change-date-task.h |   76 ++++++
 gthumb/gio-utils.c                            |   19 ++
 gthumb/gio-utils.h                            |    4 +
 gthumb/glib-utils.c                           |   21 ++
 gthumb/glib-utils.h                           |    5 +
 gthumb/gth-browser.c                          |    3 +-
 gthumb/gth-file-data.c                        |   10 +
 gthumb/gth-file-data.h                        |    1 +
 gthumb/gth-time.c                             |   29 ++
 gthumb/gth-time.h                             |    4 +
 14 files changed, 941 insertions(+), 8 deletions(-)
---
diff --git a/extensions/change_date/Makefile.am b/extensions/change_date/Makefile.am
index d3daed7..9fb44b4 100644
--- a/extensions/change_date/Makefile.am
+++ b/extensions/change_date/Makefile.am
@@ -10,6 +10,8 @@ libchange_date_la_SOURCES = 		\
 	callbacks.h			\
 	dlg-change-date.c		\
 	dlg-change-date.h		\
+	gth-change-date-task.c		\
+	gth-change-date-task.h		\
 	main.c
 
 libchange_date_la_CFLAGS = $(GTHUMB_CFLAGS) -I$(top_srcdir) -I$(top_builddir)/gthumb 
diff --git a/extensions/change_date/data/ui/change-date.ui b/extensions/change_date/data/ui/change-date.ui
index 36a7582..4741c15 100644
--- a/extensions/change_date/data/ui/change-date.ui
+++ b/extensions/change_date/data/ui/change-date.ui
@@ -12,7 +12,7 @@
       <object class="GtkVBox" id="dialog-vbox1">
         <property name="visible">True</property>
         <property name="orientation">vertical</property>
-        <property name="spacing">2</property>
+        <property name="spacing">6</property>
         <child>
           <object class="GtkVBox" id="vbox1">
             <property name="visible">True</property>
@@ -43,7 +43,86 @@
                     <property name="visible">True</property>
                     <property name="left_padding">12</property>
                     <child>
-                      <placeholder/>
+                      <object class="GtkVBox" id="vbox57">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkCheckButton" id="change_last_modified_checkbutton">
+                            <property name="label" translatable="yes">_Last modified date</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_underline">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="change_comment_checkbutton">
+                            <property name="label" translatable="yes">Co_mment date</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_underline">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="change_datetime_checkbutton">
+                            <property name="label" translatable="yes">Exif DateTime tag</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_underline">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="change_datetimeoriginal_checkbutton">
+                            <property name="label" translatable="yes">Exif DateTimeOriginal tag</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_underline">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">3</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkCheckButton" id="change_datetimedigitized_checkbutton">
+                            <property name="label" translatable="yes">Exif DateTimeDigitized tag</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_underline">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">4</property>
+                          </packing>
+                        </child>
+                      </object>
                     </child>
                   </object>
                   <packing>
@@ -79,7 +158,176 @@
                     <property name="visible">True</property>
                     <property name="left_padding">12</property>
                     <child>
-                      <placeholder/>
+                      <object class="GtkVBox" id="vbox48">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkVBox" id="vbox49">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkRadioButton" id="to_following_date_radiobutton">
+                                <property name="label" translatable="yes">The _following date:</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="use_underline">True</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkAlignment" id="alignment3">
+                                <property name="visible">True</property>
+                                <property name="left_padding">12</property>
+                                <child>
+                                  <object class="GtkHBox" id="date_selector_box">
+                                    <property name="visible">True</property>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkRadioButton" id="to_last_modified_date_radiobutton">
+                            <property name="label" translatable="yes">File _modified date</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_underline">True</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">to_following_date_radiobutton</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkRadioButton" id="to_creation_date_radiobutton">
+                            <property name="label" translatable="yes">File c_reation date</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_underline">True</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">to_following_date_radiobutton</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkRadioButton" id="to_photo_original_date_radiobutton">
+                            <property name="label" translatable="yes">Date p_hoto was taken</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="use_underline">True</property>
+                            <property name="draw_indicator">True</property>
+                            <property name="group">to_following_date_radiobutton</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">3</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkVBox" id="vbox54">
+                            <property name="visible">True</property>
+                            <property name="orientation">vertical</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkHBox" id="hbox71">
+                                <property name="visible">True</property>
+                                <property name="spacing">6</property>
+                                <child>
+                                  <object class="GtkRadioButton" id="adjust_timezone_radiobutton">
+                                    <property name="label" translatable="yes">A_djust by</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="draw_indicator">True</property>
+                                    <property name="group">to_following_date_radiobutton</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkHBox" id="timezone_box">
+                                    <property name="visible">True</property>
+                                    <property name="spacing">6</property>
+                                    <child>
+                                      <object class="GtkSpinButton" id="adjust_timezone_spinbutton">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">&#x25CF;</property>
+                                        <property name="adjustment">timezone_adjustment</property>
+                                        <property name="climb_rate">1</property>
+                                        <property name="numeric">True</property>
+                                        <property name="wrap">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="position">0</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="label102">
+                                        <property name="visible">True</property>
+                                        <property name="label" translatable="yes">hours</property>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">4</property>
+                          </packing>
+                        </child>
+                      </object>
                     </child>
                   </object>
                   <packing>
@@ -158,4 +406,10 @@
       <action-widget response="0">ok_button</action-widget>
     </action-widgets>
   </object>
+  <object class="GtkAdjustment" id="timezone_adjustment">
+    <property name="lower">-23</property>
+    <property name="upper">23</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
 </interface>
diff --git a/extensions/change_date/dlg-change-date.c b/extensions/change_date/dlg-change-date.c
index cc35bfe..6f6a698 100644
--- a/extensions/change_date/dlg-change-date.c
+++ b/extensions/change_date/dlg-change-date.c
@@ -3,7 +3,7 @@
 /*
  *  GThumb
  *
- *  Copyright (C) 2001-2008 The Free Software Foundation, Inc.
+ *  Copyright (C) 2001-2010 The 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
@@ -23,12 +23,18 @@
 #include <config.h>
 #include <gtk/gtk.h>
 #include <gthumb.h>
+#include "gth-change-date-task.h"
+
+
+#define GET_WIDGET(x) (_gtk_builder_get_widget (data->builder, (x)))
+#define IS_ACTIVE(x) (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (x)))
 
 
 typedef struct {
 	GthBrowser *browser;
 	GtkBuilder *builder;
 	GtkWidget  *dialog;
+	GtkWidget  *date_selector;
 	GList      *file_list;
 } DialogData;
 
@@ -43,11 +49,104 @@ dialog_destroy_cb (GtkWidget  *widget,
 }
 
 
+static void
+ok_button_clicked (GtkWidget  *button,
+		   DialogData *data)
+{
+	GthChangeFields  change_fields;
+	GthChangeType    change_type;
+	GthDateTime     *date_time;
+	int              time_adjustment;
+	GthTask         *task;
+
+	date_time = NULL;
+
+	change_fields = 0;
+	if (IS_ACTIVE (GET_WIDGET ("change_last_modified_checkbutton")))
+		change_fields |= GTH_CHANGE_LAST_MODIFIED_DATE;
+	if (IS_ACTIVE (GET_WIDGET ("change_comment_checkbutton")))
+		change_fields |= GTH_CHANGE_COMMENT_DATE;
+	if (IS_ACTIVE (GET_WIDGET ("change_datetime_checkbutton")))
+		change_fields |= GTH_CHANGE_EXIF_DATETIME_TAG;
+	if (IS_ACTIVE (GET_WIDGET ("change_datetimeoriginal_checkbutton")))
+		change_fields |= GTH_CHANGE_EXIF_DATETIMEORIGINAL_TAG;
+	if (IS_ACTIVE (GET_WIDGET ("change_datetimedigitized_checkbutton")))
+		change_fields |= GTH_CHANGE_EXIF_DATETIMEDIGITIZED_TAG;
+
+	if (IS_ACTIVE (GET_WIDGET ("to_following_date_radiobutton"))) {
+		change_type = GTH_CHANGE_TO_FOLLOWING_DATE;
+		date_time = gth_datetime_new ();
+		gth_time_selector_get_value (GTH_TIME_SELECTOR (data->date_selector), date_time);
+	}
+	else if (IS_ACTIVE (GET_WIDGET ("to_last_modified_date_radiobutton")))
+		change_type = GTH_CHANGE_TO_FILE_MODIFIED_DATE;
+	else if (IS_ACTIVE (GET_WIDGET ("to_creation_date_radiobutton")))
+		change_type = GTH_CHANGE_TO_FILE_CREATION_DATE;
+	else if (IS_ACTIVE (GET_WIDGET ("to_photo_original_date_radiobutton")))
+		change_type = GTH_CHANGE_TO_PHOTO_ORIGINAL_DATE;
+	else if (IS_ACTIVE (GET_WIDGET ("adjust_timezone_radiobutton"))) {
+		change_type = GTH_CHANGE_ADJUST_TIMEZONE;
+		time_adjustment = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (GET_WIDGET ("adjust_timezone_spinbutton")));
+	}
+
+	task = gth_change_date_task_new (data->file_list,
+					 change_fields,
+					 change_type,
+					 date_time,
+					 time_adjustment);
+	gth_browser_exec_task (data->browser, task, FALSE);
+	gtk_widget_destroy (data->dialog);
+
+	g_object_unref (task);
+	gth_datetime_free (date_time);
+}
+
+
+static void
+help_button_cb (GtkWidget  *widget,
+		DialogData *data)
+{
+	show_help_dialog (GTK_WINDOW (data->dialog), "gthumb-change-date");
+}
+
+
+static void
+update_sensitivity (DialogData *data)
+{
+	gtk_widget_set_sensitive (GET_WIDGET ("ok_button"),
+				  (IS_ACTIVE (GET_WIDGET ("change_last_modified_checkbutton"))
+				   || IS_ACTIVE (GET_WIDGET ("change_comment_checkbutton"))
+				   || IS_ACTIVE (GET_WIDGET ("change_datetime_checkbutton"))
+				   || IS_ACTIVE (GET_WIDGET ("change_datetimeoriginal_checkbutton"))
+				   || IS_ACTIVE (GET_WIDGET ("change_datetimedigitized_checkbutton"))));
+	gtk_widget_set_sensitive (data->date_selector, IS_ACTIVE (GET_WIDGET ("to_following_date_radiobutton")));
+	gtk_widget_set_sensitive (GET_WIDGET ("timezone_box"), IS_ACTIVE (GET_WIDGET ("adjust_timezone_radiobutton")));
+
+	if (IS_ACTIVE (GET_WIDGET ("change_last_modified_checkbutton"))) {
+		gtk_widget_set_sensitive (GET_WIDGET ("to_last_modified_date_radiobutton"), FALSE);
+		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("to_last_modified_date_radiobutton"))))
+			gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("to_following_date_radiobutton")), TRUE);
+	}
+	else
+		gtk_widget_set_sensitive (GET_WIDGET ("to_last_modified_date_radiobutton"), TRUE);
+}
+
+
+static void
+radio_button_clicked (GtkWidget  *button,
+		      DialogData *data)
+{
+	update_sensitivity (data);
+}
+
+
 void
 dlg_change_date (GthBrowser *browser,
 		 GList      *file_list)
 {
-	DialogData *data;
+	DialogData  *data;
+	GTimeVal     timeval;
+	GthDateTime *datetime;
 
 	data = g_new0 (DialogData, 1);
 	data->browser = browser;
@@ -56,20 +155,80 @@ dlg_change_date (GthBrowser *browser,
 
 	/* Get the widgets. */
 
-	data->dialog = _gtk_builder_get_widget (data->builder, "change_date_dialog");
+	data->dialog = GET_WIDGET ("change_date_dialog");
+	data->date_selector = gth_time_selector_new ();
+
+	datetime = gth_datetime_new ();
+	g_get_current_time (&timeval);
+	gth_datetime_from_timeval (datetime, &timeval);
+	gth_time_selector_set_value (GTH_TIME_SELECTOR (data->date_selector), datetime);
+	gtk_widget_show (data->date_selector);
+	gtk_box_pack_start (GTK_BOX (GET_WIDGET ("date_selector_box")), data->date_selector, TRUE, TRUE, 0);
 	
+	gth_datetime_free (datetime);
+
 	/* Set widgets data. */
 
+	update_sensitivity (data);
+
 	/* Set the signals handlers. */
 	
 	g_signal_connect (G_OBJECT (data->dialog), 
 			  "destroy",
 			  G_CALLBACK (dialog_destroy_cb),
 			  data);
-	g_signal_connect_swapped (_gtk_builder_get_widget (data->builder, "close_button"),
+	g_signal_connect_swapped (GET_WIDGET ("close_button"),
 				  "clicked",
 				  G_CALLBACK (gtk_widget_destroy),
 				  G_OBJECT (data->dialog));
+	g_signal_connect (GET_WIDGET ("ok_button"),
+			  "clicked",
+			  G_CALLBACK (ok_button_clicked),
+			  data);
+	g_signal_connect (GET_WIDGET ("help_button"),
+			  "clicked",
+			  G_CALLBACK (help_button_cb),
+			  data);
+	g_signal_connect (GET_WIDGET ("change_last_modified_checkbutton"),
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data);
+	g_signal_connect (GET_WIDGET ("change_comment_checkbutton"),
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data);
+	g_signal_connect (GET_WIDGET ("change_datetime_checkbutton"),
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data);
+	g_signal_connect (GET_WIDGET ("change_datetimeoriginal_checkbutton"),
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data);
+	g_signal_connect (GET_WIDGET ("change_datetimedigitized_checkbutton"),
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data);
+	g_signal_connect (GET_WIDGET ("to_following_date_radiobutton"),
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data);
+	g_signal_connect (GET_WIDGET ("to_last_modified_date_radiobutton"),
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data);
+	g_signal_connect (GET_WIDGET ("to_creation_date_radiobutton"),
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data);
+	g_signal_connect (GET_WIDGET ("to_photo_original_date_radiobutton"),
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data);
+	g_signal_connect (GET_WIDGET ("adjust_timezone_radiobutton"),
+			  "clicked",
+			  G_CALLBACK (radio_button_clicked),
+			  data);
 
 	/* run dialog. */
 
diff --git a/extensions/change_date/gth-change-date-task.c b/extensions/change_date/gth-change-date-task.c
new file mode 100644
index 0000000..5ad93fd
--- /dev/null
+++ b/extensions/change_date/gth-change-date-task.c
@@ -0,0 +1,348 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2010 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>
+#include "gth-change-date-task.h"
+
+
+struct _GthChangeDateTaskPrivate {
+	GList           *files; /* GFile */
+	GList           *file_list; /* GthFileData */
+	GthChangeFields  fields;
+	GthChangeType    change_type;
+	GthDateTime     *date_time;
+	int              timezone_offset;
+	int              n_files;
+	int              n_current;
+	GList           *current;
+};
+
+
+static gpointer parent_class = NULL;
+
+
+static void
+gth_change_date_task_finalize (GObject *object)
+{
+	GthChangeDateTask *self;
+
+	self = GTH_CHANGE_DATE_TASK (object);
+
+	_g_object_list_unref (self->priv->file_list);
+	_g_object_list_unref (self->priv->files);
+	gth_datetime_free (self->priv->date_time);
+
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static void
+set_date_from_change_type (GthChangeDateTask *self,
+			   GthFileData       *file_data,
+			   GthDateTime       *date_time)
+{
+	if (self->priv->change_type == GTH_CHANGE_TO_FOLLOWING_DATE) {
+		gth_datetime_copy (self->priv->date_time, date_time);
+	}
+	else if (self->priv->change_type == GTH_CHANGE_TO_FILE_MODIFIED_DATE) {
+		gth_datetime_from_timeval (date_time, gth_file_data_get_modification_time (file_data));
+	}
+	else if (self->priv->change_type == GTH_CHANGE_TO_FILE_CREATION_DATE) {
+		gth_datetime_from_timeval (date_time, gth_file_data_get_creation_time (file_data));
+	}
+	else if (self->priv->change_type == GTH_CHANGE_TO_PHOTO_ORIGINAL_DATE) {
+		GTimeVal time_val;
+
+		if (gth_file_data_get_digitalization_time (file_data, &time_val))
+			gth_datetime_from_timeval (date_time, &time_val);
+	}
+}
+
+
+static void
+update_modification_time (GthChangeDateTask *self)
+{
+	GthDateTime *date_time;
+	GList       *scan;
+	GError      *error = NULL;
+
+	if ((self->priv->fields & GTH_CHANGE_LAST_MODIFIED_DATE) == 0) {
+		gth_task_completed (GTH_TASK (self), NULL);
+		return;
+	}
+
+	date_time = gth_datetime_new ();
+	for (scan = self->priv->file_list; scan; scan = scan->next) {
+		GthFileData *file_data = scan->data;
+		GTimeVal     timeval;
+
+		gth_datetime_clear (date_time);
+		set_date_from_change_type (self, file_data, date_time);
+		if (! gth_datetime_valid (date_time))
+			continue;
+
+		if (gth_datetime_to_timeval (date_time, &timeval)) {
+			if (! _g_file_set_modification_time (file_data->file,
+							     &timeval,
+							     gth_task_get_cancellable (GTH_TASK (self)),
+							     &error))
+			{
+				break;
+			}
+		}
+	}
+	gth_task_completed (GTH_TASK (self), error);
+
+	gth_datetime_free (date_time);
+}
+
+
+static void
+write_metadata_reasy_cb (GError   *error,
+			 gpointer  user_data)
+{
+	GthChangeDateTask *self = user_data;
+
+	if (error != NULL) {
+		gth_task_completed (GTH_TASK (self), error);
+		return;
+	}
+
+	if (g_cancellable_set_error_if_cancelled (gth_task_get_cancellable (GTH_TASK (self)), &error)) {
+		gth_task_completed (GTH_TASK (self), error);
+		return;
+	}
+
+	update_modification_time (self);
+}
+
+
+static void
+info_ready_cb (GList    *files,
+	       GError   *error,
+	       gpointer  user_data)
+{
+	GthChangeDateTask *self = user_data;
+	GthDateTime       *date_time;
+	GList             *scan;
+	GPtrArray         *attribute_v;
+
+	if (error != NULL) {
+		gth_task_completed (GTH_TASK (self), error);
+		return;
+	}
+
+	if (g_cancellable_set_error_if_cancelled (gth_task_get_cancellable (GTH_TASK (self)), &error)) {
+		gth_task_completed (GTH_TASK (self), error);
+		return;
+	}
+
+	date_time = gth_datetime_new ();
+	self->priv->file_list = _g_object_list_ref (files);
+	for (scan = self->priv->file_list; scan; scan = scan->next) {
+		GthFileData *file_data = scan->data;
+		char        *raw;
+		char        *formatted;
+
+		if (self->priv->change_type == GTH_CHANGE_ADJUST_TIMEZONE) {
+			/* FIXME */
+			return;
+		}
+
+		gth_datetime_clear (date_time);
+		set_date_from_change_type (self, file_data, date_time);
+		if (! gth_datetime_valid (date_time))
+			continue;
+
+		raw = gth_datetime_to_exif_date (date_time);
+		formatted = gth_datetime_strftime (date_time, "%x");
+		if (self->priv->fields & GTH_CHANGE_COMMENT_DATE) {
+			GObject *metadata;
+
+			metadata = (GObject *) gth_metadata_new ();
+			g_object_set (metadata,
+				      "id", "general::datetime",
+				      "raw", raw,
+				      "formatted", formatted,
+				      NULL);
+			g_file_info_set_attribute_object (file_data->info, "general::datetime", metadata);
+			g_object_unref (metadata);
+		}
+		else if (self->priv->fields & GTH_CHANGE_EXIF_DATETIME_TAG) {
+			GObject *metadata;
+
+			metadata = (GObject *) gth_metadata_new ();
+			g_object_set (metadata,
+				      "id", "Exif::Image::DateTime",
+				      "raw", raw,
+				      "formatted", formatted,
+				      NULL);
+			g_file_info_set_attribute_object (file_data->info, "Exif::Image::DateTime", metadata);
+
+			g_object_unref (metadata);
+		}
+		else if (self->priv->fields & GTH_CHANGE_EXIF_DATETIMEORIGINAL_TAG) {
+			GObject *metadata;
+
+			metadata = (GObject *) gth_metadata_new ();
+			g_object_set (metadata,
+				      "id", "Exif::Photo::DateTimeOriginal",
+				      "raw", raw,
+				      "formatted", formatted,
+				      NULL);
+			g_file_info_set_attribute_object (file_data->info, "Exif::Photo::DateTimeOriginal", metadata);
+
+			g_object_unref (metadata);
+		}
+		else if (self->priv->fields & GTH_CHANGE_EXIF_DATETIMEDIGITIZED_TAG) {
+			GObject *metadata;
+
+			metadata = (GObject *) gth_metadata_new ();
+			g_object_set (metadata,
+				      "id", "Exif::Photo::DateTimeDigitized",
+				      "raw", raw,
+				      "formatted", formatted,
+				      NULL);
+			g_file_info_set_attribute_object (file_data->info, "Exif::Photo::DateTimeDigitized", metadata);
+
+			g_object_unref (metadata);
+		}
+
+		g_free (formatted);
+		g_free (raw);
+	}
+
+	attribute_v = g_ptr_array_new ();
+	if (self->priv->fields & GTH_CHANGE_COMMENT_DATE)
+		g_ptr_array_add (attribute_v, "general::datetime");
+	if (self->priv->fields & GTH_CHANGE_EXIF_DATETIME_TAG)
+		g_ptr_array_add (attribute_v, "Exif::Image::DateTime");
+	if (self->priv->fields & GTH_CHANGE_EXIF_DATETIMEORIGINAL_TAG)
+		g_ptr_array_add (attribute_v, "Exif::Photo::DateTimeOriginal");
+	if (self->priv->fields & GTH_CHANGE_EXIF_DATETIMEDIGITIZED_TAG)
+		g_ptr_array_add (attribute_v, "Exif::Photo::DateTimeDigitized");
+	if (attribute_v->len > 0) {
+		char *attributes;
+
+		attributes = _g_string_array_join (attribute_v, ",");
+		_g_write_metadata_async (self->priv->file_list,
+					 attributes,
+					 gth_task_get_cancellable (GTH_TASK (self)),
+					 write_metadata_reasy_cb,
+					 self);
+
+		g_free (attributes);
+	}
+	else
+		update_modification_time (self);
+
+	g_ptr_array_free (attribute_v, TRUE);
+	gth_datetime_free (date_time);
+}
+
+
+static void
+gth_change_date_task_exec (GthTask *task)
+{
+	GthChangeDateTask *self = GTH_CHANGE_DATE_TASK (task);
+
+	_g_query_all_metadata_async (self->priv->files,
+				     FALSE,
+				     TRUE,
+				     "*",
+				     gth_task_get_cancellable (task),
+				     info_ready_cb,
+				     self);
+}
+
+
+static void
+gth_change_date_task_class_init (GthChangeDateTaskClass *klass)
+{
+	GObjectClass *object_class;
+	GthTaskClass *task_class;
+
+	parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GthChangeDateTaskPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gth_change_date_task_finalize;
+
+	task_class = GTH_TASK_CLASS (klass);
+	task_class->exec = gth_change_date_task_exec;
+}
+
+
+static void
+gth_change_date_task_init (GthChangeDateTask *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_CHANGE_DATE_TASK, GthChangeDateTaskPrivate);
+	self->priv->date_time = gth_datetime_new ();
+}
+
+
+GType
+gth_change_date_task_get_type (void)
+{
+	static GType type = 0;
+
+	if (! type) {
+		GTypeInfo type_info = {
+			sizeof (GthChangeDateTaskClass),
+			NULL,
+			NULL,
+			(GClassInitFunc) gth_change_date_task_class_init,
+			NULL,
+			NULL,
+			sizeof (GthChangeDateTask),
+			0,
+			(GInstanceInitFunc) gth_change_date_task_init
+		};
+
+		type = g_type_register_static (GTH_TYPE_TASK,
+					       "GthChangeDateTask",
+					       &type_info,
+					       0);
+	}
+
+	return type;
+}
+
+
+GthTask *
+gth_change_date_task_new (GList             *files, /* GthFileData */
+			  GthChangeFields    fields,
+			  GthChangeType      change_type,
+			  GthDateTime       *date_time,
+			  int                timezone_offset)
+{
+	GthChangeDateTask *self;
+
+	self = GTH_CHANGE_DATE_TASK (g_object_new (GTH_TYPE_CHANGE_DATE_TASK, NULL));
+	self->priv->files = gth_file_data_list_to_file_list (files);
+	self->priv->fields = fields;
+	self->priv->change_type = change_type;
+	gth_datetime_copy (date_time, self->priv->date_time);
+	self->priv->timezone_offset = timezone_offset;
+
+	return (GthTask *) self;
+}
diff --git a/extensions/change_date/gth-change-date-task.h b/extensions/change_date/gth-change-date-task.h
new file mode 100644
index 0000000..bc0af0e
--- /dev/null
+++ b/extensions/change_date/gth-change-date-task.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2010 The 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_CHANGE_DATE_TASK_H
+#define GTH_CHANGE_DATE_TASK_H
+
+#include <glib.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+	GTH_CHANGE_LAST_MODIFIED_DATE = 1 << 0,
+	GTH_CHANGE_COMMENT_DATE = 1 << 1,
+	GTH_CHANGE_EXIF_DATETIME_TAG = 1 << 2,
+	GTH_CHANGE_EXIF_DATETIMEORIGINAL_TAG = 1 << 3,
+	GTH_CHANGE_EXIF_DATETIMEDIGITIZED_TAG = 1 << 4,
+} GthChangeFields;
+
+typedef enum {
+	GTH_CHANGE_TO_FOLLOWING_DATE,
+	GTH_CHANGE_TO_FILE_MODIFIED_DATE,
+	GTH_CHANGE_TO_FILE_CREATION_DATE,
+	GTH_CHANGE_TO_PHOTO_ORIGINAL_DATE,
+	GTH_CHANGE_ADJUST_TIMEZONE
+} GthChangeType;
+
+#define GTH_TYPE_CHANGE_DATE_TASK            (gth_change_date_task_get_type ())
+#define GTH_CHANGE_DATE_TASK(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_CHANGE_DATE_TASK, GthChangeDateTask))
+#define GTH_CHANGE_DATE_TASK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_CHANGE_DATE_TASK, GthChangeDateTaskClass))
+#define GTH_IS_CHANGE_DATE_TASK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_CHANGE_DATE_TASK))
+#define GTH_IS_CHANGE_DATE_TASK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_CHANGE_DATE_TASK))
+#define GTH_CHANGE_DATE_TASK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_CHANGE_DATE_TASK, GthChangeDateTaskClass))
+
+typedef struct _GthChangeDateTask        GthChangeDateTask;
+typedef struct _GthChangeDateTaskClass   GthChangeDateTaskClass;
+typedef struct _GthChangeDateTaskPrivate GthChangeDateTaskPrivate;
+
+struct _GthChangeDateTask {
+	GthTask __parent;
+	GthChangeDateTaskPrivate *priv;
+};
+
+struct _GthChangeDateTaskClass {
+	GthTaskClass __parent;
+};
+
+GType         gth_change_date_task_get_type  (void);
+GthTask *     gth_change_date_task_new       (GList             *files, /* GthFileData */
+					      GthChangeFields    fields,
+					      GthChangeType      change_type,
+					      GthDateTime       *date_time,
+					      int                timezone_offset);
+
+G_END_DECLS
+
+#endif /* GTH_CHANGE_DATE_TASK_H */
diff --git a/gthumb/gio-utils.c b/gthumb/gio-utils.c
index df149bc..fd54af9 100644
--- a/gthumb/gio-utils.c
+++ b/gthumb/gio-utils.c
@@ -2298,3 +2298,22 @@ _g_directory_make (GFile    *file,
 					    NULL,
 					    error);
 }
+
+
+gboolean
+_g_file_set_modification_time (GFile         *file,
+			       GTimeVal      *timeval,
+			       GCancellable  *cancellable,
+			       GError       **error)
+{
+	GFileInfo *info;
+	gboolean   result;
+
+	info = g_file_info_new ();
+        g_file_info_set_modification_time (info, timeval);
+        result = g_file_set_attributes_from_info (file, info, G_FILE_QUERY_INFO_NONE, cancellable, error);
+
+        g_object_unref (info);
+
+        return result;
+}
diff --git a/gthumb/gio-utils.h b/gthumb/gio-utils.h
index ec8bf68..42a322f 100644
--- a/gthumb/gio-utils.h
+++ b/gthumb/gio-utils.h
@@ -167,6 +167,10 @@ GFile * _g_directory_create_unique   (GFile                 *parent,
 				      const char            *display_name,
 				      const char            *suffix,
 				      GError               **error);
+gboolean _g_file_set_modification_time (GFile               *file,
+					GTimeVal            *timeval,
+					GCancellable        *cancellable,
+					GError             **error);
 
 /* convenience macros */
 
diff --git a/gthumb/glib-utils.c b/gthumb/glib-utils.c
index fcc1158..b7987df 100644
--- a/gthumb/glib-utils.c
+++ b/gthumb/glib-utils.c
@@ -1104,6 +1104,27 @@ _g_str_remove_suffix (const char *s,
 }
 
 
+/* Array utils*/
+
+
+char *
+_g_string_array_join (GPtrArray  *array,
+		      const char *separator)
+{
+	GString *s;
+	int      i;
+
+	s = g_string_new ("");
+	for (i = 0; i < array->len; i++) {
+		if ((i > 0) && (separator != NULL))
+			g_string_append (s, separator);
+		g_string_append (s, g_ptr_array_index (array, i));
+	}
+
+	return g_string_free (s, FALSE);
+}
+
+
 /* Regexp utils */
 
 static char **
diff --git a/gthumb/glib-utils.h b/gthumb/glib-utils.h
index d9fbc60..b1cc1ba 100644
--- a/gthumb/glib-utils.h
+++ b/gthumb/glib-utils.h
@@ -182,6 +182,11 @@ int             _g_strv_find                     (char        **v,
 char *          _g_str_remove_suffix             (const char   *s,
 						  const char   *suffix);
 
+/* Array utils*/
+
+char *          _g_string_array_join             (GPtrArray    *array,
+						  const char   *separator);
+
 /* Regexp utils */
 
 GRegex **       get_regexps_from_pattern         (const char  *pattern_string,
diff --git a/gthumb/gth-browser.c b/gthumb/gth-browser.c
index 57bdee6..0dc616c 100644
--- a/gthumb/gth-browser.c
+++ b/gthumb/gth-browser.c
@@ -4522,7 +4522,8 @@ _gth_browser_load_file (GthBrowser  *browser,
 	}
 
 	if ((browser->priv->current_file != NULL) && g_file_equal (file_data->file, browser->priv->current_file->file)) {
-		gth_window_set_current_page (GTH_WINDOW (browser), GTH_BROWSER_PAGE_VIEWER);
+		if (view)
+			gth_window_set_current_page (GTH_WINDOW (browser), GTH_BROWSER_PAGE_VIEWER);
 		return;
 	}
 
diff --git a/gthumb/gth-file-data.c b/gthumb/gth-file-data.c
index 054ab2e..6885468 100644
--- a/gthumb/gth-file-data.c
+++ b/gthumb/gth-file-data.c
@@ -32,6 +32,7 @@
 #define GTH_FILE_DATA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTH_TYPE_FILE_DATA, GthFileDataPrivate))
 
 struct _GthFileDataPrivate {
+	GTimeVal  ctime;   /* creation time */
 	GTimeVal  mtime;   /* modification time */
 	GTimeVal  dtime;   /* digitalization time */
 	char     *sort_key;
@@ -264,6 +265,15 @@ gth_file_data_get_modification_time (GthFileData *self)
 }
 
 
+GTimeVal *
+gth_file_data_get_creation_time (GthFileData *self)
+{
+	self->priv->ctime.tv_sec = g_file_info_get_attribute_uint64 (self->info, G_FILE_ATTRIBUTE_TIME_CREATED);
+	self->priv->ctime.tv_usec = g_file_info_get_attribute_uint32 (self->info, G_FILE_ATTRIBUTE_TIME_CREATED_USEC);
+	return &self->priv->ctime;
+}
+
+
 static const char *try_digitalization_tag[] = {
 	"Exif::Photo::DateTimeOriginal",
 	"Xmp::exif::DateTimeOriginal",
diff --git a/gthumb/gth-file-data.h b/gthumb/gth-file-data.h
index a55bafd..8740f3d 100644
--- a/gthumb/gth-file-data.h
+++ b/gthumb/gth-file-data.h
@@ -83,6 +83,7 @@ const char *  gth_file_data_get_mime_type           (GthFileData    *self);
 const char *  gth_file_data_get_filename_sort_key   (GthFileData    *self);
 time_t        gth_file_data_get_mtime               (GthFileData    *self);
 GTimeVal *    gth_file_data_get_modification_time   (GthFileData    *self);
+GTimeVal *    gth_file_data_get_creation_time       (GthFileData    *self);
 gboolean      gth_file_data_get_digitalization_time (GthFileData    *self,
 				                     GTimeVal       *_time);
 gboolean      gth_file_data_is_readable             (GthFileData    *self);
diff --git a/gthumb/gth-time.c b/gthumb/gth-time.c
index 2ec4068..a829e09 100644
--- a/gthumb/gth-time.c
+++ b/gthumb/gth-time.c
@@ -105,6 +105,19 @@ gth_datetime_free (GthDateTime *dt)
 
 
 void
+gth_datetime_copy (GthDateTime *src,
+		   GthDateTime *dest)
+{
+	if (gth_datetime_valid (src)) {
+		*dest->date = *src->date;
+		*dest->time = *src->time;
+	}
+	else
+		gth_datetime_clear (dest);
+}
+
+
+void
 gth_datetime_clear (GthDateTime *dt)
 {
 	gth_time_clear (dt->time);
@@ -264,6 +277,22 @@ gth_datetime_to_struct_tm (GthDateTime *dt,
 }
 
 
+gboolean
+gth_datetime_to_timeval (GthDateTime *dt,
+			 GTimeVal    *tv)
+{
+	char     *exif_date;
+	gboolean  result;
+
+	exif_date = gth_datetime_to_exif_date (dt);
+	result = _g_time_val_from_exif_date (exif_date, tv);
+
+	g_free (exif_date);
+
+	return result;
+}
+
+
 char *
 gth_datetime_strftime (GthDateTime *dt,
 		       const char  *format)
diff --git a/gthumb/gth-time.h b/gthumb/gth-time.h
index a9c9feb..4ad5322 100644
--- a/gthumb/gth-time.h
+++ b/gthumb/gth-time.h
@@ -52,6 +52,8 @@ void          gth_time_set_hms 		   (GthTime     *time,
 GthDateTime * gth_datetime_new             (void);
 void          gth_datetime_free            (GthDateTime *dt);
 void          gth_datetime_clear           (GthDateTime *dt);
+void          gth_datetime_copy            (GthDateTime *src,
+					    GthDateTime *dest);
 gboolean      gth_datetime_valid           (GthDateTime *dt);
 void          gth_datetime_from_timeval    (GthDateTime *dt,
 					    GTimeVal    *tv);
@@ -62,6 +64,8 @@ void          gth_datetime_from_struct_tm  (GthDateTime *dt,
 char *        gth_datetime_to_exif_date    (GthDateTime *dt);
 void          gth_datetime_to_struct_tm    (GthDateTime *dt,
 					    struct tm   *tm);
+gboolean      gth_datetime_to_timeval      (GthDateTime *dt,
+					    GTimeVal    *tv);
 char *        gth_datetime_strftime        (GthDateTime *dt,
 					    const char  *format);
 



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