changeset 1239:254b09942e68

metadata write mode (direct or sidecar) made configurable for each file format
author nadvornik
date Sun, 11 Jan 2009 12:13:30 +0000
parents 947e603a52c6
children 30e207ac22e4
files src/filedata.c src/filefilter.c src/filefilter.h src/preferences.c
diffstat 4 files changed, 174 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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);
--- 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);
--- 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();