# HG changeset patch # User nadvornik # Date 1231676010 0 # Node ID 254b09942e68f075ba0852bfd405916704d37d20 # Parent 947e603a52c64ffe7f5c908fe33259ac8fa8b656 metadata write mode (direct or sidecar) made configurable for each file format diff -r 947e603a52c6 -r 254b09942e68 src/filedata.c --- a/src/filedata.c Sat Jan 10 20:40:37 2009 +0000 +++ b/src/filedata.c Sun Jan 11 12:13:30 2009 +0000 @@ -667,14 +667,12 @@ static gboolean file_data_can_write_directly(FileData *fd) { - return (filter_file_class(fd->extension, FORMAT_CLASS_IMAGE)); -/* FIXME: detect what exiv2 really supports */ + return filter_name_is_writable(fd->extension); } static gboolean file_data_can_write_sidecar(FileData *fd) { - return (filter_file_class(fd->extension, FORMAT_CLASS_RAWIMAGE)); -/* FIXME: detect what exiv2 really supports */ + return filter_name_allow_sidecar(fd->extension) && !filter_name_is_writable(fd->extension); } gchar *file_data_get_sidecar_path(FileData *fd, gboolean existing_only) diff -r 947e603a52c6 -r 254b09942e68 src/filefilter.c --- a/src/filefilter.c Sat Jan 10 20:40:37 2009 +0000 +++ b/src/filefilter.c Sun Jan 11 12:13:30 2009 +0000 @@ -32,6 +32,9 @@ static GList *file_class_extension_list[FILE_FORMAT_CLASSES]; +static GList *file_writable_list = NULL; /* writable files */ +static GList *file_sidecar_list = NULL; /* files with allowed sidecar */ + gint ishidden(const gchar *name) { @@ -41,7 +44,8 @@ } static FilterEntry *filter_entry_new(const gchar *key, const gchar *description, - const gchar *extensions, FileFormatClass file_class, gboolean enabled) + const gchar *extensions, FileFormatClass file_class, + gboolean writable, gboolean allow_sidecar, gboolean enabled) { FilterEntry *fe; @@ -51,6 +55,8 @@ fe->extensions = g_strdup(extensions); fe->enabled = enabled; fe->file_class = file_class; + fe->writable = writable; + fe->allow_sidecar = allow_sidecar; return fe; } @@ -101,12 +107,12 @@ return (filter_get_by_key(key) == NULL ? FALSE : TRUE); } -void filter_add(const gchar *key, const gchar *description, const gchar *extensions, FileFormatClass file_class, gint enabled) +void filter_add(const gchar *key, const gchar *description, const gchar *extensions, FileFormatClass file_class, gboolean writable, gboolean allow_sidecar, gint enabled) { - filter_list = g_list_append(filter_list, filter_entry_new(key, description, extensions, file_class, enabled)); + filter_list = g_list_append(filter_list, filter_entry_new(key, description, extensions, file_class, writable, allow_sidecar, enabled)); } -void filter_add_unique(const gchar *description, const gchar *extensions, FileFormatClass file_class, gint enabled) +void filter_add_unique(const gchar *description, const gchar *extensions, FileFormatClass file_class, gboolean writable, gboolean allow_sidecar, gint enabled) { gchar *key; guint n; @@ -121,11 +127,11 @@ n++; } - filter_add(key, description, extensions, file_class, enabled); + filter_add(key, description, extensions, file_class, writable, allow_sidecar, enabled); g_free(key); } -static void filter_add_if_missing(const gchar *key, const gchar *description, const gchar *extensions, FileFormatClass file_class, gint enabled) +static void filter_add_if_missing(const gchar *key, const gchar *description, const gchar *extensions, FileFormatClass file_class, gboolean writable, gboolean allow_sidecar, gint enabled) { GList *work; @@ -140,11 +146,17 @@ { if (fe->file_class == FORMAT_CLASS_UNKNOWN) fe->file_class = file_class; /* for compatibility */ + + if (fe->writable && fe->allow_sidecar) + { + fe->writable = writable; + fe->allow_sidecar = allow_sidecar; + } return; } } - filter_add(key, description, extensions, file_class, enabled); + filter_add(key, description, extensions, file_class, writable, allow_sidecar, enabled); } void filter_reset(void) @@ -203,7 +215,7 @@ DEBUG_1("loader reported [%s] [%s] [%s]", name, desc, filter->str); - filter_add_if_missing(name, desc, filter->str, FORMAT_CLASS_IMAGE, TRUE); + filter_add_if_missing(name, desc, filter->str, FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE); g_free(name); g_free(desc); @@ -213,40 +225,40 @@ g_slist_free(list); /* add defaults even if gdk-pixbuf does not have them, but disabled */ - filter_add_if_missing("jpeg", "JPEG group", ".jpg;.jpeg;.jpe", FORMAT_CLASS_IMAGE, FALSE); - filter_add_if_missing("png", "Portable Network Graphic", ".png", FORMAT_CLASS_IMAGE, FALSE); - filter_add_if_missing("tiff", "Tiff", ".tif;.tiff", FORMAT_CLASS_IMAGE, FALSE); - filter_add_if_missing("pnm", "Packed Pixel formats", ".pbm;.pgm;.pnm;.ppm", FORMAT_CLASS_IMAGE, FALSE); - filter_add_if_missing("gif", "Graphics Interchange Format", ".gif", FORMAT_CLASS_IMAGE, FALSE); - filter_add_if_missing("xbm", "X bitmap", ".xbm", FORMAT_CLASS_IMAGE, FALSE); - filter_add_if_missing("xpm", "X pixmap", ".xpm", FORMAT_CLASS_IMAGE, FALSE); - filter_add_if_missing("bmp", "Bitmap", ".bmp", FORMAT_CLASS_IMAGE, FALSE); - filter_add_if_missing("ico", "Icon file", ".ico;.cur", FORMAT_CLASS_IMAGE, FALSE); - filter_add_if_missing("ras", "Raster", ".ras", FORMAT_CLASS_IMAGE, FALSE); - filter_add_if_missing("svg", "Scalable Vector Graphics", ".svg", FORMAT_CLASS_IMAGE, FALSE); + filter_add_if_missing("jpeg", "JPEG group", ".jpg;.jpeg;.jpe", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); + filter_add_if_missing("png", "Portable Network Graphic", ".png", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); + filter_add_if_missing("tiff", "Tiff", ".tif;.tiff", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); + filter_add_if_missing("pnm", "Packed Pixel formats", ".pbm;.pgm;.pnm;.ppm", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); + filter_add_if_missing("gif", "Graphics Interchange Format", ".gif", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); + filter_add_if_missing("xbm", "X bitmap", ".xbm", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); + filter_add_if_missing("xpm", "X pixmap", ".xpm", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); + filter_add_if_missing("bmp", "Bitmap", ".bmp", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); + filter_add_if_missing("ico", "Icon file", ".ico;.cur", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); + filter_add_if_missing("ras", "Raster", ".ras", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); + filter_add_if_missing("svg", "Scalable Vector Graphics", ".svg", FORMAT_CLASS_IMAGE, TRUE, FALSE, FALSE); /* non-image files that might be desirable to show */ - filter_add_if_missing("xmp", "XMP sidecar", ".xmp", FORMAT_CLASS_META, TRUE); - filter_add_if_missing("gqv", GQ_APPNAME " image collection", GQ_COLLECTION_EXT, FORMAT_CLASS_META, TRUE); + filter_add_if_missing("xmp", "XMP sidecar", ".xmp", FORMAT_CLASS_META, TRUE, FALSE, TRUE); + filter_add_if_missing("gqv", GQ_APPNAME " image collection", GQ_COLLECTION_EXT, FORMAT_CLASS_META, FALSE, FALSE, TRUE); /* These are the raw camera formats with embedded jpeg/exif. * (see format_raw.c and/or exiv2.cc) */ - filter_add_if_missing("arw", "Sony raw format", ".arw;.srf;.sr2", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("crw", "Canon raw format", ".crw;.cr2", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("kdc", "Kodak raw format", ".kdc;.dcr;.k25", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("raf", "Fujifilm raw format", ".raf", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("mef", "Mamiya raw format", ".mef;.mos", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("mrw", "Minolta raw format", ".mrw", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("nef", "Nikon raw format", ".nef", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("orf", "Olympus raw format", ".orf", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("pef", "Pentax or Samsung raw format", ".pef;.ptx", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("dng", "Adobe Digital Negative raw format", ".dng", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("x3f", "Sigma raw format", ".x3f", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("raw", "Panasonic raw format", ".raw", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("r3d", "Red raw format", ".r3d", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("3fr", "Hasselblad raw format", ".3fr", FORMAT_CLASS_RAWIMAGE, TRUE); - filter_add_if_missing("erf", "Epson raw format", ".erf", FORMAT_CLASS_RAWIMAGE, TRUE); + filter_add_if_missing("arw", "Sony raw format", ".arw;.srf;.sr2", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("crw", "Canon raw format", ".crw;.cr2", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("kdc", "Kodak raw format", ".kdc;.dcr;.k25", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("raf", "Fujifilm raw format", ".raf", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("mef", "Mamiya raw format", ".mef;.mos", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("mrw", "Minolta raw format", ".mrw", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("nef", "Nikon raw format", ".nef", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("orf", "Olympus raw format", ".orf", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("pef", "Pentax or Samsung raw format", ".pef;.ptx", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("dng", "Adobe Digital Negative raw format", ".dng", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("x3f", "Sigma raw format", ".x3f", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("raw", "Panasonic raw format", ".raw", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("r3d", "Red raw format", ".r3d", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("3fr", "Hasselblad raw format", ".3fr", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); + filter_add_if_missing("erf", "Epson raw format", ".erf", FORMAT_CLASS_RAWIMAGE, FALSE, TRUE, TRUE); } GList *filter_to_list(const gchar *extensions) @@ -301,6 +313,12 @@ string_list_free(extension_list); extension_list = NULL; + string_list_free(file_writable_list); + file_writable_list = NULL; + + string_list_free(file_sidecar_list); + file_sidecar_list = NULL; + for (i = 0; i < FILE_FORMAT_CLASSES; i++) { string_list_free(file_class_extension_list[i]); @@ -331,21 +349,32 @@ { log_printf("WARNING: invalid file class %d\n", fe->file_class); } + + if (fe->writable) + { + ext = filter_to_list(fe->extensions); + if (ext) file_writable_list = g_list_concat(file_writable_list, ext); + } + + if (fe->allow_sidecar) + { + ext = filter_to_list(fe->extensions); + if (ext) file_sidecar_list = g_list_concat(file_sidecar_list, ext); + } + } } sidecar_ext_parse(options->sidecar.ext, FALSE); /* this must be updated after changed file extensions */ } -gint filter_name_exists(const gchar *name) +static gboolean filter_name_find(GList *filter, const gchar *name) { GList *work; guint ln; - if (!extension_list || options->file_filter.disable) return TRUE; - ln = strlen(name); - work = extension_list; + work = filter; while (work) { gchar *filter = work->data; @@ -362,33 +391,33 @@ return FALSE; } -gint filter_file_class(const gchar *name, FileFormatClass file_class) + +gboolean filter_name_exists(const gchar *name) { - GList *work; - guint ln; + if (!extension_list || options->file_filter.disable) return TRUE; + return filter_name_find(extension_list, name); +} + +gboolean filter_file_class(const gchar *name, FileFormatClass file_class) +{ if (file_class >= FILE_FORMAT_CLASSES) { log_printf("WARNING: invalid file class %d\n", file_class); return FALSE; } - ln = strlen(name); - work = file_class_extension_list[file_class]; - while (work) - { - gchar *filter = work->data; - guint lf = strlen(filter); + return filter_name_find(file_class_extension_list[file_class], name); +} - if (ln >= lf) - { - /* FIXME: utf8 */ - if (strncasecmp(name + ln - lf, filter, lf) == 0) return TRUE; - } - work = work->next; - } +gboolean filter_name_is_writable(const gchar *name) +{ + return filter_name_find(file_writable_list, name); +} - return FALSE; +gboolean filter_name_allow_sidecar(const gchar *name) +{ + return filter_name_find(file_sidecar_list, name); } void filter_write_list(SecureSaveInfo *ssi) @@ -404,9 +433,9 @@ gchar *extensions = escquote_value(fe->extensions); gchar *description = escquote_value(fe->description); - secure_fprintf(ssi, "file_filter.ext: \"%s%s\" %s %s %d\n", + secure_fprintf(ssi, "file_filter.ext: \"%s%s\" %s %s %d %d %d\n", (fe->enabled) ? "" : "#", - fe->key, extensions, description, fe->file_class); + fe->key, extensions, description, fe->file_class, fe->writable, fe->allow_sidecar); g_free(extensions); g_free(description); } @@ -419,7 +448,9 @@ gchar *ext; gchar *desc; gint enabled = TRUE; - guint file_class; + guint file_class = FORMAT_CLASS_UNKNOWN; + gboolean writable = TRUE; + gboolean allow_sidecar = TRUE; if (!text || text[0] != '"') return; @@ -429,7 +460,7 @@ ext = quoted_value(p, &p); desc = quoted_value(p, &p); - file_class = strtoul(p, NULL, 10); + sscanf(p, "%u %d %d", &file_class, &writable, &allow_sidecar); if (file_class >= FILE_FORMAT_CLASSES) file_class = FORMAT_CLASS_UNKNOWN; @@ -448,7 +479,7 @@ FilterEntry *fe = filter_get_by_key(key); if (fe != NULL) filter_remove_entry(fe); - filter_add(key, desc, ext, file_class, enabled); + filter_add(key, desc, ext, file_class, writable, allow_sidecar, enabled); } g_free(key); diff -r 947e603a52c6 -r 254b09942e68 src/filefilter.h --- a/src/filefilter.h Sat Jan 10 20:40:37 2009 +0000 +++ b/src/filefilter.h Sun Jan 11 12:13:30 2009 +0000 @@ -22,21 +22,25 @@ gchar *extensions; FileFormatClass file_class; gboolean enabled; + gboolean writable; + gboolean allow_sidecar; }; /* you can change, but not add or remove entries from the returned list */ GList *filter_get_list(void); void filter_remove_entry(FilterEntry *fe); -void filter_add(const gchar *key, const gchar *description, const gchar *extensions, FileFormatClass file_class, gint enabled); -void filter_add_unique(const gchar *description, const gchar *extensions, FileFormatClass file_class, gint enabled); +void filter_add(const gchar *key, const gchar *description, const gchar *extensions, FileFormatClass file_class, gboolean writable, gboolean allow_sidecar, gint enabled); +void filter_add_unique(const gchar *description, const gchar *extensions, FileFormatClass file_class, gboolean writable, gboolean allow_sidecar, gint enabled); void filter_add_defaults(void); void filter_reset(void); void filter_rebuild(void); GList *filter_to_list(const gchar *extensions); -gint filter_name_exists(const gchar *name); -gint filter_file_class(const gchar *name, FileFormatClass file_class); +gboolean filter_name_exists(const gchar *name); +gboolean filter_file_class(const gchar *name, FileFormatClass file_class); +gboolean filter_name_is_writable(const gchar *name); +gboolean filter_name_allow_sidecar(const gchar *name); void filter_write_list(SecureSaveInfo *ssi); void filter_parse(const gchar *text); diff -r 947e603a52c6 -r 254b09942e68 src/preferences.c --- a/src/preferences.c Sat Jan 10 20:40:37 2009 +0000 +++ b/src/preferences.c Sun Jan 11 12:13:30 2009 +0000 @@ -73,7 +73,9 @@ FE_ENABLE, FE_EXTENSION, FE_DESCRIPTION, - FE_CLASS + FE_CLASS, + FE_WRITABLE, + FE_ALLOW_SIDECAR }; @@ -737,6 +739,44 @@ filter_rebuild(); } +static void filter_store_writable_cb(GtkCellRendererToggle *renderer, + gchar *path_str, gpointer data) +{ + GtkWidget *model = data; + FilterEntry *fe; + GtkTreePath *tpath; + GtkTreeIter iter; + + tpath = gtk_tree_path_new_from_string(path_str); + gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath); + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1); + + fe->writable = !fe->writable; + if (fe->writable) fe->allow_sidecar = FALSE; + + gtk_tree_path_free(tpath); + filter_rebuild(); +} + +static void filter_store_sidecar_cb(GtkCellRendererToggle *renderer, + gchar *path_str, gpointer data) +{ + GtkWidget *model = data; + FilterEntry *fe; + GtkTreePath *tpath; + GtkTreeIter iter; + + tpath = gtk_tree_path_new_from_string(path_str); + gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, tpath); + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 0, &fe, -1); + + fe->allow_sidecar = !fe->allow_sidecar; + if (fe->allow_sidecar) fe->writable = FALSE; + + gtk_tree_path_free(tpath); + filter_rebuild(); +} + static void filter_set_func(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { @@ -762,12 +802,20 @@ g_object_set(GTK_CELL_RENDERER(cell), "text", _(format_class_list[fe->file_class]), NULL); break; + case FE_WRITABLE: + g_object_set(GTK_CELL_RENDERER(cell), + "active", fe->writable, NULL); + break; + case FE_ALLOW_SIDECAR: + g_object_set(GTK_CELL_RENDERER(cell), + "active", fe->allow_sidecar, NULL); + break; } } static void filter_add_cb(GtkWidget *widget, gpointer data) { - filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE); + filter_add_unique("description", ".new", FORMAT_CLASS_IMAGE, TRUE, FALSE, TRUE); filter_store_populate(); /* FIXME: implement the scroll to/select row stuff for tree view */ @@ -1296,6 +1344,27 @@ GINT_TO_POINTER(FE_CLASS), NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column); + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Writable")); + gtk_tree_view_column_set_resizable(column, FALSE); + renderer = gtk_cell_renderer_toggle_new(); + g_signal_connect(G_OBJECT(renderer), "toggled", + G_CALLBACK(filter_store_writable_cb), filter_store); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func, + GINT_TO_POINTER(FE_WRITABLE), NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column); + + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Sidecar is allowed")); + gtk_tree_view_column_set_resizable(column, FALSE); + renderer = gtk_cell_renderer_toggle_new(); + g_signal_connect(G_OBJECT(renderer), "toggled", + G_CALLBACK(filter_store_sidecar_cb), filter_store); + gtk_tree_view_column_pack_start(column, renderer, FALSE); + gtk_tree_view_column_set_cell_data_func(column, renderer, filter_set_func, + GINT_TO_POINTER(FE_ALLOW_SIDECAR), NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(filter_view), column); filter_store_populate();