From c37e94332ad3d4a33a38a29f9557b7838f955f10 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Sun, 02 Dec 2007 20:02:01 +0000 Subject: Use a message area instead of a popup dialog for error notifications. 2007-12-02 Carlos Garcia Campos * configure.ac: * cut-n-paste/gedit-message-area/Makefile.am: * cut-n-paste/gedit-message-area/gedit-message-area.[ch]: * shell/Makefile.am: * shell/ev-message-area.[ch]: * shell/ev-window.c: (ev_window_set_message_area), (ev_window_error_message_response_cb), (ev_window_error_message), (ev_window_load_job_cb), (ev_window_cmd_file_open_copy_at_dest), (ev_window_save_job_cb), (image_save_dialog_response_cb), (ev_attachment_popup_cmd_open_attachment), (attachment_save_dialog_response_cb), (ev_window_set_document), (ev_window_init): Use a message area instead of a popup dialog for error notifications. Fixes bug #337495. svn path=/trunk/; revision=2757 --- diff --git a/ChangeLog b/ChangeLog index 23af1c2..8806552 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,23 @@ 2007-12-02 Carlos Garcia Campos + * configure.ac: + * cut-n-paste/gedit-message-area/Makefile.am: + * cut-n-paste/gedit-message-area/gedit-message-area.[ch]: + * shell/Makefile.am: + * shell/ev-message-area.[ch]: + * shell/ev-window.c: (ev_window_set_message_area), + (ev_window_error_message_response_cb), (ev_window_error_message), + (ev_window_load_job_cb), (ev_window_cmd_file_open_copy_at_dest), + (ev_window_save_job_cb), (image_save_dialog_response_cb), + (ev_attachment_popup_cmd_open_attachment), + (attachment_save_dialog_response_cb), (ev_window_set_document), + (ev_window_init): + + Use a message area instead of a popup dialog for error + notifications. Fixes bug #337495. + +2007-12-02 Carlos Garcia Campos + * shell/ev-window.c: (fullscreen_toolbar_remove_shadow), (ev_window_run_fullscreen): diff --git a/configure.ac b/configure.ac index d8801fa..01a9ce7 100644 --- a/configure.ac +++ b/configure.ac @@ -448,6 +448,7 @@ backend/pixbuf/Makefile backend/ps/Makefile backend/tiff/Makefile cut-n-paste/Makefile +cut-n-paste/gedit-message-area/Makefile cut-n-paste/toolbar-editor/Makefile cut-n-paste/zoom-control/Makefile cut-n-paste/totem-screensaver/Makefile diff --git a/cut-n-paste/Makefile.am b/cut-n-paste/Makefile.am index e308131..3c5609c 100644 --- a/cut-n-paste/Makefile.am +++ b/cut-n-paste/Makefile.am @@ -1 +1 @@ -SUBDIRS = zoom-control toolbar-editor totem-screensaver +SUBDIRS = zoom-control toolbar-editor totem-screensaver gedit-message-area diff --git a/cut-n-paste/gedit-message-area/Makefile.am b/cut-n-paste/gedit-message-area/Makefile.am new file mode 100644 index 0000000..8e6368b --- /dev/null +++ b/cut-n-paste/gedit-message-area/Makefile.am @@ -0,0 +1,10 @@ +noinst_LTLIBRARIES = libgeditmsgarea.la +libgeditmsgarea_la_SOURCES = \ + gedit-message-area.c \ + gedit-message-area.h + +libgeditmsgarea_la_CFLAGS = \ + -I$(top_srcdir)/lib \ + $(LIB_CFLAGS) \ + $(WARNING_CFLAGS) \ + $(DISABLE_DEPRECATED) diff --git a/cut-n-paste/gedit-message-area/gedit-message-area.c b/cut-n-paste/gedit-message-area/gedit-message-area.c new file mode 100644 index 0000000..7fb88cc --- /dev/null +++ b/cut-n-paste/gedit-message-area/gedit-message-area.c @@ -0,0 +1,540 @@ +/* + * gedit-message-area.c + * This file is part of gedit + * + * Copyright (C) 2005 - Paolo Maggi + * + * 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. + */ + +/* + * Modified by the gedit Team, 2005. See the AUTHORS file for a + * list of people on the gedit Team. + * See the ChangeLog files for a list of changes. + * + * $Id: gedit-message-area.c 5887 2007-09-07 07:20:19Z pborelli $ + */ + +/* TODO: Style properties */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "gedit-message-area.h" + +#define GEDIT_MESSAGE_AREA_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), \ + GEDIT_TYPE_MESSAGE_AREA, \ + GeditMessageAreaPrivate)) + +struct _GeditMessageAreaPrivate +{ + GtkWidget *main_hbox; + + GtkWidget *contents; + GtkWidget *action_area; + + gboolean changing_style; +}; + +typedef struct _ResponseData ResponseData; + +struct _ResponseData +{ + gint response_id; +}; + +enum { + RESPONSE, + CLOSE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE(GeditMessageArea, gedit_message_area, GTK_TYPE_HBOX) + + +static void +gedit_message_area_finalize (GObject *object) +{ + /* + GeditMessageArea *message_area = GEDIT_MESSAGE_AREA (object); + */ + + G_OBJECT_CLASS (gedit_message_area_parent_class)->finalize (object); +} + +static ResponseData * +get_response_data (GtkWidget *widget, + gboolean create) +{ + ResponseData *ad = g_object_get_data (G_OBJECT (widget), + "gedit-message-area-response-data"); + + if (ad == NULL && create) + { + ad = g_new (ResponseData, 1); + + g_object_set_data_full (G_OBJECT (widget), + "gedit-message-area-response-data", + ad, + g_free); + } + + return ad; +} + +static GtkWidget * +find_button (GeditMessageArea *message_area, + gint response_id) +{ + GList *children, *tmp_list; + GtkWidget *child = NULL; + + children = gtk_container_get_children ( + GTK_CONTAINER (message_area->priv->action_area)); + + for (tmp_list = children; tmp_list; tmp_list = tmp_list->next) + { + ResponseData *rd = get_response_data (tmp_list->data, FALSE); + + if (rd && rd->response_id == response_id) + { + child = tmp_list->data; + break; + } + } + + g_list_free (children); + + return child; +} + +static void +gedit_message_area_close (GeditMessageArea *message_area) +{ + if (!find_button (message_area, GTK_RESPONSE_CANCEL)) + return; + + /* emit response signal */ + gedit_message_area_response (GEDIT_MESSAGE_AREA (message_area), + GTK_RESPONSE_CANCEL); +} + +static gboolean +paint_message_area (GtkWidget *widget, + GdkEventExpose *event, + gpointer user_data) +{ + gtk_paint_flat_box (widget->style, + widget->window, + GTK_STATE_NORMAL, + GTK_SHADOW_OUT, + NULL, + widget, + "tooltip", + widget->allocation.x + 1, + widget->allocation.y + 1, + widget->allocation.width - 2, + widget->allocation.height - 2); + + return FALSE; +} + +static void +gedit_message_area_class_init (GeditMessageAreaClass *klass) +{ + GObjectClass *object_class; + GtkBindingSet *binding_set; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gedit_message_area_finalize; + + klass->close = gedit_message_area_close; + + g_type_class_add_private (object_class, sizeof(GeditMessageAreaPrivate)); + + signals[RESPONSE] = g_signal_new ("response", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GeditMessageAreaClass, response), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); + + signals[CLOSE] = g_signal_new ("close", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GeditMessageAreaClass, close), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + binding_set = gtk_binding_set_by_class (klass); + + gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, "close", 0); +} + +static void +style_set (GtkWidget *widget, + GtkStyle *prev_style, + GeditMessageArea *message_area) +{ + GtkWidget *window; + GtkStyle *style; + + if (message_area->priv->changing_style) + return; + + /* This is a hack needed to use the tooltip background color */ + window = gtk_window_new (GTK_WINDOW_POPUP); + gtk_widget_set_name (window, "gtk-tooltip"); + gtk_widget_ensure_style (window); + style = gtk_widget_get_style (window); + + message_area->priv->changing_style = TRUE; + gtk_widget_set_style (GTK_WIDGET (message_area), style); + message_area->priv->changing_style = FALSE; + + gtk_widget_destroy (window); + + gtk_widget_queue_draw (GTK_WIDGET (message_area)); +} + +static void +gedit_message_area_init (GeditMessageArea *message_area) +{ + message_area->priv = GEDIT_MESSAGE_AREA_GET_PRIVATE (message_area); + + message_area->priv->main_hbox = gtk_hbox_new (FALSE, 16); /* FIXME: use style properties */ + gtk_widget_show (message_area->priv->main_hbox); + gtk_container_set_border_width (GTK_CONTAINER (message_area->priv->main_hbox), + 8); /* FIXME: use style properties */ + + message_area->priv->action_area = gtk_vbox_new (TRUE, 10); /* FIXME: use style properties */ + gtk_widget_show (message_area->priv->action_area); + gtk_box_pack_end (GTK_BOX (message_area->priv->main_hbox), + message_area->priv->action_area, + FALSE, + TRUE, + 0); + + gtk_box_pack_start (GTK_BOX (message_area), + message_area->priv->main_hbox, + TRUE, + TRUE, + 0); + + gtk_widget_set_app_paintable (GTK_WIDGET (message_area), TRUE); + + g_signal_connect (message_area, + "expose-event", + G_CALLBACK (paint_message_area), + NULL); + + /* Note that we connect to style-set on one of the internal + * widgets, not on the message area itself, since gtk does + * not deliver any further style-set signals for a widget on + * which the style has been forced with gtk_widget_set_style() */ + g_signal_connect (message_area->priv->main_hbox, + "style-set", + G_CALLBACK (style_set), + message_area); +} + +static gint +get_response_for_widget (GeditMessageArea *message_area, + GtkWidget *widget) +{ + ResponseData *rd; + + rd = get_response_data (widget, FALSE); + if (!rd) + return GTK_RESPONSE_NONE; + else + return rd->response_id; +} + +static void +action_widget_activated (GtkWidget *widget, GeditMessageArea *message_area) +{ + gint response_id; + + response_id = get_response_for_widget (message_area, widget); + + gedit_message_area_response (message_area, response_id); +} + +void +gedit_message_area_add_action_widget (GeditMessageArea *message_area, + GtkWidget *child, + gint response_id) +{ + ResponseData *ad; + guint signal_id; + + g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area)); + g_return_if_fail (GTK_IS_WIDGET (child)); + + ad = get_response_data (child, TRUE); + + ad->response_id = response_id; + + if (GTK_IS_BUTTON (child)) + signal_id = g_signal_lookup ("clicked", GTK_TYPE_BUTTON); + else + signal_id = GTK_WIDGET_GET_CLASS (child)->activate_signal; + + if (signal_id) + { + GClosure *closure; + + closure = g_cclosure_new_object (G_CALLBACK (action_widget_activated), + G_OBJECT (message_area)); + + g_signal_connect_closure_by_id (child, + signal_id, + 0, + closure, + FALSE); + } + else + g_warning ("Only 'activatable' widgets can be packed into the action area of a GeditMessageArea"); + + if (response_id != GTK_RESPONSE_HELP) + gtk_box_pack_start (GTK_BOX (message_area->priv->action_area), + child, + FALSE, + FALSE, + 0); + else + gtk_box_pack_end (GTK_BOX (message_area->priv->action_area), + child, + FALSE, + FALSE, + 0); +} + +void +gedit_message_area_set_contents (GeditMessageArea *message_area, + GtkWidget *contents) +{ + g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area)); + g_return_if_fail (GTK_IS_WIDGET (contents)); + + message_area->priv->contents = contents; + gtk_box_pack_start (GTK_BOX (message_area->priv->main_hbox), + message_area->priv->contents, + TRUE, + TRUE, + 0); +} + +GtkWidget* +gedit_message_area_add_button (GeditMessageArea *message_area, + const gchar *button_text, + gint response_id) +{ + GtkWidget *button; + + g_return_val_if_fail (GEDIT_IS_MESSAGE_AREA (message_area), NULL); + g_return_val_if_fail (button_text != NULL, NULL); + + button = gtk_button_new_from_stock (button_text); + + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + + gtk_widget_show (button); + + gedit_message_area_add_action_widget (message_area, + button, + response_id); + + return button; +} + +void +gedit_message_area_add_buttons_valist (GeditMessageArea *message_area, + const gchar *first_button_text, + va_list args) +{ + const gchar* text; + gint response_id; + + g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area)); + + if (first_button_text == NULL) + return; + + text = first_button_text; + response_id = va_arg (args, gint); + + while (text != NULL) + { + gedit_message_area_add_button (message_area, + text, + response_id); + + text = va_arg (args, gchar*); + if (text == NULL) + break; + + response_id = va_arg (args, int); + } +} + +void +gedit_message_area_add_buttons (GeditMessageArea *message_area, + const gchar *first_button_text, + ...) +{ + va_list args; + + va_start (args, first_button_text); + + gedit_message_area_add_buttons_valist (message_area, + first_button_text, + args); + + va_end (args); +} + +GtkWidget * +gedit_message_area_new (void) +{ + return g_object_new (GEDIT_TYPE_MESSAGE_AREA, NULL); +} + +GtkWidget * +gedit_message_area_new_with_buttons (const gchar *first_button_text, + ...) +{ + GeditMessageArea *message_area; + va_list args; + + message_area = GEDIT_MESSAGE_AREA (gedit_message_area_new ()); + + va_start (args, first_button_text); + + gedit_message_area_add_buttons_valist (message_area, + first_button_text, + args); + + va_end (args); + + return GTK_WIDGET (message_area); +} + +void +gedit_message_area_set_response_sensitive (GeditMessageArea *message_area, + gint response_id, + gboolean setting) +{ + GList *children; + GList *tmp_list; + + g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area)); + + children = gtk_container_get_children (GTK_CONTAINER (message_area->priv->action_area)); + + tmp_list = children; + while (tmp_list != NULL) + { + GtkWidget *widget = tmp_list->data; + ResponseData *rd = get_response_data (widget, FALSE); + + if (rd && rd->response_id == response_id) + gtk_widget_set_sensitive (widget, setting); + + tmp_list = g_list_next (tmp_list); + } + + g_list_free (children); +} + +void +gedit_message_area_set_default_response (GeditMessageArea *message_area, + gint response_id) +{ + GList *children; + GList *tmp_list; + + g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area)); + + children = gtk_container_get_children (GTK_CONTAINER (message_area->priv->action_area)); + + tmp_list = children; + while (tmp_list != NULL) + { + GtkWidget *widget = tmp_list->data; + ResponseData *rd = get_response_data (widget, FALSE); + + if (rd && rd->response_id == response_id) + gtk_widget_grab_default (widget); + + tmp_list = g_list_next (tmp_list); + } + + g_list_free (children); +} + +void +gedit_message_area_response (GeditMessageArea *message_area, + gint response_id) +{ + g_return_if_fail (GEDIT_IS_MESSAGE_AREA (message_area)); + + g_signal_emit (message_area, + signals[RESPONSE], + 0, + response_id); +} + +GtkWidget * +gedit_message_area_add_stock_button_with_text (GeditMessageArea *message_area, + const gchar *text, + const gchar *stock_id, + gint response_id) +{ + GtkWidget *button; + + g_return_val_if_fail (GEDIT_IS_MESSAGE_AREA (message_area), NULL); + g_return_val_if_fail (text != NULL, NULL); + g_return_val_if_fail (stock_id != NULL, NULL); + + button = gtk_button_new_with_mnemonic (text); + gtk_button_set_image (GTK_BUTTON (button), + gtk_image_new_from_stock (stock_id, + GTK_ICON_SIZE_BUTTON)); + + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + + gtk_widget_show (button); + + gedit_message_area_add_action_widget (message_area, + button, + response_id); + + return button; +} + diff --git a/cut-n-paste/gedit-message-area/gedit-message-area.h b/cut-n-paste/gedit-message-area/gedit-message-area.h new file mode 100644 index 0000000..c53a800 --- /dev/null +++ b/cut-n-paste/gedit-message-area/gedit-message-area.h @@ -0,0 +1,132 @@ +/* + * gedit-message-area.h + * This file is part of gedit + * + * Copyright (C) 2005 - Paolo Maggi + * + * 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. + */ + +/* + * Modified by the gedit Team, 2005. See the AUTHORS file for a + * list of people on the gedit Team. + * See the ChangeLog files for a list of changes. + * + * $Id: gedit-message-area.h 5666 2007-06-29 19:52:25Z sfre $ + */ + +#ifndef __GEDIT_MESSAGE_AREA_H__ +#define __GEDIT_MESSAGE_AREA_H__ + +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define GEDIT_TYPE_MESSAGE_AREA (gedit_message_area_get_type()) +#define GEDIT_MESSAGE_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GEDIT_TYPE_MESSAGE_AREA, GeditMessageArea)) +#define GEDIT_MESSAGE_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GEDIT_TYPE_MESSAGE_AREA, GeditMessageAreaClass)) +#define GEDIT_IS_MESSAGE_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GEDIT_TYPE_MESSAGE_AREA)) +#define GEDIT_IS_MESSAGE_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_MESSAGE_AREA)) +#define GEDIT_MESSAGE_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GEDIT_TYPE_MESSAGE_AREA, GeditMessageAreaClass)) + +/* Private structure type */ +typedef struct _GeditMessageAreaPrivate GeditMessageAreaPrivate; + +/* + * Main object structure + */ +typedef struct _GeditMessageArea GeditMessageArea; + +struct _GeditMessageArea +{ + GtkHBox parent; + + /*< private > */ + GeditMessageAreaPrivate *priv; +}; + +/* + * Class definition + */ +typedef struct _GeditMessageAreaClass GeditMessageAreaClass; + +struct _GeditMessageAreaClass +{ + GtkHBoxClass parent_class; + + /* Signals */ + void (* response) (GeditMessageArea *message_area, gint response_id); + + /* Keybinding signals */ + void (* close) (GeditMessageArea *message_area); + + /* Padding for future expansion */ + void (*_gedit_reserved1) (void); + void (*_gedit_reserved2) (void); +}; + +/* + * Public methods + */ +GType gedit_message_area_get_type (void) G_GNUC_CONST; + +GtkWidget *gedit_message_area_new (void); + +GtkWidget *gedit_message_area_new_with_buttons (const gchar *first_button_text, + ...); + +void gedit_message_area_set_contents (GeditMessageArea *message_area, + GtkWidget *contents); + +void gedit_message_area_add_action_widget (GeditMessageArea *message_area, + GtkWidget *child, + gint response_id); + +GtkWidget *gedit_message_area_add_button (GeditMessageArea *message_area, + const gchar *button_text, + gint response_id); + +GtkWidget *gedit_message_area_add_stock_button_with_text + (GeditMessageArea *message_area, + const gchar *text, + const gchar *stock_id, + gint response_id); + +void gedit_message_area_add_buttons (GeditMessageArea *message_area, + const gchar *first_button_text, + ...); +void gedit_message_area_add_buttons_valist (GeditMessageArea *message_area, + const gchar *first_button_text, + va_list args); + +void gedit_message_area_set_response_sensitive + (GeditMessageArea *message_area, + gint response_id, + gboolean setting); +void gedit_message_area_set_default_response + (GeditMessageArea *message_area, + gint response_id); + +/* Emit response signal */ +void gedit_message_area_response (GeditMessageArea *message_area, + gint response_id); + +G_END_DECLS + +#endif /* __GEDIT_MESSAGE_AREA_H__ */ diff --git a/shell/Makefile.am b/shell/Makefile.am index 34dc0ff..973882b 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -4,6 +4,7 @@ INCLUDES= \ -I$(top_srcdir)/cut-n-paste/zoom-control/ \ -I$(top_srcdir)/cut-n-paste/toolbar-editor/ \ -I$(top_srcdir)/cut-n-paste/totem-screensaver/ \ + -I$(top_srcdir)/cut-n-paste/gedit-message-area/ \ -I$(top_srcdir)/libdocument \ -I$(top_srcdir)/properties \ -DGNOMELOCALEDIR=\"$(datadir)/locale\" \ @@ -29,6 +30,8 @@ evince_SOURCES= \ ev-history.h \ ev-marshal.c \ ev-marshal.h \ + ev-message-area.c \ + ev-message-area.h \ ev-metadata-manager.c \ ev-metadata-manager.h \ ev-navigation-action.c \ @@ -89,13 +92,14 @@ evince_SOURCES+= \ endif -evince_LDADD= \ - $(top_builddir)/cut-n-paste/zoom-control/libephyzoom.la \ - $(top_builddir)/cut-n-paste/toolbar-editor/libtoolbareditor.la \ +evince_LDADD= \ + $(top_builddir)/cut-n-paste/zoom-control/libephyzoom.la \ + $(top_builddir)/cut-n-paste/toolbar-editor/libtoolbareditor.la \ $(top_builddir)/cut-n-paste/totem-screensaver/libtotemscrsaver.la \ - $(top_builddir)/properties/libevproperties.la \ - $(top_builddir)/libdocument/libevbackend.la \ - $(SHELL_LIBS) \ + $(top_builddir)/cut-n-paste/gedit-message-area/libgeditmsgarea.la \ + $(top_builddir)/properties/libevproperties.la \ + $(top_builddir)/libdocument/libevbackend.la \ + $(SHELL_LIBS) \ $(GNOME_PRINT_LIBS) if ENABLE_DJVU diff --git a/shell/ev-message-area.c b/shell/ev-message-area.c new file mode 100644 index 0000000..93e227d --- /dev/null +++ b/shell/ev-message-area.c @@ -0,0 +1,324 @@ +/* ev-message-area.c + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2007 Carlos Garcia Campos + * + * Author: + * Carlos Garcia Campos + * + * Evince 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. + * + * Evince 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 +#include +#include +#include +#include +#include + +#include "ev-message-area.h" + +#define EV_MESSAGE_AREA_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EV_TYPE_MESSAGE_AREA, EvMessageAreaPrivate)) + +struct _EvMessageAreaPrivate { + GtkWidget *image; + GtkWidget *label; + GtkWidget *secondary_label; + + guint message_type : 3; +}; + +enum { + PROP_0, + PROP_MESSAGE_TYPE, + PROP_TEXT, + PROP_SECONDARY_TEXT, + PROP_IMAGE +}; + +static void ev_message_area_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void ev_message_area_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +G_DEFINE_TYPE (EvMessageArea, ev_message_area, GEDIT_TYPE_MESSAGE_AREA) + +static void +ev_message_area_class_init (EvMessageAreaClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + gobject_class->set_property = ev_message_area_set_property; + gobject_class->get_property = ev_message_area_get_property; + + g_object_class_install_property (gobject_class, + PROP_MESSAGE_TYPE, + g_param_spec_enum ("message-type", + "Message Type", + "The type of message", + GTK_TYPE_MESSAGE_TYPE, + GTK_MESSAGE_INFO, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (gobject_class, + PROP_TEXT, + g_param_spec_string ("text", + "Text", + "The primary text of the message dialog", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_SECONDARY_TEXT, + g_param_spec_string ("secondary-text", + "Secondary Text", + "The secondary text of the message dialog", + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_IMAGE, + g_param_spec_object ("image", + "Image", + "The image", + GTK_TYPE_WIDGET, + G_PARAM_READWRITE)); + + g_type_class_add_private (gobject_class, sizeof (EvMessageAreaPrivate)); +} + +static void +ev_message_area_init (EvMessageArea *area) +{ + GtkWidget *hbox, *vbox; + + area->priv = EV_MESSAGE_AREA_GET_PRIVATE (area); + + hbox = gtk_hbox_new (FALSE, 12); + vbox = gtk_vbox_new (FALSE, 12); + + area->priv->label = gtk_label_new (NULL); + gtk_label_set_use_markup (GTK_LABEL (area->priv->label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (area->priv->label), TRUE); + gtk_label_set_selectable (GTK_LABEL (area->priv->label), TRUE); + gtk_misc_set_alignment (GTK_MISC (area->priv->label), 0.0, 0.5); + GTK_WIDGET_SET_FLAGS (area->priv->label, GTK_CAN_FOCUS); + gtk_box_pack_start (GTK_BOX (vbox), area->priv->label, TRUE, TRUE, 0); + gtk_widget_show (area->priv->label); + + area->priv->secondary_label = gtk_label_new (NULL); + gtk_label_set_use_markup (GTK_LABEL (area->priv->secondary_label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (area->priv->secondary_label), TRUE); + gtk_label_set_selectable (GTK_LABEL (area->priv->secondary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (area->priv->secondary_label), 0.0, 0.5); + GTK_WIDGET_SET_FLAGS (area->priv->secondary_label, GTK_CAN_FOCUS); + gtk_box_pack_start (GTK_BOX (vbox), area->priv->secondary_label, TRUE, TRUE, 0); + + area->priv->image = gtk_image_new_from_stock (NULL, GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (area->priv->image), 0.5, 0.0); + gtk_box_pack_start (GTK_BOX (hbox), area->priv->image, FALSE, FALSE, 0); + gtk_widget_show (area->priv->image); + + gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); + gtk_widget_show (vbox); + + gedit_message_area_set_contents (GEDIT_MESSAGE_AREA (area), hbox); + gtk_widget_show (hbox); +} + +static void +ev_message_area_set_image_for_type (EvMessageArea *area, + GtkMessageType type) +{ + const gchar *stock_id = NULL; + AtkObject *atk_obj; + + switch (type) { + case GTK_MESSAGE_INFO: + stock_id = GTK_STOCK_DIALOG_INFO; + break; + case GTK_MESSAGE_QUESTION: + stock_id = GTK_STOCK_DIALOG_QUESTION; + break; + case GTK_MESSAGE_WARNING: + stock_id = GTK_STOCK_DIALOG_WARNING; + break; + case GTK_MESSAGE_ERROR: + stock_id = GTK_STOCK_DIALOG_ERROR; + break; + case GTK_MESSAGE_OTHER: + break; + default: + g_warning ("Unknown GtkMessageType %u", type); + break; + } + + if (stock_id) + gtk_image_set_from_stock (GTK_IMAGE (area->priv->image), stock_id, + GTK_ICON_SIZE_DIALOG); + + atk_obj = gtk_widget_get_accessible (GTK_WIDGET (area)); + if (GTK_IS_ACCESSIBLE (atk_obj)) { + atk_object_set_role (atk_obj, ATK_ROLE_ALERT); + if (stock_id) { + GtkStockItem item; + + gtk_stock_lookup (stock_id, &item); + atk_object_set_name (atk_obj, item.label); + } + } +} + +static void +ev_message_area_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EvMessageArea *area = EV_MESSAGE_AREA (object); + + switch (prop_id) { + case PROP_MESSAGE_TYPE: + area->priv->message_type = g_value_get_enum (value); + ev_message_area_set_image_for_type (area, area->priv->message_type); + break; + case PROP_TEXT: + ev_message_area_set_text (area, g_value_get_string (value)); + break; + case PROP_SECONDARY_TEXT: + ev_message_area_set_secondary_text (area, g_value_get_string (value)); + break; + case PROP_IMAGE: + ev_message_area_set_image (area, (GtkWidget *)g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +ev_message_area_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EvMessageArea *area = EV_MESSAGE_AREA (object); + + switch (prop_id) { + case PROP_MESSAGE_TYPE: + g_value_set_enum (value, (GtkMessageType) area->priv->message_type); + break; + case PROP_TEXT: + g_value_set_string (value, gtk_label_get_label (GTK_LABEL (area->priv->label))); + break; + case PROP_SECONDARY_TEXT: + g_value_set_string (value, gtk_label_get_label (GTK_LABEL (area->priv->secondary_label))); + break; + case PROP_IMAGE: + g_value_set_object (value, area->priv->image); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +GtkWidget * +ev_message_area_new (GtkMessageType type, + const gchar *text, + const gchar *first_button_text, + ...) +{ + GtkWidget *widget; + + widget = g_object_new (EV_TYPE_MESSAGE_AREA, + "message-type", type, + "text", text, + NULL); + if (first_button_text) { + va_list args; + + va_start (args, first_button_text); + gedit_message_area_add_buttons_valist (GEDIT_MESSAGE_AREA (widget), + first_button_text, + args); + va_end (args); + } + + return widget; +} + +void +ev_message_area_set_image (EvMessageArea *area, + GtkWidget *image) +{ + GtkWidget *parent; + + g_return_if_fail (EV_IS_MESSAGE_AREA (area)); + + area->priv->message_type = GTK_MESSAGE_OTHER; + + parent = area->priv->image->parent; + gtk_container_add (GTK_CONTAINER (parent), image); + gtk_container_remove (GTK_CONTAINER (parent), area->priv->image); + gtk_box_reorder_child (GTK_BOX (parent), image, 0); + + area->priv->image = image; + + g_object_notify (G_OBJECT (area), "image"); +} + +void +ev_message_area_set_text (EvMessageArea *area, + const gchar *str) +{ + g_return_if_fail (EV_IS_MESSAGE_AREA (area)); + + if (str) { + gchar *msg; + + msg = g_strdup_printf ("%s", str); + gtk_label_set_markup (GTK_LABEL (area->priv->label), msg); + g_free (msg); + } else { + gtk_label_set_markup (GTK_LABEL (area->priv->label), NULL); + } + + g_object_notify (G_OBJECT (area), "text"); +} + +void +ev_message_area_set_secondary_text (EvMessageArea *area, + const gchar *str) +{ + g_return_if_fail (EV_IS_MESSAGE_AREA (area)); + + if (str) { + gchar *msg; + + msg = g_strdup_printf ("%s", str); + gtk_label_set_markup (GTK_LABEL (area->priv->secondary_label), msg); + g_free (msg); + gtk_widget_show (area->priv->secondary_label); + } else { + gtk_label_set_markup (GTK_LABEL (area->priv->secondary_label), NULL); + gtk_widget_hide (area->priv->secondary_label); + } + + g_object_notify (G_OBJECT (area), "secondary-text"); +} diff --git a/shell/ev-message-area.h b/shell/ev-message-area.h new file mode 100644 index 0000000..bb29545 --- /dev/null +++ b/shell/ev-message-area.h @@ -0,0 +1,69 @@ +/* ev-message-area.h + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2007 Carlos Garcia Campos + * + * Author: + * Carlos Garcia Campos + * + * Evince 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. + * + * Evince 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. + */ + +#ifndef EV_MESSAGE_AREA_H +#define EV_MESSAGE_AREA_H + +#include + +#include "gedit-message-area.h" + +G_BEGIN_DECLS + +#define EV_TYPE_MESSAGE_AREA (ev_message_area_get_type ()) +#define EV_MESSAGE_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_MESSAGE_AREA, EvMessageArea)) +#define EV_MESSAGE_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_MESSAGE_AREA, EvMessageAreaClass)) +#define EV_IS_MESSAGE_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_MESSAGE_AREA)) +#define EV_IS_MESSAGE_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_MESSAGE_AREA)) +#define EV_MESSAGE_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_MESSAGE_AREA, EvMessageAreaClass)) + +typedef struct _EvMessageArea EvMessageArea; +typedef struct _EvMessageAreaClass EvMessageAreaClass; +typedef struct _EvMessageAreaPrivate EvMessageAreaPrivate; + +struct _EvMessageArea { + GeditMessageArea parent_instance; + + /*< private >*/ + EvMessageAreaPrivate *priv; +}; + +struct _EvMessageAreaClass { + GeditMessageAreaClass parent_class; +}; + +GType ev_message_area_get_type (void) G_GNUC_CONST; +GtkWidget *ev_message_area_new (GtkMessageType type, + const gchar *text, + const gchar *first_button_text, + ...); +void ev_message_area_set_image (EvMessageArea *area, + GtkWidget *image); +void ev_message_area_set_text (EvMessageArea *area, + const gchar *str); +void ev_message_area_set_secondary_text (EvMessageArea *area, + const gchar *str); + +G_END_DECLS + +#endif /* EV_MESSAGE_AREA_H */ diff --git a/shell/ev-window.c b/shell/ev-window.c index ed568f9..ca2a14e 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -91,6 +91,8 @@ #include #include +#include "ev-message-area.h" + #if !GLIB_CHECK_VERSION (2, 13, 3) char *xdg_user_dir_lookup (char *type); #endif @@ -119,10 +121,12 @@ struct _EvWindowPrivate { GtkWidget *menubar; GtkWidget *toolbar; GtkWidget *hpaned; + GtkWidget *view_box; GtkWidget *sidebar; GtkWidget *find_bar; GtkWidget *scrolled_window; GtkWidget *view; + GtkWidget *message_area; GtkWidget *password_view; GtkWidget *sidebar_thumbs; GtkWidget *sidebar_links; @@ -624,29 +628,55 @@ ev_window_is_empty (const EvWindow *ev_window) } static void -ev_window_error_dialog_response_cb (GtkWidget *dialog, - gint response_id, - EvWindow *ev_window) +ev_window_set_message_area (EvWindow *window, + GtkWidget *area) { - gtk_widget_destroy (dialog); + if (window->priv->message_area == area) + return; + + if (window->priv->message_area) + gtk_widget_destroy (window->priv->message_area); + window->priv->message_area = area; + + if (!area) + return; + + gtk_box_pack_start (GTK_BOX (window->priv->view_box), + window->priv->message_area, + FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (window->priv->view_box), + window->priv->message_area, 0); + g_object_add_weak_pointer (G_OBJECT (window->priv->message_area), + (gpointer) &(window->priv->message_area)); } static void -ev_window_error_dialog (GtkWindow *window, const gchar *msg, GError *error) +ev_window_error_message_response_cb (EvMessageArea *area, + gint response_id, + EvWindow *window) { - GtkWidget *dialog; + ev_window_set_message_area (window, NULL); +} - dialog = gtk_message_dialog_new (GTK_WINDOW (window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - msg); - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - "%s", error->message); - g_signal_connect (dialog, "response", - G_CALLBACK (ev_window_error_dialog_response_cb), - window); - gtk_widget_show (dialog); +static void +ev_window_error_message (GtkWindow *window, const gchar *msg, GError *error) +{ + GtkWidget *area; + + if (EV_WINDOW (window)->priv->message_area) + return; + + area = ev_message_area_new (GTK_MESSAGE_ERROR, + msg, + GTK_STOCK_CLOSE, + GTK_RESPONSE_CANCEL, + NULL); + ev_message_area_set_secondary_text (EV_MESSAGE_AREA (area), error->message); + g_signal_connect (area, "response", + G_CALLBACK (ev_window_error_message_response_cb), + window); + gtk_widget_show (area); + ev_window_set_message_area (EV_WINDOW (window), area); } static void @@ -1149,6 +1179,8 @@ ev_window_set_document (EvWindow *ev_window, EvDocument *document) if (ev_window->priv->document) g_object_unref (ev_window->priv->document); ev_window->priv->document = g_object_ref (document); + + ev_window_set_message_area (ev_window, NULL); ev_window->priv->page_cache = ev_page_cache_get (ev_window->priv->document); g_signal_connect (ev_window->priv->page_cache, "page-changed", @@ -1384,9 +1416,9 @@ ev_window_load_job_cb (EvJobLoad *job, ev_window_popup_password_dialog (ev_window); } else { - ev_window_error_dialog (GTK_WINDOW (ev_window), - _("Unable to open document"), - job->error); + ev_window_error_message (GTK_WINDOW (ev_window), + _("Unable to open document"), + job->error); ev_window_clear_load_job (ev_window); ev_window->priv->in_reload = FALSE; } @@ -1679,9 +1711,9 @@ ev_window_cmd_file_open_copy_at_dest (EvWindow *window, EvLinkDest *dest) new_filename = ev_window_create_tmp_symlink (old_filename, &error); if (error) { - ev_window_error_dialog (GTK_WINDOW (window), - _("Cannot open a copy."), - error); + ev_window_error_message (GTK_WINDOW (window), + _("Cannot open a copy."), + error); g_error_free (error); g_free (old_filename); @@ -1998,7 +2030,7 @@ ev_window_save_job_cb (EvJobSave *job, gchar *msg; msg = g_strdup_printf (_("The file could not be saved as ā€œ%sā€."), job->uri); - ev_window_error_dialog (GTK_WINDOW (window), msg, job->error); + ev_window_error_message (GTK_WINDOW (window), msg, job->error); g_free (msg); } @@ -4960,9 +4992,9 @@ image_save_dialog_response_cb (GtkWidget *fc, filename, "png", &error, NULL); if (error) { - ev_window_error_dialog (GTK_WINDOW (ev_window), - _("The image could not be saved."), - error); + ev_window_error_message (GTK_WINDOW (ev_window), + _("The image could not be saved."), + error); g_error_free (error); g_free (filename); gnome_vfs_uri_unref (target_uri); @@ -5051,9 +5083,9 @@ ev_attachment_popup_cmd_open_attachment (GtkAction *action, EvWindow *window) ev_attachment_open (attachment, &error); if (error) { - ev_window_error_dialog (GTK_WINDOW (window), - _("Unable to open attachment"), - error); + ev_window_error_message (GTK_WINDOW (window), + _("Unable to open attachment"), + error); g_error_free (error); } } @@ -5104,9 +5136,9 @@ attachment_save_dialog_response_cb (GtkWidget *fc, ev_attachment_save (attachment, filename, &error); if (error) { - ev_window_error_dialog (GTK_WINDOW (ev_window), - _("The attachment could not be saved."), - error); + ev_window_error_message (GTK_WINDOW (ev_window), + _("The attachment could not be saved."), + error); g_error_free (error); g_free (filename); @@ -5338,14 +5370,19 @@ ev_window_init (EvWindow *ev_window) ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar), sidebar_widget); + ev_window->priv->view_box = gtk_vbox_new (FALSE, 0); ev_window->priv->scrolled_window = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW, "shadow-type", GTK_SHADOW_IN, NULL)); + gtk_box_pack_start (GTK_BOX (ev_window->priv->view_box), + ev_window->priv->scrolled_window, + TRUE, TRUE, 0); gtk_widget_show (ev_window->priv->scrolled_window); gtk_paned_add2 (GTK_PANED (ev_window->priv->hpaned), - ev_window->priv->scrolled_window); + ev_window->priv->view_box); + gtk_widget_show (ev_window->priv->view_box); ev_window->priv->view = ev_view_new (); ev_view_set_screen_dpi (EV_VIEW (ev_window->priv->view), -- cgit v0.9.1