gimp/app/gui/file-commands.c
Michael Natterer 9252db5865 Fixed File->Revert, which was completely broken before:
2003-05-17  Michael Natterer  <mitch@gimp.org>

	Fixed File->Revert, which was completely broken before:

	* app/gui/file-commands.c (file_revert_confirm_callback): set the
	new image on all GimpContexts which had the old image set.  Unref
	the new image after the displays are reconnected.

	Added some paranoia code for similar future situations (the
	functions below were not broken, but affected by the above bug):

	* app/display/gimpdisplay-handlers.c (gimp_display_disconnect):
	set gdisp->gimage to NULL before unrefing the image.

	* app/widgets/gimpimagedock.c (gimp_image_dock_image_changed):
	unref the gimage pointer returned by g_object_get() only if it is
	non-NULL. Cleanup.
2003-05-17 16:34:30 +00:00

486 lines
12 KiB
C

/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include "libgimpwidgets/gimpwidgets.h"
#include "gui-types.h"
#include "config/gimpguiconfig.h"
#include "core/gimp.h"
#include "core/gimpcontainer.h"
#include "core/gimpcontext.h"
#include "core/gimplist.h"
#include "core/gimpimage.h"
#include "core/gimpimage-undo.h"
#include "core/gimptemplate.h"
#include "file/file-open.h"
#include "file/file-save.h"
#include "file/file-utils.h"
#include "widgets/gimpdialogfactory.h"
#include "display/gimpdisplay.h"
#include "display/gimpdisplay-foreach.h"
#include "display/gimpdisplayshell.h"
#include "dialogs.h"
#include "file-commands.h"
#include "file-new-dialog.h"
#include "file-open-dialog.h"
#include "file-save-dialog.h"
#include "menus.h"
#include "gimp-intl.h"
#define REVERT_DATA_KEY "revert-confirm-dialog"
#define return_if_no_gimp(gimp,data) \
if (GIMP_IS_DISPLAY (data)) \
gimp = ((GimpDisplay *) data)->gimage->gimp; \
else if (GIMP_IS_GIMP (data)) \
gimp = data; \
else \
gimp = NULL; \
if (! gimp) \
return
#define return_if_no_display(gdisp,data) \
if (GIMP_IS_DISPLAY (data)) \
gdisp = data; \
else if (GIMP_IS_GIMP (data)) \
gdisp = gimp_context_get_display (gimp_get_user_context (GIMP (data))); \
else \
gdisp = NULL; \
if (! gdisp) \
return
/* local function prototypes */
static void file_new_template_callback (GtkWidget *widget,
gchar *name,
gpointer data);
static void file_revert_confirm_callback (GtkWidget *widget,
gboolean revert,
gpointer data);
/* public functions */
void
file_new_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
Gimp *gimp;
GimpImage *gimage;
GtkWidget *dialog;
return_if_no_gimp (gimp, data);
/* if called from the image menu */
if (action)
gimage = gimp_context_get_image (gimp_get_user_context (gimp));
else
gimage = NULL;
dialog = gimp_dialog_factory_dialog_new (global_dialog_factory,
"gimp-file-new-dialog", -1);
if (dialog)
file_new_dialog_set (dialog, gimage, NULL);
}
void
file_open_by_extension_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
file_open_dialog_set_type (NULL);
}
void
file_open_type_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
file_open_dialog_set_type ((PlugInProcDef *) data);
}
void
file_open_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
Gimp *gimp;
GimpImage *gimage;
return_if_no_gimp (gimp, data);
/* if called from the image menu */
if (action)
gimage = gimp_context_get_image (gimp_get_user_context (gimp));
else
gimage = NULL;
file_open_dialog_show (gimp, gimage, NULL, global_menu_factory);
}
void
file_last_opened_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
Gimp *gimp;
GimpImagefile *imagefile;
guint num_entries;
return_if_no_gimp (gimp, data);
num_entries = gimp_container_num_children (gimp->documents);
if (action >= num_entries)
return;
imagefile = (GimpImagefile *)
gimp_container_get_child_by_index (gimp->documents, action);
if (imagefile)
{
GimpImage *gimage;
GimpPDBStatusType status;
GError *error = NULL;
gimage = file_open_with_display (gimp, GIMP_OBJECT (imagefile)->name,
&status, &error);
if (! gimage && status != GIMP_PDB_CANCEL)
{
gchar *filename;
filename =
file_utils_uri_to_utf8_filename (GIMP_OBJECT (imagefile)->name);
g_message (_("Opening '%s' failed:\n\n%s"),
filename, error->message);
g_clear_error (&error);
g_free (filename);
}
}
}
void
file_save_by_extension_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
file_save_dialog_set_type (NULL);
}
void
file_save_type_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
file_save_dialog_set_type ((PlugInProcDef *) data);
}
void
file_save_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
GimpDisplay *gdisp;
return_if_no_display (gdisp, data);
if (! gimp_image_active_drawable (gdisp->gimage))
return;
/* Only save if the gimage has been modified */
if (gdisp->gimage->dirty ||
! GIMP_GUI_CONFIG (gdisp->gimage->gimp->config)->trust_dirty_flag)
{
const gchar *uri;
uri = gimp_object_get_name (GIMP_OBJECT (gdisp->gimage));
if (! uri)
{
file_save_as_cmd_callback (widget, data, action);
}
else
{
GimpPDBStatusType status;
GError *error = NULL;
status = file_save (gdisp->gimage, GIMP_RUN_WITH_LAST_VALS, &error);
if (status != GIMP_PDB_SUCCESS &&
status != GIMP_PDB_CANCEL)
{
gchar *filename;
filename = file_utils_uri_to_utf8_filename (uri);
g_message (_("Saving '%s' failed:\n\n%s"),
filename, error->message);
g_clear_error (&error);
g_free (filename);
}
}
}
}
void
file_save_as_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
GimpDisplay *gdisp;
return_if_no_display (gdisp, data);
file_save_dialog_show (gdisp->gimage, global_menu_factory);
}
void
file_save_a_copy_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
GimpDisplay *gdisp;
return_if_no_display (gdisp, data);
file_save_a_copy_dialog_show (gdisp->gimage, global_menu_factory);
}
void
file_save_template_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
GimpDisplay *gdisp;
GtkWidget *qbox;
return_if_no_display (gdisp, data);
qbox = gimp_query_string_box (_("Create New Template"),
gimp_standard_help_func,
"dialogs/new_template.html",
_("Enter a name for this template"),
NULL,
G_OBJECT (gdisp->gimage), "disconnect",
file_new_template_callback, gdisp->gimage);
gtk_widget_show (qbox);
}
void
file_revert_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
GimpDisplay *gdisp;
GtkWidget *query_box;
const gchar *uri;
return_if_no_display (gdisp, data);
uri = gimp_object_get_name (GIMP_OBJECT (gdisp->gimage));
query_box = g_object_get_data (G_OBJECT (gdisp->gimage), REVERT_DATA_KEY);
if (! uri)
{
g_message (_("Revert failed.\n"
"No file name associated with this image."));
}
else if (query_box)
{
gtk_window_present (GTK_WINDOW (query_box->window));
}
else
{
gchar *basename;
gchar *text;
basename = g_path_get_basename (uri);
text = g_strdup_printf (_("Revert '%s' to\n"
"'%s'?\n\n"
"You will lose all your changes, "
"including all undo information."),
basename, uri);
g_free (basename);
query_box = gimp_query_boolean_box (_("Revert Image"),
gimp_standard_help_func,
"file/revert.html",
GIMP_STOCK_QUESTION,
text,
GTK_STOCK_YES, GTK_STOCK_NO,
G_OBJECT (gdisp->gimage),
"disconnect",
file_revert_confirm_callback,
gdisp->gimage);
g_free (text);
g_object_set_data (G_OBJECT (gdisp->gimage), REVERT_DATA_KEY,
query_box);
gtk_window_set_transient_for (GTK_WINDOW (query_box),
GTK_WINDOW (gdisp->shell));
gtk_widget_show (query_box);
}
}
void
file_close_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
GimpDisplay *gdisp;
return_if_no_display (gdisp, data);
gimp_display_shell_close (GIMP_DISPLAY_SHELL (gdisp->shell), FALSE);
}
void
file_quit_cmd_callback (GtkWidget *widget,
gpointer data,
guint action)
{
Gimp *gimp;
return_if_no_gimp (gimp, data);
gimp_exit (gimp, FALSE);
}
void
file_file_open_dialog (Gimp *gimp,
const gchar *uri)
{
file_open_dialog_show (gimp, NULL, uri, global_menu_factory);
}
/* private functions */
static void
file_new_template_callback (GtkWidget *widget,
gchar *name,
gpointer data)
{
GimpTemplate *template;
GimpImage *gimage;
gimage = (GimpImage *) data;
if (! (name && strlen (name)))
name = _("(Unnamed Template)");
template = gimp_template_new (name);
gimp_template_set_from_image (template, gimage);
gimp_list_uniquefy_name (GIMP_LIST (gimage->gimp->templates),
GIMP_OBJECT (template), TRUE);
gimp_container_add (gimage->gimp->templates,
GIMP_OBJECT (template));
g_object_unref (template);
}
static void
file_revert_confirm_callback (GtkWidget *widget,
gboolean revert,
gpointer data)
{
GimpImage *old_gimage;
old_gimage = (GimpImage *) data;
g_object_set_data (G_OBJECT (old_gimage), REVERT_DATA_KEY, NULL);
if (revert)
{
Gimp *gimp;
GimpImage *new_gimage;
const gchar *uri;
GimpPDBStatusType status;
GError *error = NULL;
gimp = old_gimage->gimp;
uri = gimp_object_get_name (GIMP_OBJECT (old_gimage));
new_gimage = file_open_image (gimp, uri, uri, NULL,
GIMP_RUN_INTERACTIVE,
&status, &error);
if (new_gimage)
{
GList *contexts = NULL;
GList *list;
/* remember which contexts refer to old_gimage */
for (list = gimp->context_list; list; list = g_list_next (list))
{
GimpContext *context = list->data;
if (gimp_context_get_image (context) == old_gimage)
contexts = g_list_prepend (contexts, list->data);
}
gimp_image_undo_free (new_gimage);
gimp_displays_reconnect (gimp, old_gimage, new_gimage);
gimp_image_clean_all (new_gimage);
gimp_image_flush (new_gimage);
/* set the new_gimage on the remembered contexts (in reverse
* order, since older contexts are usually the parents of
* newer ones)
*/
g_list_foreach (contexts, (GFunc) gimp_context_set_image, new_gimage);
g_list_free (contexts);
/* the displays own the image now */
g_object_unref (new_gimage);
}
else if (status != GIMP_PDB_CANCEL)
{
gchar *filename;
filename = file_utils_uri_to_utf8_filename (uri);
g_message (_("Reverting to '%s' failed:\n\n%s"),
filename, error->message);
g_clear_error (&error);
g_free (filename);
}
}
}