commit 9c3b2fabe4e990c4d95d03eb77f6eb285376b7a6 Author: Omari Stephens Date: Sun Nov 15 00:57:03 2009 +0000 Add support for reading and writing Rating xmp metadata - Add a constant to metadata.h to reference the Xmp.xmp.Rating tag - Add a UI in the metadata bar - Add associated configuration stuff diff --git a/trunk/src/Makefile.am b/trunk/src/Makefile.am index 144b090..9528d30 100644 --- a/trunk/src/Makefile.am +++ b/trunk/src/Makefile.am @@ -94,6 +94,8 @@ geeqie_SOURCES = \ bar_keywords.h \ bar_exif.c \ bar_exif.h \ + bar_rating.c \ + bar_rating.h \ bar_sort.c \ bar_sort.h \ cache.c \ diff --git a/trunk/src/bar.c b/trunk/src/bar.c index 52d6a54..4d64b71 100644 --- a/trunk/src/bar.c +++ b/trunk/src/bar.c @@ -25,6 +25,7 @@ #include "ui_menu.h" #include "bar_comment.h" #include "bar_keywords.h" +#include "bar_rating.h" #include "bar_exif.h" #include "bar_histogram.h" #include "histogram.h" @@ -76,6 +77,15 @@ static const gchar default_config_comment[] = " " ""; +static const gchar default_config_rating[] = +"" +" " +" " +" " +" " +" " +""; + static const gchar default_config_exif[] = "" " " @@ -178,6 +188,7 @@ static const KnownPanes known_panes[] = { {PANE_GPS, "gps", N_("GPS Map"), default_config_gps}, #endif #endif + {PANE_RATING, "rating", N_("Rating"), default_config_rating}, {PANE_UNDEF, NULL, NULL, NULL} }; diff --git a/trunk/src/bar.h b/trunk/src/bar.h index 61dc4be..d24acf3 100644 --- a/trunk/src/bar.h +++ b/trunk/src/bar.h @@ -20,7 +20,8 @@ typedef enum { PANE_EXIF, PANE_HISTOGRAM, PANE_KEYWORDS, - PANE_GPS + PANE_GPS, + PANE_RATING } PaneType; typedef struct _PaneData PaneData; diff --git a/trunk/src/bar_rating.c b/trunk/src/bar_rating.c new file mode 100644 index 0000000..684e713 --- /dev/null +++ b/trunk/src/bar_rating.c @@ -0,0 +1,344 @@ +/* + * Geeqie + * (C) 2004 John Ellis + * Copyright (C) 2008 - 2009 The Geeqie Team + * + * Author: Omari Stephens + * + * This software is released under the GNU General Public License (GNU GPL). + * Please read the included file COPYING for more information. + * This software comes with no warranty of any kind, use at your own risk! + */ + + +#include "main.h" +#include "bar_rating.h" + +#include "bar.h" +#include "metadata.h" +#include "filedata.h" +#include "ui_menu.h" +#include "ui_misc.h" +#include "rcfile.h" +#include "layout.h" + +static void bar_pane_rating_changed(GtkSpinButton *button, gpointer data); + +/* + *------------------------------------------------------------------- + * rating utils + *------------------------------------------------------------------- + */ + + + +typedef struct _PaneRatingData PaneRatingData; +struct _PaneRatingData +{ + PaneData pane; + GtkWidget *widget; + GtkWidget *spinbutton; + FileData *fd; + gchar *key; + gint height; +}; + + +static void bar_pane_rating_write(PaneRatingData *prd) +{ + guint value; + + if (!prd->fd) return; + + value = gtk_spin_button_get_value_as_int(prd->spinbutton); + + metadata_write_int(prd->fd, prd->key, value); +} + + +static void bar_pane_rating_update(PaneRatingData *prd) +{ + guint value; + + g_signal_handlers_block_by_func(prd->spinbutton, bar_pane_rating_changed, prd); + + value = metadata_read_int(prd->fd, prd->key, (guint64)-1); + + if(value != (guint64)-1) + { + gtk_spin_button_set_value(prd->spinbutton, value); + } + + g_signal_handlers_unblock_by_func(prd->spinbutton, bar_pane_rating_changed, prd); + + gtk_widget_set_sensitive(prd->spinbutton, (prd->fd != NULL)); +} + +static void bar_pane_rating_set_selection(PaneRatingData *prd, gboolean overwrite) +{ + GList *list = NULL; + GList *work; + gint value = -1; + + value = gtk_spin_button_get_value_as_int(prd->spinbutton); + + list = layout_selection_list(prd->pane.lw); + list = file_data_process_groups_in_selection(list, FALSE, NULL); + + work = list; + while (work) + { + FileData *fd = work->data; + work = work->next; + if (fd == prd->fd) continue; + + if (overwrite || (metadata_read_int(fd, prd->key, -1) == (guint64)-1)) + { + metadata_write_int(fd, prd->key, value); + } + } + + filelist_free(list); +} + +/* +static void bar_pane_comment_sel_add_cb(GtkWidget *button, gpointer data) +{ + PaneCommentData *pcd = data; + + bar_pane_comment_set_selection(pcd, TRUE); +} + + +static void bar_pane_comment_sel_replace_cb(GtkWidget *button, gpointer data) +{ + PaneCommentData *pcd = data; + + bar_pane_comment_set_selection(pcd, FALSE); +} +*/ + +static void bar_pane_rating_set_fd(GtkWidget *bar, FileData *fd) +{ + PaneRatingData *prd; + + prd = g_object_get_data(G_OBJECT(bar), "pane_data"); + if (!prd) return; + + file_data_unref(prd->fd); + prd->fd = file_data_ref(fd); + + bar_pane_rating_update(prd); +} + +static gint bar_pane_rating_event(GtkWidget *bar, GdkEvent *event) +{ + PaneRatingData *prd; + + prd = g_object_get_data(G_OBJECT(bar), "pane_data"); + if (!prd) return FALSE; + + if (GTK_WIDGET_HAS_FOCUS(prd->spinbutton)) + { + return gtk_widget_event(prd->spinbutton, event); + } + + return FALSE; +} + +static void bar_pane_rating_write_config(GtkWidget *pane, GString *outstr, gint indent) +{ + PaneRatingData *prd; + + prd = g_object_get_data(G_OBJECT(pane), "pane_data"); + if (!prd) return; + + WRITE_NL(); WRITE_STRING("pane.id); + write_char_option(outstr, indent, "title", gtk_label_get_text(GTK_LABEL(prd->pane.title))); + WRITE_BOOL(prd->pane, expanded); + WRITE_CHAR(*prd, key); + WRITE_INT(*prd, height); + WRITE_STRING("/>"); +} + +static void bar_pane_rating_notify_cb(FileData *fd, NotifyType type, gpointer data) +{ + PaneRatingData *prd = data; + if ((type & (NOTIFY_REREAD | NOTIFY_CHANGE | NOTIFY_METADATA)) && fd == prd->fd) + { + DEBUG_1("Notify pane_rating: %s %04x", fd->path, type); + + bar_pane_rating_update(prd); + } +} + +static void bar_pane_rating_changed(GtkSpinButton *button, gpointer data) +{ + PaneRatingData *prd = data; + + file_data_unregister_notify_func(bar_pane_rating_notify_cb, prd); + bar_pane_rating_write(prd); + file_data_register_notify_func(bar_pane_rating_notify_cb, prd, NOTIFY_PRIORITY_LOW); +} + + +/* +static void bar_pane_comment_populate_popup(GtkTextView *textview, GtkMenu *menu, gpointer data) +{ + PaneCommentData *pcd = data; + + menu_item_add_divider(GTK_WIDGET(menu)); + menu_item_add_stock(GTK_WIDGET(menu), _("Add text to selected files"), GTK_STOCK_ADD, G_CALLBACK(bar_pane_comment_sel_add_cb), pcd); + menu_item_add_stock(GTK_WIDGET(menu), _("Replace existing text in selected files"), GTK_STOCK_CONVERT, G_CALLBACK(bar_pane_comment_sel_replace_cb), data); +} +*/ + +#if 0 +static void bar_pane_comment_close(GtkWidget *bar) +{ + PaneCommentData *pcd; + + pcd = g_object_get_data(G_OBJECT(bar), "pane_data"); + if (!pcd) return; + + gtk_widget_destroy(pcd->comment_view); +} +#endif + +static void bar_pane_rating_destroy(GtkWidget *widget, gpointer data) +{ + // FIXME: make sure we free the spinbutton + PaneRatingData *prd = data; + + file_data_unregister_notify_func(bar_pane_rating_notify_cb, prd); + + file_data_unref(prd->fd); + g_free(prd->key); + + g_free(prd->pane.id); + + g_free(prd); +} + + +static GtkWidget *bar_pane_rating_new(const gchar *id, const gchar *title, const gchar *key, + gboolean expanded, gint height) +{ + PaneRatingData *prd; + GtkWidget *hbox; + + prd = g_new0(PaneRatingData, 1); + + prd->pane.pane_set_fd = bar_pane_rating_set_fd; + prd->pane.pane_event = bar_pane_rating_event; + prd->pane.pane_write_config = bar_pane_rating_write_config; + prd->pane.title = bar_pane_expander_title(title); + prd->pane.id = g_strdup(id); + prd->pane.type = PANE_RATING; + + prd->pane.expanded = expanded; + + prd->key = g_strdup(key); + prd->height = height; + + // HBOX + hbox = gtk_hbox_new(FALSE, 0); + + prd->widget = hbox; + g_object_set_data(G_OBJECT(prd->widget), "pane_data", prd); + g_signal_connect(G_OBJECT(prd->widget), "destroy", + G_CALLBACK(bar_pane_rating_destroy), prd); + + gtk_widget_set_size_request(prd->widget, -1, height); + gtk_widget_show(hbox); + + // SPIN BUTTON + prd->spinbutton = gtk_spin_button_new_with_range(0.0, 5.0, 1.0); + gtk_spin_button_set_numeric(prd->spinbutton, TRUE); + gtk_spin_button_set_snap_to_ticks(prd->spinbutton, TRUE); + + gtk_box_pack_start(hbox, prd->spinbutton, TRUE, TRUE, 0); +// g_signal_connect(G_OBJECT(pcd->comment_view), "populate-popup", +// G_CALLBACK(bar_pane_comment_populate_popup), pcd); + gtk_widget_show(prd->spinbutton); + + g_signal_connect(G_OBJECT(prd->spinbutton), "value-changed", + G_CALLBACK(bar_pane_rating_changed), prd); + + + file_data_register_notify_func(bar_pane_rating_notify_cb, prd, NOTIFY_PRIORITY_LOW); + + return prd->widget; +} + +GtkWidget *bar_pane_rating_new_from_config(const gchar **attribute_names, + const gchar **attribute_values) +{ + gchar *title = NULL; + gchar *key = g_strdup(RATING_KEY); + gboolean expanded = TRUE; + gint height = 50; + gchar *id = g_strdup("rating"); + GtkWidget *ret; + + while (*attribute_names) + { + const gchar *option = *attribute_names++; + const gchar *value = *attribute_values++; + + if (READ_CHAR_FULL("title", title)) continue; + if (READ_CHAR_FULL("key", key)) continue; + if (READ_BOOL_FULL("expanded", expanded)) continue; + if (READ_INT_FULL("height", height)) continue; + if (READ_CHAR_FULL("id", id)) continue; + + + log_printf("unknown attribute %s = %s\n", option, value); + } + + bar_pane_translate_title(PANE_RATING, id, &title); + ret = bar_pane_rating_new(id, title, key, expanded, height); + g_free(title); + g_free(key); + g_free(id); + return ret; +} + +void bar_pane_rating_update_from_config(GtkWidget *pane, const gchar **attribute_names, + const gchar **attribute_values) +{ + PaneRatingData *prd; + + prd = g_object_get_data(G_OBJECT(pane), "pane_data"); + if (!prd) return; + + gchar *title = NULL; + + while (*attribute_names) + { + const gchar *option = *attribute_names++; + const gchar *value = *attribute_values++; + + if (READ_CHAR_FULL("title", title)) continue; + if (READ_CHAR_FULL("key", prd->key)) continue; + if (READ_BOOL_FULL("expanded", prd->pane.expanded)) continue; + if (READ_INT_FULL("height", prd->height)) continue; + if (READ_CHAR_FULL("id", prd->pane.id)) continue; + + + log_printf("unknown attribute %s = %s\n", option, value); + } + + if (title) + { + bar_pane_translate_title(PANE_RATING, prd->pane.id, &title); + gtk_label_set_text(GTK_LABEL(prd->pane.title), title); + g_free(title); + } + gtk_widget_set_size_request(prd->widget, -1, prd->height); + bar_update_expander(pane); + bar_pane_rating_update(prd); +} + +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/trunk/src/bar_rating.h b/trunk/src/bar_rating.h new file mode 100644 index 0000000..45302c5 --- /dev/null +++ b/trunk/src/bar_rating.h @@ -0,0 +1,23 @@ +/* + * Geeqie + * (C) 2004 John Ellis + * Copyright (C) 2008 - 2009 The Geeqie Team + * + * Author: Omari Stephens + * + * This software is released under the GNU General Public License (GNU GPL). + * Please read the included file COPYING for more information. + * This software comes with no warranty of any kind, use at your own risk! + */ + + +#ifndef BAR_RATING_H +#define BAR_RATING_H + +GtkWidget *bar_pane_rating_new_from_config(const gchar **attribute_names, + const gchar **attribute_values); +void bar_pane_rating_update_from_config(GtkWidget *pane, const gchar **attribute_names, + const gchar **attribute_values); + +#endif +/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */ diff --git a/trunk/src/metadata.h b/trunk/src/metadata.h index 639da6d..be265cc 100644 --- a/trunk/src/metadata.h +++ b/trunk/src/metadata.h @@ -17,6 +17,7 @@ #define COMMENT_KEY "Xmp.dc.description" #define KEYWORD_KEY "Xmp.dc.subject" #define ORIENTATION_KEY "Xmp.tiff.Orientation" +#define RATING_KEY "Xmp.xmp.Rating" gboolean metadata_write_queue_remove(FileData *fd); gboolean metadata_write_queue_remove_list(GList *list); diff --git a/trunk/src/rcfile.c b/trunk/src/rcfile.c index 4053b58..babd0a4 100644 --- a/trunk/src/rcfile.c +++ b/trunk/src/rcfile.c @@ -22,6 +22,7 @@ #include "bar_histogram.h" #include "bar_keywords.h" #include "bar_sort.h" +#include "bar_rating.h" #include "editors.h" #include "filefilter.h" #include "misc.h" @@ -918,6 +919,22 @@ static void options_parse_bar(GQParserData *parser_data, GMarkupParseContext *co } options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL); } + else if (g_ascii_strcasecmp(element_name, "pane_rating") == 0) + { + GtkWidget *pane = bar_find_pane_by_id(bar, PANE_RATING, + options_get_id(attribute_names, attribute_values)); + if (pane) + { + bar_pane_rating_update_from_config(pane, attribute_names, + attribute_values); + } + else + { + pane = bar_pane_rating_new_from_config(attribute_names, attribute_values); + bar_add(bar, pane); + } + options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL); + } #ifdef HAVE_LIBCHAMPLAIN #ifdef HAVE_LIBCHAMPLAIN_GTK else if (g_ascii_strcasecmp(element_name, "pane_gps") == 0)