/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Pix
*
* 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, see .
*/
#include
#include
#include
#include "gth-edit-comment-dialog.h"
#include "gth-edit-general-page.h"
#include "utils.h"
#define GET_WIDGET(name) _gtk_builder_get_widget (self->priv->builder, (name))
typedef enum {
NO_DATE = 0,
FOLLOWING_DATE,
CURRENT_DATE,
PHOTO_DATE,
LAST_MODIFIED_DATE,
CREATION_DATE,
NO_CHANGE
} DateOption;
struct _GthEditGeneralPagePrivate {
GFileInfo *info;
GtkBuilder *builder;
GtkWidget *date_combobox;
GtkWidget *date_selector;
GtkWidget *tags_entry;
GTimeVal current_date;
};
static void gth_edit_general_page_gth_edit_general_page_interface_init (GthEditCommentPageInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GthEditGeneralPage,
gth_edit_general_page,
GTK_TYPE_BOX,
G_ADD_PRIVATE (GthEditGeneralPage)
G_IMPLEMENT_INTERFACE (GTH_TYPE_EDIT_COMMENT_PAGE,
gth_edit_general_page_gth_edit_general_page_interface_init))
static void
gth_edit_general_page_real_set_file_list (GthEditCommentPage *base,
GList *file_list)
{
GthEditGeneralPage *self;
GtkTextBuffer *buffer;
GthMetadata *metadata;
GthMetadataProvider *provider;
GHashTable *common_tags;
GHashTable *no_common_tags;
GList *common_tags_list;
GList *no_common_tags_list;
gboolean no_provider;
GthFileData *file_data;
const char *mime_type;
self = GTH_EDIT_GENERAL_PAGE (base);
/* get the metadata common to the seleted files */
_g_object_unref (self->priv->info);
self->priv->info = gth_file_data_list_get_common_info (file_list, "general::description,general::title,general::location,general::datetime,general::tags,general::rating");
/* description */
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (GET_WIDGET ("note_text")));
metadata = (GthMetadata *) g_file_info_get_attribute_object (self->priv->info, "general::description");
if (metadata != NULL) {
GtkTextIter iter;
gtk_text_buffer_set_text (buffer, gth_metadata_get_formatted (metadata), -1);
gtk_text_buffer_get_iter_at_line (buffer, &iter, 0);
gtk_text_buffer_place_cursor (buffer, &iter);
}
else
gtk_text_buffer_set_text (buffer, "", -1);
/* title */
metadata = (GthMetadata *) g_file_info_get_attribute_object (self->priv->info, "general::title");
if (metadata != NULL)
gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("title_entry")), gth_metadata_get_formatted (metadata));
else
gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("title_entry")), "");
/* location */
metadata = (GthMetadata *) g_file_info_get_attribute_object (self->priv->info, "general::location");
if (metadata != NULL)
gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("place_entry")), gth_metadata_get_formatted (metadata));
else
gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("place_entry")), "");
/* date */
metadata = (GthMetadata *) g_file_info_get_attribute_object (self->priv->info, "general::datetime");
if (metadata != NULL) {
gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->date_combobox), FOLLOWING_DATE);
gtk_widget_set_sensitive (self->priv->date_combobox, TRUE);
gth_time_selector_set_exif_date (GTH_TIME_SELECTOR (self->priv->date_selector), gth_metadata_get_raw (metadata));
}
else {
if ((file_list != NULL) && (file_list->next == NULL))
gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->date_combobox), NO_DATE);
else
gtk_combo_box_set_active (GTK_COMBO_BOX (self->priv->date_combobox), NO_CHANGE);
gtk_widget_set_sensitive (self->priv->date_combobox, FALSE);
gth_time_selector_set_exif_date (GTH_TIME_SELECTOR (self->priv->date_selector), "");
}
/* tags */
utils_get_common_tags (file_list, &common_tags, &no_common_tags);
common_tags_list = g_hash_table_get_keys (common_tags);
no_common_tags_list = g_hash_table_get_keys (no_common_tags);
gth_tags_entry_set_tag_list (GTH_TAGS_ENTRY (self->priv->tags_entry),
common_tags_list,
no_common_tags_list);
g_list_free (no_common_tags_list);
g_list_free (common_tags_list);
g_hash_table_unref (no_common_tags);
g_hash_table_unref (common_tags);
/* rating */
metadata = (GthMetadata *) g_file_info_get_attribute_object (self->priv->info, "general::rating");
if (metadata != NULL) {
int v;
sscanf (gth_metadata_get_raw (metadata), "%d", &v);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("rating_spinbutton")), v);
}
else
gtk_spin_button_set_value (GTK_SPIN_BUTTON (GET_WIDGET ("rating_spinbutton")), 0);
gtk_widget_grab_focus (GET_WIDGET ("note_text"));
/* set a widget insensitive if there is no way to save the relative
* metadata */
no_provider = TRUE;
if (file_list == NULL) {
file_data = gth_file_data_new (NULL, NULL);
}
else if (file_list->next == NULL) {
GthFileData *first = file_list->data;
file_data = gth_file_data_new (first->file, first->info);
}
else
file_data = gth_file_data_new (NULL, ((GthFileData *) file_list->data)->info);
mime_type = gth_file_data_get_mime_type (file_data);
provider = gth_main_get_metadata_writer ("general::description", mime_type);
gtk_widget_set_sensitive (GET_WIDGET ("note_text"), provider != NULL);
if (no_provider && (provider != NULL))
no_provider = FALSE;
_g_object_unref (provider);
provider = gth_main_get_metadata_writer ("general::location", mime_type);
gtk_widget_set_sensitive (GET_WIDGET ("place_entry"), provider != NULL);
if (no_provider && (provider != NULL))
no_provider = FALSE;
_g_object_unref (provider);
provider = gth_main_get_metadata_writer ("general::datetime", mime_type);
gtk_widget_set_sensitive (self->priv->date_combobox, provider != NULL);
if (provider == NULL)
gtk_widget_set_sensitive (self->priv->date_selector, FALSE);
if (no_provider && (provider != NULL))
no_provider = FALSE;
_g_object_unref (provider);
provider = gth_main_get_metadata_writer ("general::tags", mime_type);
gtk_widget_set_sensitive (self->priv->tags_entry, provider != NULL);
if (no_provider && (provider != NULL))
no_provider = FALSE;
_g_object_unref (provider);
provider = gth_main_get_metadata_writer ("general::rating", mime_type);
gtk_widget_set_sensitive (GET_WIDGET ("rating_spinbutton"), provider != NULL);
if (no_provider && (provider != NULL))
no_provider = FALSE;
_g_object_unref (provider);
/* hide the whole page if no metadata can be saved */
if (no_provider)
gtk_widget_hide (GTK_WIDGET (self));
else
gtk_widget_show (GTK_WIDGET (self));
g_object_unref (file_data);
}
static char *
get_date_from_option (GthEditGeneralPage *self,
DateOption option,
GFileInfo *info)
{
GTimeVal timeval;
GthDateTime *date_time;
char *exif_date;
GthMetadata *metadata;
_g_time_val_reset (&timeval);
switch (option) {
case NO_DATE:
return g_strdup ("");
case FOLLOWING_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);
_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 (&self->priv->current_date);
timeval = self->priv->current_date;
break;
case PHOTO_DATE:
metadata = (GthMetadata *) g_file_info_get_attribute_object (info, "Embedded::Photo::DateTimeOriginal");
if (metadata != NULL)
_g_time_val_from_exif_date (gth_metadata_get_raw (metadata), &timeval);
else
return g_strdup ("");
break;
case LAST_MODIFIED_DATE:
timeval.tv_sec = g_file_info_get_attribute_uint64 (info, "time::modified");
timeval.tv_usec = g_file_info_get_attribute_uint32 (info, "time::modified-usec");
break;
case CREATION_DATE:
timeval.tv_sec = g_file_info_get_attribute_uint64 (info, "time::created");
timeval.tv_usec = g_file_info_get_attribute_uint32 (info, "time::created-usec");
break;
case NO_CHANGE:
metadata = (GthMetadata *) g_file_info_get_attribute_object (info, "general::datetime");
if (metadata != NULL)
_g_time_val_from_exif_date (gth_metadata_get_raw (metadata), &timeval);
else
return g_strdup ("");
break;
}
return _g_time_val_to_exif_date (&timeval);
}
static void
gth_edit_general_page_real_update_info (GthEditCommentPage *base,
GFileInfo *info,
gboolean only_modified_fields)
{
GthEditGeneralPage *self;
GthFileData *file_data;
GtkTextBuffer *buffer;
GtkTextIter start;
GtkTextIter end;
char *text;
GthMetadata *metadata;
char *s;
self = GTH_EDIT_GENERAL_PAGE (base);
file_data = gth_file_data_new (NULL, self->priv->info);
/* caption */
if (! only_modified_fields || ! gth_file_data_attribute_equal (file_data, "general::title", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("title_entry"))))) {
metadata = g_object_new (GTH_TYPE_METADATA,
"id", "general::title",
"raw", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("title_entry"))),
"formatted", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("title_entry"))),
NULL);
g_file_info_set_attribute_object (info, "general::title", G_OBJECT (metadata));
g_object_unref (metadata);
}
/* comment */
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (GET_WIDGET ("note_text")));
gtk_text_buffer_get_bounds (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
if (! only_modified_fields || ! gth_file_data_attribute_equal (file_data, "general::description", text)) {
metadata = g_object_new (GTH_TYPE_METADATA,
"id", "general::description",
"raw", text,
"formatted", text,
NULL);
g_file_info_set_attribute_object (info, "general::description", G_OBJECT (metadata));
g_object_unref (metadata);
}
g_free (text);
/* location */
if (! only_modified_fields || ! gth_file_data_attribute_equal (file_data, "general::location", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("place_entry"))))) {
metadata = g_object_new (GTH_TYPE_METADATA,
"id", "general::location",
"raw", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("place_entry"))),
"formatted", gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("place_entry"))),
NULL);
g_file_info_set_attribute_object (info, "general::location", G_OBJECT (metadata));
g_object_unref (metadata);
}
/* date */
switch (gtk_combo_box_get_active (GTK_COMBO_BOX (self->priv->date_combobox))) {
case NO_CHANGE:
break;
case NO_DATE:
g_file_info_remove_attribute (info, "general::datetime");
break;
default:
{
char *exif_date;
if (gtk_combo_box_get_active (GTK_COMBO_BOX (self->priv->date_combobox)) == CURRENT_DATE)
exif_date = _g_time_val_to_exif_date (&self->priv->current_date);
else
exif_date = get_date_from_option (self, gtk_combo_box_get_active (GTK_COMBO_BOX (self->priv->date_combobox)), info);
if (! only_modified_fields
|| ! gth_file_data_attribute_equal (file_data, "general::datetime", exif_date))
{
metadata = g_object_new (GTH_TYPE_METADATA,
"id", "general::datetime",
"raw", exif_date,
"formatted", exif_date,
NULL);
g_file_info_set_attribute_object (info, "general::datetime", G_OBJECT (metadata));
g_object_unref (metadata);
}
g_free (exif_date);
break;
}
}
/* tags */
if (only_modified_fields) {
GList *checked_tags;
GList *inconsistent_tags;
GList *new_tags;
GHashTable *old_tags;
GList *scan_tags;
gth_tags_entry_get_tag_list (GTH_TAGS_ENTRY (self->priv->tags_entry),
TRUE,
&checked_tags,
&inconsistent_tags);
new_tags = _g_string_list_dup (checked_tags);
/* keep the inconsistent tags */
metadata = (GthMetadata *) g_file_info_get_attribute_object (info, "general::tags");
old_tags = _g_hash_table_from_string_list (gth_metadata_get_string_list (metadata));
for (scan_tags = inconsistent_tags; scan_tags; scan_tags = scan_tags->next) {
char *inconsistent_tag = scan_tags->data;
if (g_hash_table_lookup (old_tags, inconsistent_tag) != NULL)
new_tags = g_list_prepend (new_tags, g_strdup (inconsistent_tag));
}
g_hash_table_unref (old_tags);
/* update the general::tags attribute */
if (new_tags != NULL) {
GthStringList *file_tags;
GthMetadata *metadata;
new_tags = g_list_sort (new_tags, (GCompareFunc) g_strcmp0);
file_tags = gth_string_list_new (new_tags);
metadata = gth_metadata_new_for_string_list (file_tags);
g_file_info_set_attribute_object (info, "general::tags", G_OBJECT (metadata));
g_object_unref (metadata);
g_object_unref (file_tags);
_g_string_list_free (new_tags);
}
else
g_file_info_remove_attribute (info, "general::tags");
g_list_free (inconsistent_tags);
_g_string_list_free (checked_tags);
}
else {
char **tagv;
GList *tags;
int i;
GthStringList *string_list;
tagv = gth_tags_entry_get_tags (GTH_TAGS_ENTRY (self->priv->tags_entry), TRUE);
tags = NULL;
for (i = 0; tagv[i] != NULL; i++)
tags = g_list_prepend (tags, tagv[i]);
tags = g_list_reverse (tags);
if (tags != NULL)
string_list = gth_string_list_new (tags);
else
string_list = NULL;
if (string_list != NULL) {
metadata = gth_metadata_new_for_string_list (string_list);
g_file_info_set_attribute_object (info, "general::tags", G_OBJECT (metadata));
g_object_unref (metadata);
}
else
g_file_info_remove_attribute (info, "general::tags");
_g_object_unref (string_list);
g_list_free (tags);
g_strfreev (tagv);
}
/* rating */
s = g_strdup_printf ("%d", gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (GET_WIDGET ("rating_spinbutton"))));
if (! only_modified_fields || ! gth_file_data_attribute_equal_int (file_data, "general::rating", s)) {
if (gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (GET_WIDGET ("rating_spinbutton"))) > 0) {
metadata = g_object_new (GTH_TYPE_METADATA,
"id", "general::rating",
"raw", s,
"formatted", s,
NULL);
g_file_info_set_attribute_object (info, "general::rating", G_OBJECT (metadata));
g_object_unref (metadata);
}
else
g_file_info_remove_attribute (info, "general::rating");
}
g_free (s);
g_object_unref (file_data);
}
static const char *
gth_edit_general_page_real_get_name (GthEditCommentPage *self)
{
return _("General");
}
static void
gth_edit_general_page_finalize (GObject *object)
{
GthEditGeneralPage *self;
self = GTH_EDIT_GENERAL_PAGE (object);
_g_object_unref (self->priv->info);
g_object_unref (self->priv->builder);
G_OBJECT_CLASS (gth_edit_general_page_parent_class)->finalize (object);
}
static void
gth_edit_general_page_class_init (GthEditGeneralPageClass *klass)
{
G_OBJECT_CLASS (klass)->finalize = gth_edit_general_page_finalize;
}
static void
date_combobox_changed_cb (GtkComboBox *widget,
gpointer user_data)
{
GthEditGeneralPage *self = user_data;
char *value;
value = get_date_from_option (self, gtk_combo_box_get_active (widget), self->priv->info);
gth_time_selector_set_exif_date (GTH_TIME_SELECTOR (self->priv->date_selector), value);
gtk_widget_set_sensitive (self->priv->date_selector, ! g_str_equal (value, ""));
g_free (value);
}
static void
tags_entry_list_collapsed_cb (GthTagsEntry *widget,
gpointer user_data)
{
GtkWindow *toplevel;
int width;
/* collapse the dialog height */
toplevel = _gtk_widget_get_toplevel_if_window (GTK_WIDGET (widget));
if (toplevel == NULL)
return;
gtk_window_get_size (toplevel, &width, NULL);
gtk_window_resize (toplevel, width, 1);
}
static void
gth_edit_general_page_init (GthEditGeneralPage *self)
{
self->priv = gth_edit_general_page_get_instance_private (self);
self->priv->info = NULL;
gtk_container_set_border_width (GTK_CONTAINER (self), 12);
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
self->priv->builder = _gtk_builder_new_from_file ("edit-comment-page.ui", "edit_metadata");
gtk_box_pack_start (GTK_BOX (self), _gtk_builder_get_widget (self->priv->builder, "content"), TRUE, TRUE, 0);
self->priv->date_combobox = gtk_combo_box_text_new ();
_gtk_combo_box_append_texts (GTK_COMBO_BOX_TEXT (self->priv->date_combobox),
_("No date"),
_("The following date"),
_("Current date"),
_("Date photo was taken"),
_("Last modified date"),
_("File creation date"),
_("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, TRUE, TRUE, 0);
g_signal_connect (self->priv->date_combobox,
"changed",
G_CALLBACK (date_combobox_changed_cb),
self);
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);
gtk_label_set_mnemonic_widget (GTK_LABEL (GET_WIDGET ("date_label")), self->priv->date_combobox);
self->priv->tags_entry = gth_tags_entry_new (GTH_TAGS_ENTRY_MODE_POPUP);
gtk_widget_show (self->priv->tags_entry);
gtk_box_pack_start (GTK_BOX (GET_WIDGET ("tags_entry_container")), self->priv->tags_entry, TRUE, TRUE, 0);
gtk_label_set_mnemonic_widget (GTK_LABEL (GET_WIDGET ("tags_label")), self->priv->tags_entry);
g_signal_connect (self->priv->tags_entry,
"list-collapsed",
G_CALLBACK (tags_entry_list_collapsed_cb),
self);
}
static void
gth_edit_general_page_gth_edit_general_page_interface_init (GthEditCommentPageInterface *iface)
{
iface->set_file_list = gth_edit_general_page_real_set_file_list;
iface->update_info = gth_edit_general_page_real_update_info;
iface->get_name = gth_edit_general_page_real_get_name;
}