2004-05-23 Michael Natterer <mitch@gimp.org> * app/widgets/widgets-types.h: reoedered to somehow reflect the class hierarchy. Some dockable context handling cleanup: * app/widgets/gimpdocked.[ch]: removed "prev_context" parameter from GimpDocked::set_context(). Widgets which need the old context to disconnect from should remember it themselves. * app/widgets/gimpdockable.c (gimp_dockable_set_context): don't pass the old context to gimp_docked_set_context(). Some cleanup. * app/widgets/gimpcontainerbox.c * app/widgets/gimpcontainereditor.c: changed accordingly. * app/display/gimpnavigationview.[ch] * app/widgets/gimpimageeditor.[ch] * app/widgets/gimpitemtreeview.[ch]: added a "context" member which holds the context set by GimpDocked::set_context(). * app/widgets/gimpdrawabletreeview.c: use the view's context instead of gimp_get_user_context(). * app/widgets/gimpcoloreditor.[ch]: removed separate API to set the context because it implements the GimpDockedInterface. * app/widgets/gimpcomponenteditor.c * app/widgets/gimperrorconsole.c: pass "menu-factory", "menu-identifier" and "ui-path" to g_object_new() instead of calling gimp_editor_create_menu() later. Action cleanup partly related to the context stuff above: * app/actions/actions.c (action_data_get_gimp): get the Gimp from context->gimp, not gimage->gimp because gimage may be NULL. (action_data_get_context): changed to use the new context members added above. * app/actions/channels-actions.c (channels_actions_update): cleanup. * app/actions/edit-actions.c (edit_actions_update): fixed sensitivity of "edit-undo-clear". * app/actions/vectors-actions.c (vectors_actions_update): make "vectors-merge-visible" sensitive only if there is more than one GimpVectors in the image. * app/actions/colormap-editor-actions.c * app/actions/gradient-editor-actions.c * app/actions/palette-editor-actions.c: added FG/BG color previews to actions which take colors from them. Changed code to be safe against "context" being NULL. * app/actions/drawable-commands.c: s/active_drawable/drawable/g. Makes the code more readable. * app/actions/select-commands.[ch] * app/actions/vectors-commands.[ch]: removed public stroke utility functions and other stuff which is not needed any more because dialog buttons invoke the correct actions now. Moved the functions' code to the resp. action callbacks.
454 lines
14 KiB
C
454 lines
14 KiB
C
/* The GIMP -- an image manipulation program
|
|
* Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
|
|
*
|
|
* gimperrorconsole.c
|
|
* Copyright (C) 2003 Michael Natterer <mitch@gimp.org>
|
|
*
|
|
* partly based on errorconsole.c
|
|
* Copyright (C) 1998 Nick Fetchak <nuke@bayside.net>
|
|
*
|
|
* 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 <glib.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
|
|
#ifdef G_OS_WIN32
|
|
#include <io.h>
|
|
#ifndef S_IRUSR
|
|
#define S_IRUSR _S_IREAD
|
|
#endif
|
|
#ifndef S_IWUSR
|
|
#define S_IWUSR _S_IWRITE
|
|
#endif
|
|
#endif
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
#include "widgets-types.h"
|
|
|
|
#include "core/gimp.h"
|
|
|
|
#include "gimperrorconsole.h"
|
|
#include "gimphelp-ids.h"
|
|
#include "gimpmenufactory.h"
|
|
#include "gimpwidgets-utils.h"
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
static void gimp_error_console_class_init (GimpErrorConsoleClass *klass);
|
|
static void gimp_error_console_init (GimpErrorConsole *editor);
|
|
|
|
static void gimp_error_console_destroy (GtkObject *object);
|
|
static void gimp_error_console_unmap (GtkWidget *widget);
|
|
|
|
static gboolean gimp_error_console_button_press (GtkWidget *widget,
|
|
GdkEventButton *event,
|
|
GimpErrorConsole *console);
|
|
static void gimp_error_console_clear_clicked (GtkWidget *button,
|
|
GimpErrorConsole *console);
|
|
static void gimp_error_console_save_clicked (GtkWidget *button,
|
|
GimpErrorConsole *console);
|
|
static void gimp_error_console_save_ext_clicked (GtkWidget *button,
|
|
GdkModifierType state,
|
|
GimpErrorConsole *console);
|
|
static void gimp_error_console_save_response (GtkWidget *dialog,
|
|
gint response_id,
|
|
GimpErrorConsole *console);
|
|
|
|
static gboolean gimp_error_console_write_file (GtkTextBuffer *text_buffer,
|
|
const gchar *path,
|
|
gboolean selection_only);
|
|
|
|
|
|
static GimpEditorClass *parent_class = NULL;
|
|
|
|
|
|
GType
|
|
gimp_error_console_get_type (void)
|
|
{
|
|
static GType view_type = 0;
|
|
|
|
if (! view_type)
|
|
{
|
|
static const GTypeInfo view_info =
|
|
{
|
|
sizeof (GimpErrorConsoleClass),
|
|
NULL, /* base_init */
|
|
NULL, /* base_finalize */
|
|
(GClassInitFunc) gimp_error_console_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (GimpErrorConsole),
|
|
0, /* n_preallocs */
|
|
(GInstanceInitFunc) gimp_error_console_init,
|
|
};
|
|
|
|
view_type = g_type_register_static (GIMP_TYPE_EDITOR,
|
|
"GimpErrorConsole",
|
|
&view_info, 0);
|
|
}
|
|
|
|
return view_type;
|
|
}
|
|
|
|
static void
|
|
gimp_error_console_class_init (GimpErrorConsoleClass *klass)
|
|
{
|
|
GtkObjectClass *object_class;
|
|
GtkWidgetClass *widget_class;
|
|
|
|
object_class = GTK_OBJECT_CLASS (klass);
|
|
widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
|
|
|
object_class->destroy = gimp_error_console_destroy;
|
|
widget_class->unmap = gimp_error_console_unmap;
|
|
}
|
|
|
|
static void
|
|
gimp_error_console_init (GimpErrorConsole *console)
|
|
{
|
|
GtkWidget *scrolled_window;
|
|
gchar *str;
|
|
|
|
console->text_buffer = gtk_text_buffer_new (NULL);
|
|
|
|
gtk_text_buffer_create_tag (console->text_buffer, "title",
|
|
"weight", PANGO_WEIGHT_BOLD,
|
|
"scale", PANGO_SCALE_LARGE,
|
|
NULL);
|
|
gtk_text_buffer_create_tag (console->text_buffer, "message",
|
|
NULL);
|
|
|
|
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
|
|
GTK_POLICY_AUTOMATIC,
|
|
GTK_POLICY_AUTOMATIC);
|
|
gtk_container_add (GTK_CONTAINER (console), scrolled_window);
|
|
gtk_widget_show (scrolled_window);
|
|
|
|
console->text_view = gtk_text_view_new_with_buffer (console->text_buffer);
|
|
g_object_unref (console->text_buffer);
|
|
|
|
gtk_text_view_set_editable (GTK_TEXT_VIEW (console->text_view), FALSE);
|
|
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (console->text_view),
|
|
GTK_WRAP_WORD);
|
|
gtk_container_add (GTK_CONTAINER (scrolled_window), console->text_view);
|
|
gtk_widget_show (console->text_view);
|
|
|
|
g_signal_connect (console->text_view, "button_press_event",
|
|
G_CALLBACK (gimp_error_console_button_press),
|
|
console);
|
|
|
|
console->clear_button =
|
|
gimp_editor_add_button (GIMP_EDITOR (console),
|
|
GTK_STOCK_CLEAR, _("Clear Errors"),
|
|
GIMP_HELP_ERRORS_CLEAR,
|
|
G_CALLBACK (gimp_error_console_clear_clicked),
|
|
NULL,
|
|
console);
|
|
|
|
str = g_strdup_printf (_("Save all Errors\n"
|
|
"%s Save Selection"),
|
|
gimp_get_mod_name_shift ());
|
|
|
|
console->save_button =
|
|
gimp_editor_add_button (GIMP_EDITOR (console),
|
|
GTK_STOCK_SAVE_AS, str,
|
|
GIMP_HELP_ERRORS_SAVE,
|
|
G_CALLBACK (gimp_error_console_save_clicked),
|
|
G_CALLBACK (gimp_error_console_save_ext_clicked),
|
|
console);
|
|
|
|
g_free (str);
|
|
|
|
console->file_dialog = NULL;
|
|
}
|
|
|
|
static void
|
|
gimp_error_console_destroy (GtkObject *object)
|
|
{
|
|
GimpErrorConsole *console = GIMP_ERROR_CONSOLE (object);
|
|
|
|
if (console->file_dialog)
|
|
gtk_widget_destroy (console->file_dialog);
|
|
|
|
console->gimp->message_handler = GIMP_MESSAGE_BOX;
|
|
|
|
GTK_OBJECT_CLASS (parent_class)->destroy (object);
|
|
}
|
|
|
|
static void
|
|
gimp_error_console_unmap (GtkWidget *widget)
|
|
{
|
|
GimpErrorConsole *console = GIMP_ERROR_CONSOLE (widget);
|
|
|
|
if (console->file_dialog)
|
|
gtk_widget_destroy (console->file_dialog);
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->unmap (widget);
|
|
}
|
|
|
|
GtkWidget *
|
|
gimp_error_console_new (Gimp *gimp,
|
|
GimpMenuFactory *menu_factory)
|
|
{
|
|
GimpErrorConsole *console;
|
|
|
|
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
|
|
g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
|
|
|
|
console = g_object_new (GIMP_TYPE_ERROR_CONSOLE,
|
|
"menu-factory", menu_factory,
|
|
"menu-dentifier", "<ErrorConsole>",
|
|
"ui-path", "/error-console-popup",
|
|
NULL);
|
|
|
|
console->gimp = gimp;
|
|
|
|
console->gimp->message_handler = GIMP_ERROR_CONSOLE;
|
|
|
|
return GTK_WIDGET (console);
|
|
}
|
|
|
|
void
|
|
gimp_error_console_add (GimpErrorConsole *console,
|
|
const gchar *stock_id,
|
|
const gchar *domain,
|
|
const gchar *message)
|
|
{
|
|
GtkTextIter end;
|
|
GtkTextMark *end_mark;
|
|
GdkPixbuf *pixbuf;
|
|
gchar *str;
|
|
|
|
g_return_if_fail (GIMP_IS_ERROR_CONSOLE (console));
|
|
g_return_if_fail (stock_id != NULL);
|
|
g_return_if_fail (message != NULL);
|
|
|
|
if (! domain)
|
|
domain = _("GIMP");
|
|
|
|
gtk_text_buffer_get_end_iter (console->text_buffer, &end);
|
|
|
|
pixbuf = gtk_widget_render_icon (console->text_view, stock_id,
|
|
GTK_ICON_SIZE_MENU, NULL);
|
|
gtk_text_buffer_insert_pixbuf (console->text_buffer, &end, pixbuf);
|
|
g_object_unref (pixbuf);
|
|
|
|
gtk_text_buffer_insert (console->text_buffer, &end, " ", -1);
|
|
|
|
str = g_strdup_printf (_("%s Message"), domain);
|
|
gtk_text_buffer_insert_with_tags_by_name (console->text_buffer, &end,
|
|
str, -1,
|
|
"title",
|
|
NULL);
|
|
g_free (str);
|
|
|
|
gtk_text_buffer_insert (console->text_buffer, &end, "\n", -1);
|
|
|
|
gtk_text_buffer_insert_with_tags_by_name (console->text_buffer, &end,
|
|
message, -1,
|
|
"message",
|
|
NULL);
|
|
|
|
gtk_text_buffer_insert (console->text_buffer, &end, "\n\n", -1);
|
|
|
|
end_mark = gtk_text_buffer_create_mark (console->text_buffer,
|
|
NULL, &end, TRUE);
|
|
gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (console->text_view), end_mark,
|
|
FALSE, TRUE, 1.0, 0.0);
|
|
gtk_text_buffer_delete_mark (console->text_buffer, end_mark);
|
|
}
|
|
|
|
|
|
/* private functions */
|
|
|
|
static gboolean
|
|
gimp_error_console_button_press (GtkWidget *widget,
|
|
GdkEventButton *bevent,
|
|
GimpErrorConsole *console)
|
|
{
|
|
if (bevent->button == 3 && bevent->type == GDK_BUTTON_PRESS)
|
|
{
|
|
return gimp_editor_popup_menu (GIMP_EDITOR (console), NULL, NULL);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gimp_error_console_clear_clicked (GtkWidget *button,
|
|
GimpErrorConsole *console)
|
|
{
|
|
GtkTextIter start_iter;
|
|
GtkTextIter end_iter;
|
|
|
|
gtk_text_buffer_get_start_iter (console->text_buffer, &start_iter);
|
|
gtk_text_buffer_get_end_iter (console->text_buffer, &end_iter);
|
|
|
|
gtk_text_buffer_delete (console->text_buffer, &start_iter, &end_iter);
|
|
}
|
|
|
|
static void
|
|
gimp_error_console_save_clicked (GtkWidget *button,
|
|
GimpErrorConsole *console)
|
|
{
|
|
gimp_error_console_save_ext_clicked (button, 0, console);
|
|
}
|
|
|
|
static void
|
|
gimp_error_console_save_ext_clicked (GtkWidget *button,
|
|
GdkModifierType state,
|
|
GimpErrorConsole *console)
|
|
{
|
|
GtkFileChooser *chooser;
|
|
|
|
if (! gtk_text_buffer_get_selection_bounds (console->text_buffer,
|
|
NULL, NULL) &&
|
|
(state & GDK_SHIFT_MASK))
|
|
{
|
|
g_message (_("Cannot save. Nothing is selected."));
|
|
return;
|
|
}
|
|
|
|
if (console->file_dialog)
|
|
{
|
|
gtk_window_present (GTK_WINDOW (console->file_dialog));
|
|
return;
|
|
}
|
|
|
|
console->file_dialog =
|
|
gtk_file_chooser_dialog_new (_("Save Error Log to File"), NULL,
|
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
|
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_SAVE, GTK_RESPONSE_OK,
|
|
|
|
NULL);
|
|
|
|
console->save_selection = (state & GDK_SHIFT_MASK) ? TRUE : FALSE;
|
|
|
|
g_object_add_weak_pointer (G_OBJECT (console->file_dialog),
|
|
(gpointer *) &console->file_dialog);
|
|
|
|
chooser = GTK_FILE_CHOOSER (console->file_dialog);
|
|
|
|
gtk_window_set_screen (GTK_WINDOW (chooser), gtk_widget_get_screen (button));
|
|
|
|
gtk_window_set_position (GTK_WINDOW (chooser), GTK_WIN_POS_MOUSE);
|
|
gtk_window_set_role (GTK_WINDOW (chooser), "gimp-save-errors");
|
|
|
|
g_signal_connect (chooser, "response",
|
|
G_CALLBACK (gimp_error_console_save_response),
|
|
console);
|
|
g_signal_connect (chooser, "delete_event",
|
|
G_CALLBACK (gtk_true),
|
|
NULL);
|
|
|
|
gimp_help_connect (GTK_WIDGET (chooser), gimp_standard_help_func,
|
|
GIMP_HELP_ERRORS_DIALOG, NULL);
|
|
|
|
gtk_widget_show (GTK_WIDGET (chooser));
|
|
}
|
|
|
|
static void
|
|
gimp_error_console_save_response (GtkWidget *dialog,
|
|
gint response_id,
|
|
GimpErrorConsole *console)
|
|
{
|
|
if (response_id == GTK_RESPONSE_OK)
|
|
{
|
|
gchar *filename;
|
|
|
|
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
|
|
|
|
if (! gimp_error_console_write_file (console->text_buffer, filename,
|
|
console->save_selection))
|
|
{
|
|
g_message (_("Error writing file '%s':\n%s"),
|
|
gimp_filename_to_utf8 (filename), g_strerror (errno));
|
|
g_free (filename);
|
|
return;
|
|
}
|
|
|
|
g_free (filename);
|
|
}
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
static gboolean
|
|
gimp_error_console_write_file (GtkTextBuffer *text_buffer,
|
|
const gchar *path,
|
|
gboolean selection_only)
|
|
{
|
|
GtkTextIter start_iter;
|
|
GtkTextIter end_iter;
|
|
gint fd;
|
|
gint text_length;
|
|
gint bytes_written;
|
|
gchar *text_contents;
|
|
|
|
fd = open (path, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
|
|
|
|
if (fd == -1)
|
|
return FALSE;
|
|
|
|
if (selection_only)
|
|
gtk_text_buffer_get_selection_bounds (text_buffer, &start_iter, &end_iter);
|
|
else
|
|
gtk_text_buffer_get_bounds (text_buffer, &start_iter, &end_iter);
|
|
|
|
text_contents = gtk_text_buffer_get_text (text_buffer,
|
|
&start_iter, &end_iter, TRUE);
|
|
|
|
text_length = strlen (text_contents);
|
|
|
|
if (text_contents && (text_length > 0))
|
|
{
|
|
bytes_written = write (fd, text_contents, text_length);
|
|
|
|
g_free (text_contents);
|
|
close (fd);
|
|
|
|
if (bytes_written != text_length)
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
}
|
|
|
|
close (fd);
|
|
|
|
return TRUE;
|
|
}
|