diff --git a/ChangeLog b/ChangeLog index 973cd06b31..b0bd5c9780 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2002-04-29 Michael Natterer + + * app/core/gimpviewable.[ch]: added "gchar *name_changed_signal" + to GimpViewableClass which defaults to "name_changed". + + * app/widgets/gimplistitem.c + * app/widgets/gimpmenuitem.c: connect to + viewable_class->name_changed_signal instead of just + "name_changed". Fixed possible UI inconsistency where the previous + viewable's tooltip would have been displayed. + + * app/core/gimpimagefile.[ch]: set name_changed_signal to + "info_changed" so views can update their tooltips correctly. + Merged the separate image_state and thumb_state states into one + state variable and extended the state enum. Added description + strings for all states. Show the file size for all files, not only + for those with a thumbnail. Enabled display of outdated + thumbnails. + + * app/gui/file-open-dialog.c: some changes because + gimp_imagefile_get_description() returns 3 instead of 2 lines of + text now. + + * app/widgets/gimpcontainerview-utils.c: show the imagefile's + description in the tooltip. + + * app/gui/menus.c + * app/gui/documents-commands.[ch] + * app/widgets/gimpdocumentview.c: added functions to remove + "dangling" document history entries. Updated the context menu so + all functions can be accessed through it. + 2002-04-28 Sven Neumann * app/tools/gimpairbrushtool.c diff --git a/app/actions/documents-commands.c b/app/actions/documents-commands.c index ef64b877ea..1c038fd8d3 100644 --- a/app/actions/documents-commands.c +++ b/app/actions/documents-commands.c @@ -100,8 +100,8 @@ documents_delete_document_cmd_callback (GtkWidget *widget, void -documents_refresh_documents_cmd_callback (GtkWidget *widget, - gpointer data) +documents_recreate_preview_cmd_callback (GtkWidget *widget, + gpointer data) { GimpDocumentView *view; @@ -113,6 +113,36 @@ documents_refresh_documents_cmd_callback (GtkWidget *widget, gtk_button_clicked (GTK_BUTTON (view->refresh_button)); } +void +documents_reload_previews_cmd_callback (GtkWidget *widget, + gpointer data) +{ + GimpDocumentView *view; + + view = (GimpDocumentView *) gimp_widget_get_callback_context (widget); + + if (! view) + return; + + gimp_button_extended_clicked (GIMP_BUTTON (view->refresh_button), + GDK_SHIFT_MASK); +} + +void +documents_delete_dangling_documents_cmd_callback (GtkWidget *widget, + gpointer data) +{ + GimpDocumentView *view; + + view = (GimpDocumentView *) gimp_widget_get_callback_context (widget); + + if (! view) + return; + + gimp_button_extended_clicked (GIMP_BUTTON (view->refresh_button), + GDK_CONTROL_MASK); +} + void documents_menu_update (GtkItemFactory *factory, gpointer data) @@ -127,11 +157,13 @@ documents_menu_update (GtkItemFactory *factory, #define SET_SENSITIVE(menu,condition) \ gimp_item_factory_set_sensitive (factory, menu, (condition) != 0) - SET_SENSITIVE ("/Open Image", imagefile); - SET_SENSITIVE ("/Raise or Open Image", imagefile); - SET_SENSITIVE ("/File Open Dialog...", TRUE); - SET_SENSITIVE ("/Remove Entry", imagefile); - SET_SENSITIVE ("/Refresh History", TRUE); + SET_SENSITIVE ("/Open Image", imagefile); + SET_SENSITIVE ("/Raise or Open Image", imagefile); + SET_SENSITIVE ("/File Open Dialog...", TRUE); + SET_SENSITIVE ("/Remove Entry", imagefile); + SET_SENSITIVE ("/Recreate Preview", imagefile); + SET_SENSITIVE ("/Reload all Previews", imagefile); + SET_SENSITIVE ("/Remove Dangling Entries", imagefile); #undef SET_SENSITIVE } diff --git a/app/actions/documents-commands.h b/app/actions/documents-commands.h index f226e55398..d7f4c7124c 100644 --- a/app/actions/documents-commands.h +++ b/app/actions/documents-commands.h @@ -20,19 +20,23 @@ #define __DOCUMENTS_COMMANDS_H__ -void documents_open_document_cmd_callback (GtkWidget *widget, - gpointer data); -void documents_raise_or_open_document_cmd_callback (GtkWidget *widget, - gpointer data); -void documents_file_open_dialog_cmd_callback (GtkWidget *widget, - gpointer data); -void documents_delete_document_cmd_callback (GtkWidget *widget, - gpointer data); -void documents_refresh_documents_cmd_callback (GtkWidget *widget, - gpointer data); +void documents_open_document_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_raise_or_open_document_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_file_open_dialog_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_delete_document_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_recreate_preview_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_reload_previews_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_delete_dangling_documents_cmd_callback (GtkWidget *widget, + gpointer data); -void documents_menu_update (GtkItemFactory *factory, - gpointer data); +void documents_menu_update (GtkItemFactory *factory, + gpointer data); #endif /* __DOCUMENTS_COMMANDS_H__ */ diff --git a/app/core/gimpimagefile.c b/app/core/gimpimagefile.c index ad174dfe8d..1b6e35cf43 100644 --- a/app/core/gimpimagefile.c +++ b/app/core/gimpimagefile.c @@ -21,6 +21,7 @@ #include "config.h" +#include #include #include #include @@ -89,7 +90,6 @@ static void gimp_imagefile_set_info (GimpImagefile *imagefile, gboolean emit_always, gint width, gint height, - gint size, GimpImageType type, gint n_layers); static TempBuf * gimp_imagefile_get_new_preview (GimpViewable *viewable, @@ -189,9 +189,12 @@ gimp_imagefile_class_init (GimpImagefileClass *klass) gimp_marshal_VOID__VOID, G_TYPE_NONE, 0); - object_class->finalize = gimp_imagefile_finalize; - gimp_object_class->name_changed = gimp_imagefile_name_changed; - viewable_class->get_new_preview = gimp_imagefile_get_new_preview; + object_class->finalize = gimp_imagefile_finalize; + + gimp_object_class->name_changed = gimp_imagefile_name_changed; + + viewable_class->name_changed_signal = "info_changed"; + viewable_class->get_new_preview = gimp_imagefile_get_new_preview; g_type_class_ref (GIMP_TYPE_IMAGE_TYPE); @@ -205,16 +208,17 @@ gimp_imagefile_class_init (GimpImagefileClass *klass) static void gimp_imagefile_init (GimpImagefile *imagefile) { + imagefile->state = GIMP_IMAGEFILE_STATE_UNKNOWN; + imagefile->image_mtime = 0; + imagefile->image_size = -1; + imagefile->thumb_mtime = 0; + imagefile->width = -1; imagefile->height = -1; - imagefile->size = -1; imagefile->type = -1; imagefile->n_layers = -1; + imagefile->description = NULL; - imagefile->image_state = GIMP_IMAGEFILE_STATE_UNKNOWN; - imagefile->image_mtime = 0; - imagefile->thumb_state = GIMP_IMAGEFILE_STATE_UNKNOWN; - imagefile->thumb_mtime = 0; } static void @@ -252,32 +256,41 @@ gimp_imagefile_update (GimpImagefile *imagefile) if (uri) { - gchar *filename = NULL; - gchar *thumbname = NULL; - gint thumb_size = GIMP_IMAGEFILE_THUMB_SIZE_FAIL; + GimpImagefileState old_state; + gchar *filename = NULL; + gchar *thumbname = NULL; + gint thumb_size = GIMP_IMAGEFILE_THUMB_SIZE_FAIL; + off_t image_size; + + old_state = imagefile->state; filename = g_filename_from_uri (uri, NULL, NULL); imagefile->image_mtime = 0; + imagefile->image_size = -1; if (! filename) { /* no thumbnails of remote images :-( */ - imagefile->image_state = GIMP_IMAGEFILE_STATE_REMOTE; + imagefile->state = GIMP_IMAGEFILE_STATE_REMOTE; goto cleanup; } - if (! gimp_imagefile_test (filename, &imagefile->image_mtime, NULL)) + if (! gimp_imagefile_test (filename, + &imagefile->image_mtime, + &image_size)) { - imagefile->image_state = GIMP_IMAGEFILE_STATE_NOT_FOUND; + imagefile->state = GIMP_IMAGEFILE_STATE_NOT_FOUND; goto cleanup; } - imagefile->image_state = GIMP_IMAGEFILE_STATE_EXISTS; + imagefile->state = GIMP_IMAGEFILE_STATE_EXISTS; + imagefile->image_size = image_size; /* found the image, now look for the thumbnail */ + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_NOT_FOUND; imagefile->thumb_mtime = 0; thumbname = @@ -288,16 +301,19 @@ gimp_imagefile_update (GimpImagefile *imagefile) &thumb_size); if (! thumbname) - { - imagefile->thumb_state = GIMP_IMAGEFILE_STATE_NOT_FOUND; - goto cleanup; - } + goto cleanup; - imagefile->thumb_state = GIMP_IMAGEFILE_STATE_EXISTS; + if (imagefile->image_mtime >= imagefile->thumb_mtime) + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_OK; + else + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_OLD; cleanup: g_free (filename); g_free (thumbname); + + if (imagefile->state != old_state) + gimp_imagefile_set_info (imagefile, TRUE, -1, -1, -1, -1); } gimp_viewable_invalidate_preview (GIMP_VIEWABLE (imagefile)); @@ -328,12 +344,12 @@ gimp_imagefile_create_thumbnail (GimpImagefile *imagefile) if (uri) { - GimpImage *gimage = NULL; - GimpPDBStatusType dummy; - gchar *filename; - gchar *thumb_name; + gchar *filename = NULL; + gchar *thumb_name = NULL; time_t image_mtime; off_t image_size; + GimpImage *gimage; + GimpPDBStatusType dummy; filename = g_filename_from_uri (uri, NULL, NULL); @@ -346,20 +362,18 @@ gimp_imagefile_create_thumbnail (GimpImagefile *imagefile) /* the thumbnail directory doesn't exist and couldn't be created */ if (! thumb_name) - return; + goto cleanup; - if (gimp_imagefile_test (filename, &image_mtime, &image_size)) - { - gimage = file_open_image (the_gimp, - uri, - uri, - NULL, - GIMP_RUN_NONINTERACTIVE, - &dummy, - NULL); - } + if (! gimp_imagefile_test (filename, &image_mtime, &image_size)) + goto cleanup; - g_free (filename); + gimage = file_open_image (the_gimp, + uri, + uri, + NULL, + GIMP_RUN_NONINTERACTIVE, + &dummy, + NULL); if (gimage) { @@ -371,7 +385,15 @@ gimp_imagefile_create_thumbnail (GimpImagefile *imagefile) g_object_unref (G_OBJECT (gimage)); } + else + { + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_FAILED; + gimp_imagefile_set_info (imagefile, TRUE, -1, -1, -1, -1); + } + + cleanup: + g_free (filename); g_free (thumb_name); } } @@ -433,13 +455,12 @@ gimp_imagefile_name_changed (GimpObject *object) if (GIMP_OBJECT_CLASS (parent_class)->name_changed) GIMP_OBJECT_CLASS (parent_class)->name_changed (object); - imagefile->image_state = GIMP_IMAGEFILE_STATE_UNKNOWN; + imagefile->state = GIMP_IMAGEFILE_STATE_UNKNOWN; imagefile->image_mtime = 0; - - imagefile->thumb_state = GIMP_IMAGEFILE_STATE_UNKNOWN; + imagefile->image_size = -1; imagefile->thumb_mtime = 0; - gimp_imagefile_set_info (imagefile, TRUE, -1, -1, -1, -1, -1); + gimp_imagefile_set_info (imagefile, TRUE, -1, -1, -1, -1); } static void @@ -447,7 +468,6 @@ gimp_imagefile_set_info (GimpImagefile *imagefile, gboolean emit_always, gint width, gint height, - gint size, GimpImageType type, gint n_layers) { @@ -455,13 +475,11 @@ gimp_imagefile_set_info (GimpImagefile *imagefile, changed = (imagefile->width != width || imagefile->height != height || - imagefile->size != size || imagefile->type != type || imagefile->n_layers != n_layers); imagefile->width = width; imagefile->height = height; - imagefile->size = size; imagefile->type = type; imagefile->n_layers = n_layers; @@ -479,12 +497,12 @@ gimp_imagefile_set_info (GimpImagefile *imagefile, static void gimp_imagefile_set_info_from_pixbuf (GimpImagefile *imagefile, + gboolean emit_always, GdkPixbuf *pixbuf) { const gchar *option; gint img_width = -1; gint img_height = -1; - gint img_size = -1; GimpImageType img_type = -1; gint img_layers = -1; @@ -495,10 +513,6 @@ gimp_imagefile_set_info_from_pixbuf (GimpImagefile *imagefile, option = gdk_pixbuf_get_option (pixbuf, TAG_THUMB_IMAGE_HEIGHT); if (!option || sscanf (option, "%d", &img_height) != 1) img_height = -1; - - option = gdk_pixbuf_get_option (pixbuf, TAG_THUMB_SIZE); - if (!option || sscanf (option, "%d", &img_size) != 1) - img_size = -1; option = gdk_pixbuf_get_option (pixbuf, TAG_THUMB_GIMP_TYPE); if (option) @@ -515,10 +529,10 @@ gimp_imagefile_set_info_from_pixbuf (GimpImagefile *imagefile, option = gdk_pixbuf_get_option (pixbuf, TAG_THUMB_GIMP_LAYERS); if (!option || sscanf (option, "%d", &img_layers) != 1) - img_size = -1; + img_layers = -1; - gimp_imagefile_set_info (imagefile, FALSE, - img_width, img_height, img_size, + gimp_imagefile_set_info (imagefile, emit_always, + img_width, img_height, img_type, img_layers); } @@ -551,88 +565,112 @@ gimp_imagefile_get_description (GimpImagefile *imagefile) if (imagefile->description) return (const gchar *) imagefile->description; - switch (imagefile->thumb_state) + switch (imagefile->state) { case GIMP_IMAGEFILE_STATE_UNKNOWN: - case GIMP_IMAGEFILE_STATE_REMOTE: - case GIMP_IMAGEFILE_STATE_NOT_FOUND: - imagefile->description = _("No preview available"); + imagefile->description = NULL; imagefile->static_desc = TRUE; break; - case GIMP_IMAGEFILE_STATE_EXISTS: - if (imagefile->image_mtime > imagefile->thumb_mtime) - { - imagefile->description = _("Thumbnail is out of date"); - imagefile->static_desc = TRUE; - } - else - { - GString *str; - GEnumClass *enum_class; - GEnumValue *enum_value; + case GIMP_IMAGEFILE_STATE_REMOTE: + imagefile->description = _("Remote image"); + imagefile->static_desc = TRUE; + break; - str = g_string_new (NULL); - - if (imagefile->width > -1 && imagefile->height > -1) - { - /* image size */ - g_string_append_printf (str, _("%d x %d"), - imagefile->width, imagefile->height); - } - - enum_class = g_type_class_peek (GIMP_TYPE_IMAGE_TYPE); - enum_value = g_enum_get_value (enum_class, imagefile->type); - - if (enum_value) - { - if (str->len) - g_string_append_len (str, ", ", 2); - - g_string_append (str, gettext (enum_value->value_name)); - } - - if (imagefile->size > -1) - { - gchar *size; - - size = gimp_image_new_get_memsize_string (imagefile->size); - - if (str->len) - g_string_append_len (str, "\n", 1); - - g_string_append (str, size); - g_free (size); - } - - if (imagefile->n_layers > -1) - { - gchar *n_layers; - - if (imagefile->n_layers == 1) - n_layers = g_strdup_printf (_("%d Layer"), imagefile->n_layers); - else - n_layers = g_strdup_printf (_("%d Layers"), imagefile->n_layers); - - if (str->len) - { - if (imagefile->size > -1) - g_string_append_len (str, ", ", 2); - else - g_string_append_len (str, "\n", 1); - } - - g_string_append (str, n_layers); - g_free (n_layers); - } - - imagefile->static_desc = FALSE; - imagefile->description = g_string_free (str, FALSE); - } + case GIMP_IMAGEFILE_STATE_NOT_FOUND: + imagefile->description = _("Could not open image"); + imagefile->static_desc = TRUE; break; default: - break; + { + GString *str; + + str = g_string_new (NULL); + + if (imagefile->image_size > -1) + { + gchar *size; + + size = gimp_image_new_get_memsize_string (imagefile->image_size); + + g_string_append (str, size); + g_free (size); + } + + switch (imagefile->state) + { + case GIMP_IMAGEFILE_STATE_THUMBNAIL_NOT_FOUND: + g_string_append_printf (str, "\n%s", _("No preview available")); + break; + + case GIMP_IMAGEFILE_STATE_THUMBNAIL_OLD: + g_string_append_printf (str, "\n%s", _("Preview is out of date")); + break; + + case GIMP_IMAGEFILE_STATE_THUMBNAIL_FAILED: + g_string_append_printf (str, "\n%s", _("Failed to create preview")); + break; + + case GIMP_IMAGEFILE_STATE_THUMBNAIL_OK: + g_string_append_len (str, "\n", 1); + + if (imagefile->image_mtime > imagefile->thumb_mtime) + { + g_string_append (str, _("Thumbnail is out of date")); + } + else + { + GEnumClass *enum_class; + GEnumValue *enum_value; + + if (imagefile->width > -1 && imagefile->height > -1) + { + /* image size */ + g_string_append_printf (str, _("%d x %d Pixel"), + imagefile->width, imagefile->height); + } + + enum_class = g_type_class_peek (GIMP_TYPE_IMAGE_TYPE); + enum_value = g_enum_get_value (enum_class, imagefile->type); + + if (enum_value) + { + if (str->len) + g_string_append (str, "\n"); + + g_string_append (str, gettext (enum_value->value_name)); + } + + if (imagefile->n_layers > -1) + { + gchar *n_layers; + + if (imagefile->n_layers == 1) + n_layers = g_strdup_printf (_("%d Layer"), + imagefile->n_layers); + else + n_layers = g_strdup_printf (_("%d Layers"), + imagefile->n_layers); + + if (enum_value) + g_string_append (str, ", "); + else + g_string_append (str, "\n"); + + g_string_append (str, n_layers); + g_free (n_layers); + } + } + break; + + default: + break; + } + + imagefile->static_desc = FALSE; + imagefile->description = g_string_free (str, FALSE); + } } return (const gchar *) imagefile->description; @@ -667,24 +705,29 @@ static TempBuf * gimp_imagefile_read_png_thumb (GimpImagefile *imagefile, gint size) { - TempBuf *temp_buf = NULL; - GdkPixbuf *pixbuf = NULL; - gchar *thumbname = NULL; - gint thumb_size = GIMP_IMAGEFILE_THUMB_SIZE_FAIL; - const gchar *option; - gint width; - gint height; - gint bytes; - time_t y; - guchar *src; - guchar *dest; - GError *error = NULL; + GimpImagefileState old_state; + TempBuf *temp_buf = NULL; + GdkPixbuf *pixbuf = NULL; + gchar *thumbname = NULL; + gint thumb_size = GIMP_IMAGEFILE_THUMB_SIZE_FAIL; + const gchar *option; + gint width; + gint height; + gint bytes; + time_t thumb_image_mtime; + off_t thumb_image_size; + guchar *src; + guchar *dest; + gint y; + GError *error = NULL; - if (imagefile->image_state != GIMP_IMAGEFILE_STATE_EXISTS) + if (imagefile->state < GIMP_IMAGEFILE_STATE_EXISTS) return NULL; + old_state = imagefile->state; + /* try to locate a thumbnail for this image */ - imagefile->thumb_state = GIMP_IMAGEFILE_STATE_NOT_FOUND; + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_NOT_FOUND; imagefile->thumb_mtime = 0; thumbname = gimp_imagefile_find_png_thumb (GIMP_OBJECT (imagefile)->name, @@ -695,17 +738,22 @@ gimp_imagefile_read_png_thumb (GimpImagefile *imagefile, if (!thumbname) goto cleanup; - imagefile->thumb_state = GIMP_IMAGEFILE_STATE_EXISTS; + if (imagefile->image_mtime >= imagefile->thumb_mtime) + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_OK; + else + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_OLD; - pixbuf = gdk_pixbuf_new_from_file (thumbname, &error); + pixbuf = gdk_pixbuf_new_from_file (thumbname, &error); if (!pixbuf) { g_message (_("Could not open thumbnail\nfile '%s':\n%s"), thumbname, error->message); + + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_NOT_FOUND; goto cleanup; } - + g_free (thumbname); thumbname = NULL; @@ -716,9 +764,19 @@ gimp_imagefile_read_png_thumb (GimpImagefile *imagefile, goto cleanup; option = gdk_pixbuf_get_option (pixbuf, TAG_THUMB_MTIME); - if (!option || sscanf (option, "%ld", &y) != 1 || y != imagefile->image_mtime) + if (!option || sscanf (option, "%ld", &thumb_image_mtime) != 1) goto cleanup; + option = gdk_pixbuf_get_option (pixbuf, TAG_THUMB_SIZE); + if (!option || sscanf (option, "%ld", &thumb_image_size) != 1) + goto cleanup; + + if (thumb_image_mtime != imagefile->image_mtime || + thumb_image_size != imagefile->image_size) + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_OLD; + else + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_OK; + /* now convert the pixbuf to a tempbuf */ width = gdk_pixbuf_get_width (pixbuf); @@ -738,12 +796,14 @@ gimp_imagefile_read_png_thumb (GimpImagefile *imagefile, } /* extract into about the original file from the pixbuf */ - gimp_imagefile_set_info_from_pixbuf (imagefile, pixbuf); + gimp_imagefile_set_info_from_pixbuf (imagefile, + imagefile->state != old_state, + pixbuf); cleanup: g_free (thumbname); if (pixbuf) - g_object_unref (pixbuf); + g_object_unref (pixbuf); if (error) g_error_free (error); @@ -833,6 +893,11 @@ gimp_imagefile_save_png_thumb (GimpImagefile *imagefile, uri, thumb_name, error->message); g_error_free (error); } + else if (chmod (thumb_name, 0600)) + { + g_message (_("Couldn't set permissions of thumbnail '%s'.\n%s"), + thumb_name, g_strerror (errno)); + } g_free (desc); g_free (t_str); @@ -840,6 +905,7 @@ gimp_imagefile_save_png_thumb (GimpImagefile *imagefile, g_free (h_str); g_free (s_str); g_free (l_str); + } g_object_unref (G_OBJECT (pixbuf)); @@ -883,6 +949,12 @@ gimp_imagefile_png_thumb_path (const gchar *uri, gchar *thumb_name = NULL; gint i, n; + if (strstr (uri, "/.thumbnails/")) + { + g_message (_("Cannot create thumbnail of thumbnail\n%s"), uri); + return NULL; + } + name = gimp_imagefile_png_thumb_name (uri); n = G_N_ELEMENTS (thumb_sizes); @@ -935,8 +1007,7 @@ gimp_imagefile_find_png_thumb (const gchar *uri, { thumb_name = g_build_filename (thumb_subdirs[i], name, NULL); - if (gimp_imagefile_test (thumb_name, thumb_mtime, NULL) && - image_mtime <= *thumb_mtime) + if (gimp_imagefile_test (thumb_name, thumb_mtime, NULL)) { *thumb_size = thumb_sizes[i].size; return thumb_name; @@ -949,8 +1020,7 @@ gimp_imagefile_find_png_thumb (const gchar *uri, { thumb_name = g_build_filename (thumb_subdirs[i], name, NULL); - if (gimp_imagefile_test (thumb_name, thumb_mtime, NULL) && - image_mtime <= *thumb_mtime) + if (gimp_imagefile_test (thumb_name, thumb_mtime, NULL)) { *thumb_size = thumb_sizes[i].size; return thumb_name; @@ -1016,6 +1086,8 @@ gimp_imagefile_read_xv_thumb (GimpImagefile *imagefile) if (!raw_thumb) return NULL; + imagefile->state = GIMP_IMAGEFILE_STATE_THUMBNAIL_OLD; + if (image_info) { gint img_width; @@ -1027,7 +1099,7 @@ gimp_imagefile_read_xv_thumb (GimpImagefile *imagefile) img_height = 0; } gimp_imagefile_set_info (imagefile, FALSE, - img_width, img_height, -1, -1, -1); + img_width, img_height, -1, -1); g_free (image_info); } diff --git a/app/core/gimpimagefile.h b/app/core/gimpimagefile.h index e35d6d0241..47c73acc9b 100644 --- a/app/core/gimpimagefile.h +++ b/app/core/gimpimagefile.h @@ -36,7 +36,11 @@ typedef enum GIMP_IMAGEFILE_STATE_UNKNOWN, GIMP_IMAGEFILE_STATE_REMOTE, GIMP_IMAGEFILE_STATE_NOT_FOUND, - GIMP_IMAGEFILE_STATE_EXISTS + GIMP_IMAGEFILE_STATE_EXISTS, + GIMP_IMAGEFILE_STATE_THUMBNAIL_NOT_FOUND, + GIMP_IMAGEFILE_STATE_THUMBNAIL_OLD, + GIMP_IMAGEFILE_STATE_THUMBNAIL_FAILED, + GIMP_IMAGEFILE_STATE_THUMBNAIL_OK } GimpImagefileState; @@ -54,18 +58,17 @@ struct _GimpImagefile { GimpViewable parent_instance; + GimpImagefileState state; + + time_t image_mtime; + gssize image_size; + time_t thumb_mtime; + gint width; gint height; - gssize size; GimpImageType type; gint n_layers; - GimpImagefileState image_state; - time_t image_mtime; - - GimpImagefileState thumb_state; - time_t thumb_mtime; - gchar *description; gboolean static_desc; }; diff --git a/app/core/gimpviewable.c b/app/core/gimpviewable.c index f08f4d47d1..f982559c93 100644 --- a/app/core/gimpviewable.c +++ b/app/core/gimpviewable.c @@ -109,6 +109,8 @@ gimp_viewable_class_init (GimpViewableClass *klass) gimp_object_class->get_memsize = gimp_viewable_get_memsize; + klass->name_changed_signal = "name_changed"; + klass->invalidate_preview = gimp_viewable_real_invalidate_preview; klass->size_changed = NULL; diff --git a/app/core/gimpviewable.h b/app/core/gimpviewable.h index 5ec3f26cbd..097b0e734f 100644 --- a/app/core/gimpviewable.h +++ b/app/core/gimpviewable.h @@ -47,6 +47,8 @@ struct _GimpViewableClass { GimpObjectClass parent_class; + const gchar *name_changed_signal; + /* signals */ void (* invalidate_preview) (GimpViewable *viewable); void (* size_changed) (GimpViewable *viewable); diff --git a/app/dialogs/file-open-dialog.c b/app/dialogs/file-open-dialog.c index 1b64d54590..26e2ac2d86 100644 --- a/app/dialogs/file-open-dialog.c +++ b/app/dialogs/file-open-dialog.c @@ -296,11 +296,20 @@ file_open_dialog_create (Gimp *gimp) gtk_box_pack_start (GTK_BOX (vbox2), open_options_title, FALSE, FALSE, 0); gtk_widget_show (open_options_title); - label = gtk_label_new (" \n "); + label = gtk_label_new (" \n \n "); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.0); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER); gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); gtk_widget_show (label); + /* eek */ + { + GtkRequisition requisition; + + gtk_widget_size_request (label, &requisition); + gtk_widget_set_size_request (label, -1, requisition.height); + } + g_signal_connect (G_OBJECT (open_options_imagefile), "info_changed", G_CALLBACK (file_open_imagefile_info_changed), label); diff --git a/app/gui/documents-commands.c b/app/gui/documents-commands.c index ef64b877ea..1c038fd8d3 100644 --- a/app/gui/documents-commands.c +++ b/app/gui/documents-commands.c @@ -100,8 +100,8 @@ documents_delete_document_cmd_callback (GtkWidget *widget, void -documents_refresh_documents_cmd_callback (GtkWidget *widget, - gpointer data) +documents_recreate_preview_cmd_callback (GtkWidget *widget, + gpointer data) { GimpDocumentView *view; @@ -113,6 +113,36 @@ documents_refresh_documents_cmd_callback (GtkWidget *widget, gtk_button_clicked (GTK_BUTTON (view->refresh_button)); } +void +documents_reload_previews_cmd_callback (GtkWidget *widget, + gpointer data) +{ + GimpDocumentView *view; + + view = (GimpDocumentView *) gimp_widget_get_callback_context (widget); + + if (! view) + return; + + gimp_button_extended_clicked (GIMP_BUTTON (view->refresh_button), + GDK_SHIFT_MASK); +} + +void +documents_delete_dangling_documents_cmd_callback (GtkWidget *widget, + gpointer data) +{ + GimpDocumentView *view; + + view = (GimpDocumentView *) gimp_widget_get_callback_context (widget); + + if (! view) + return; + + gimp_button_extended_clicked (GIMP_BUTTON (view->refresh_button), + GDK_CONTROL_MASK); +} + void documents_menu_update (GtkItemFactory *factory, gpointer data) @@ -127,11 +157,13 @@ documents_menu_update (GtkItemFactory *factory, #define SET_SENSITIVE(menu,condition) \ gimp_item_factory_set_sensitive (factory, menu, (condition) != 0) - SET_SENSITIVE ("/Open Image", imagefile); - SET_SENSITIVE ("/Raise or Open Image", imagefile); - SET_SENSITIVE ("/File Open Dialog...", TRUE); - SET_SENSITIVE ("/Remove Entry", imagefile); - SET_SENSITIVE ("/Refresh History", TRUE); + SET_SENSITIVE ("/Open Image", imagefile); + SET_SENSITIVE ("/Raise or Open Image", imagefile); + SET_SENSITIVE ("/File Open Dialog...", TRUE); + SET_SENSITIVE ("/Remove Entry", imagefile); + SET_SENSITIVE ("/Recreate Preview", imagefile); + SET_SENSITIVE ("/Reload all Previews", imagefile); + SET_SENSITIVE ("/Remove Dangling Entries", imagefile); #undef SET_SENSITIVE } diff --git a/app/gui/documents-commands.h b/app/gui/documents-commands.h index f226e55398..d7f4c7124c 100644 --- a/app/gui/documents-commands.h +++ b/app/gui/documents-commands.h @@ -20,19 +20,23 @@ #define __DOCUMENTS_COMMANDS_H__ -void documents_open_document_cmd_callback (GtkWidget *widget, - gpointer data); -void documents_raise_or_open_document_cmd_callback (GtkWidget *widget, - gpointer data); -void documents_file_open_dialog_cmd_callback (GtkWidget *widget, - gpointer data); -void documents_delete_document_cmd_callback (GtkWidget *widget, - gpointer data); -void documents_refresh_documents_cmd_callback (GtkWidget *widget, - gpointer data); +void documents_open_document_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_raise_or_open_document_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_file_open_dialog_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_delete_document_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_recreate_preview_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_reload_previews_cmd_callback (GtkWidget *widget, + gpointer data); +void documents_delete_dangling_documents_cmd_callback (GtkWidget *widget, + gpointer data); -void documents_menu_update (GtkItemFactory *factory, - gpointer data); +void documents_menu_update (GtkItemFactory *factory, + gpointer data); #endif /* __DOCUMENTS_COMMANDS_H__ */ diff --git a/app/gui/file-open-dialog.c b/app/gui/file-open-dialog.c index 1b64d54590..26e2ac2d86 100644 --- a/app/gui/file-open-dialog.c +++ b/app/gui/file-open-dialog.c @@ -296,11 +296,20 @@ file_open_dialog_create (Gimp *gimp) gtk_box_pack_start (GTK_BOX (vbox2), open_options_title, FALSE, FALSE, 0); gtk_widget_show (open_options_title); - label = gtk_label_new (" \n "); + label = gtk_label_new (" \n \n "); + gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.0); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER); gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0); gtk_widget_show (label); + /* eek */ + { + GtkRequisition requisition; + + gtk_widget_size_request (label, &requisition); + gtk_widget_set_size_request (label, -1, requisition.height); + } + g_signal_connect (G_OBJECT (open_options_imagefile), "info_changed", G_CALLBACK (file_open_imagefile_info_changed), label); diff --git a/app/gui/menus.c b/app/gui/menus.c index bf6756159e..b3d00c49fd 100644 --- a/app/gui/menus.c +++ b/app/gui/menus.c @@ -1866,31 +1866,34 @@ static GimpItemFactoryEntry documents_entries[] = { { N_("/Open Image"), NULL, documents_open_document_cmd_callback, 0, "", GTK_STOCK_OPEN }, - NULL, - NULL, NULL }, + NULL, NULL, NULL }, { { N_("/Raise or Open Image"), NULL, documents_raise_or_open_document_cmd_callback, 0, "", GTK_STOCK_OPEN }, - NULL, - NULL, NULL }, + NULL, NULL, NULL }, { { N_("/File Open Dialog..."), NULL, documents_file_open_dialog_cmd_callback, 0, "", GTK_STOCK_OPEN }, - NULL, - NULL, NULL }, + NULL, NULL, NULL }, { { N_("/Remove Entry"), NULL, documents_delete_document_cmd_callback, 0, "", GTK_STOCK_DELETE }, - NULL, - NULL, NULL }, + NULL, NULL, NULL }, SEPARATOR ("/---"), - { { N_("/Refresh History"), NULL, - documents_refresh_documents_cmd_callback, 0, + { { N_("/Recreate Preview"), NULL, + documents_recreate_preview_cmd_callback, 0, "", GTK_STOCK_REFRESH }, - NULL, - NULL, NULL } + NULL, NULL, NULL }, + { { N_("/Reload all Previews"), NULL, + documents_reload_previews_cmd_callback, 0, + "", GTK_STOCK_REFRESH }, + NULL, NULL, NULL }, + { { N_("/Remove Dangling Entries"), NULL, + documents_delete_dangling_documents_cmd_callback, 0, + "", GTK_STOCK_REFRESH }, + NULL, NULL, NULL }, }; diff --git a/app/menus/menus.c b/app/menus/menus.c index bf6756159e..b3d00c49fd 100644 --- a/app/menus/menus.c +++ b/app/menus/menus.c @@ -1866,31 +1866,34 @@ static GimpItemFactoryEntry documents_entries[] = { { N_("/Open Image"), NULL, documents_open_document_cmd_callback, 0, "", GTK_STOCK_OPEN }, - NULL, - NULL, NULL }, + NULL, NULL, NULL }, { { N_("/Raise or Open Image"), NULL, documents_raise_or_open_document_cmd_callback, 0, "", GTK_STOCK_OPEN }, - NULL, - NULL, NULL }, + NULL, NULL, NULL }, { { N_("/File Open Dialog..."), NULL, documents_file_open_dialog_cmd_callback, 0, "", GTK_STOCK_OPEN }, - NULL, - NULL, NULL }, + NULL, NULL, NULL }, { { N_("/Remove Entry"), NULL, documents_delete_document_cmd_callback, 0, "", GTK_STOCK_DELETE }, - NULL, - NULL, NULL }, + NULL, NULL, NULL }, SEPARATOR ("/---"), - { { N_("/Refresh History"), NULL, - documents_refresh_documents_cmd_callback, 0, + { { N_("/Recreate Preview"), NULL, + documents_recreate_preview_cmd_callback, 0, "", GTK_STOCK_REFRESH }, - NULL, - NULL, NULL } + NULL, NULL, NULL }, + { { N_("/Reload all Previews"), NULL, + documents_reload_previews_cmd_callback, 0, + "", GTK_STOCK_REFRESH }, + NULL, NULL, NULL }, + { { N_("/Remove Dangling Entries"), NULL, + documents_delete_dangling_documents_cmd_callback, 0, + "", GTK_STOCK_REFRESH }, + NULL, NULL, NULL }, }; diff --git a/app/widgets/gimpcontainerview-utils.c b/app/widgets/gimpcontainerview-utils.c index 65d1ab8f47..6277228723 100644 --- a/app/widgets/gimpcontainerview-utils.c +++ b/app/widgets/gimpcontainerview-utils.c @@ -382,11 +382,21 @@ gimp_container_view_imagefile_name_func (GtkWidget *widget, if (tooltip) { - gchar *filename; + gchar *filename; + const gchar *desc; filename = file_utils_uri_to_utf8_filename (uri); + desc = gimp_imagefile_get_description (imagefile); - *tooltip = filename; + if (desc) + { + *tooltip = g_strdup_printf ("%s\n%s", filename, desc); + g_free (filename); + } + else + { + *tooltip = filename; + } } if (imagefile->width > 0 && imagefile->height > 0) diff --git a/app/widgets/gimpdocumentview.c b/app/widgets/gimpdocumentview.c index e3b204ec01..405a69e350 100644 --- a/app/widgets/gimpdocumentview.c +++ b/app/widgets/gimpdocumentview.c @@ -176,7 +176,8 @@ gimp_document_view_new (GimpViewType view_type, gimp_editor_add_button (GIMP_EDITOR (editor->view), GTK_STOCK_REFRESH, _("Recreate preview\n" - " Reload all previews"), + " Reload all previews\n" + " Remove Dangling Entries"), NULL, G_CALLBACK (gimp_document_view_refresh_clicked), G_CALLBACK (gimp_document_view_refresh_extended_clicked), @@ -333,6 +334,18 @@ gimp_document_view_refresh_clicked (GtkWidget *widget, } } +static void +gimp_document_view_delete_dangling_foreach (GimpImagefile *imagefile, + GimpContainer *container) +{ + gimp_imagefile_update (imagefile); + + if (imagefile->state == GIMP_IMAGEFILE_STATE_NOT_FOUND) + { + gimp_container_remove (container, GIMP_OBJECT (imagefile)); + } +} + static void gimp_document_view_refresh_extended_clicked (GtkWidget *widget, guint state, @@ -342,7 +355,13 @@ gimp_document_view_refresh_extended_clicked (GtkWidget *widget, editor = GIMP_CONTAINER_EDITOR (view); - if (state & GDK_SHIFT_MASK) + if (state & GDK_CONTROL_MASK) + { + gimp_container_foreach (editor->view->container, + (GFunc) gimp_document_view_delete_dangling_foreach, + editor->view->container); + } + else if (state & GDK_SHIFT_MASK) { gimp_container_foreach (editor->view->container, (GFunc) gimp_imagefile_update, diff --git a/app/widgets/gimplistitem.c b/app/widgets/gimplistitem.c index 9713115dab..dc3f8ca889 100644 --- a/app/widgets/gimplistitem.c +++ b/app/widgets/gimplistitem.c @@ -324,7 +324,8 @@ gimp_list_item_real_set_viewable (GimpListItem *list_item, gimp_list_item_name_changed (viewable, list_item); - g_signal_connect_object (G_OBJECT (viewable), "name_changed", + g_signal_connect_object (G_OBJECT (viewable), + GIMP_VIEWABLE_GET_CLASS (viewable)->name_changed_signal, G_CALLBACK (gimp_list_item_name_changed), list_item, 0); @@ -592,21 +593,16 @@ gimp_list_item_name_changed (GimpViewable *viewable, { if (list_item->get_name_func) { - gchar *name; - gchar *tooltip; + gchar *name = NULL; + gchar *tooltip = NULL; name = list_item->get_name_func (GTK_WIDGET (list_item), &tooltip); gtk_label_set_text (GTK_LABEL (list_item->name_label), name); + gimp_help_set_help_data (GTK_WIDGET (list_item), tooltip, NULL); g_free (name); - - if (tooltip) - { - gimp_help_set_help_data (GTK_WIDGET (list_item), tooltip, NULL); - - g_free (tooltip); - } + g_free (tooltip); } else { diff --git a/app/widgets/gimpmenuitem.c b/app/widgets/gimpmenuitem.c index b0094eb0c4..acdd2f3279 100644 --- a/app/widgets/gimpmenuitem.c +++ b/app/widgets/gimpmenuitem.c @@ -146,7 +146,8 @@ gimp_menu_item_real_set_viewable (GimpMenuItem *menu_item, gimp_menu_item_name_changed (viewable, menu_item); - g_signal_connect_object (G_OBJECT (viewable), "name_changed", + g_signal_connect_object (G_OBJECT (viewable), + GIMP_VIEWABLE_GET_CLASS (viewable)->name_changed_signal, G_CALLBACK (gimp_menu_item_name_changed), menu_item, 0); @@ -185,21 +186,16 @@ gimp_menu_item_name_changed (GimpViewable *viewable, { if (menu_item->get_name_func) { - gchar *name; - gchar *tooltip; + gchar *name = NULL; + gchar *tooltip = NULL; name = menu_item->get_name_func (GTK_WIDGET (menu_item), &tooltip); gtk_label_set_text (GTK_LABEL (menu_item->name_label), name); + gimp_help_set_help_data (GTK_WIDGET (menu_item), tooltip, NULL); g_free (name); - - if (tooltip) - { - gimp_help_set_help_data (GTK_WIDGET (menu_item), tooltip, NULL); - - g_free (tooltip); - } + g_free (tooltip); } else {