1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
3 *
4 * gimperrorconsole.c
5 * Copyright (C) 2003 Michael Natterer <mitch@gimp.org>
6 *
7 * partly based on errorconsole.c
8 * Copyright (C) 1998 Nick Fetchak <nuke@bayside.net>
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24 #include "config.h"
25
26 #include <gegl.h>
27 #include <gtk/gtk.h>
28
29 #include "libgimpbase/gimpbase.h"
30 #include "libgimpwidgets/gimpwidgets.h"
31
32 #include "widgets-types.h"
33
34 #include "core/gimp.h"
35
36 #include "gimpdocked.h"
37 #include "gimperrorconsole.h"
38 #include "gimpmenufactory.h"
39 #include "gimpsessioninfo-aux.h"
40 #include "gimptextbuffer.h"
41 #include "gimpwidgets-utils.h"
42
43 #include "gimp-intl.h"
44
45
46 static const gboolean default_highlight[] =
47 {
48 [GIMP_MESSAGE_ERROR] = TRUE,
49 [GIMP_MESSAGE_WARNING] = TRUE,
50 [GIMP_MESSAGE_INFO] = FALSE
51 };
52
53
54 static void gimp_error_console_docked_iface_init (GimpDockedInterface *iface);
55
56 static void gimp_error_console_constructed (GObject *object);
57 static void gimp_error_console_dispose (GObject *object);
58
59 static void gimp_error_console_unmap (GtkWidget *widget);
60
61 static gboolean gimp_error_console_button_press (GtkWidget *widget,
62 GdkEventButton *event,
63 GimpErrorConsole *console);
64
65 static void gimp_error_console_set_aux_info (GimpDocked *docked,
66 GList *aux_info);
67 static GList * gimp_error_console_get_aux_info (GimpDocked *docked);
68
69
70 G_DEFINE_TYPE_WITH_CODE (GimpErrorConsole, gimp_error_console, GIMP_TYPE_EDITOR,
71 G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,
72 gimp_error_console_docked_iface_init))
73
74 #define parent_class gimp_error_console_parent_class
75
76 static GimpDockedInterface *parent_docked_iface = NULL;
77
78
79 static void
gimp_error_console_class_init(GimpErrorConsoleClass * klass)80 gimp_error_console_class_init (GimpErrorConsoleClass *klass)
81 {
82 GObjectClass *object_class = G_OBJECT_CLASS (klass);
83 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
84
85 object_class->constructed = gimp_error_console_constructed;
86 object_class->dispose = gimp_error_console_dispose;
87
88 widget_class->unmap = gimp_error_console_unmap;
89 }
90
91 static void
gimp_error_console_init(GimpErrorConsole * console)92 gimp_error_console_init (GimpErrorConsole *console)
93 {
94 GtkWidget *scrolled_window;
95
96 console->text_buffer = GTK_TEXT_BUFFER (gimp_text_buffer_new ());
97
98 gtk_text_buffer_create_tag (console->text_buffer, "title",
99 "scale", PANGO_SCALE_LARGE,
100 "weight", PANGO_WEIGHT_BOLD,
101 NULL);
102 gtk_text_buffer_create_tag (console->text_buffer, "message",
103 NULL);
104
105 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
106 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
107 GTK_POLICY_AUTOMATIC,
108 GTK_POLICY_AUTOMATIC);
109 gtk_box_pack_start (GTK_BOX (console), scrolled_window, TRUE, TRUE, 0);
110 gtk_widget_show (scrolled_window);
111
112 console->text_view = gtk_text_view_new_with_buffer (console->text_buffer);
113 g_object_unref (console->text_buffer);
114
115 gtk_text_view_set_editable (GTK_TEXT_VIEW (console->text_view), FALSE);
116 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (console->text_view),
117 GTK_WRAP_WORD);
118 gtk_container_add (GTK_CONTAINER (scrolled_window), console->text_view);
119 gtk_widget_show (console->text_view);
120
121 g_signal_connect (console->text_view, "button-press-event",
122 G_CALLBACK (gimp_error_console_button_press),
123 console);
124
125 console->file_dialog = NULL;
126
127 memcpy (console->highlight, default_highlight, sizeof (default_highlight));
128 }
129
130 static void
gimp_error_console_docked_iface_init(GimpDockedInterface * iface)131 gimp_error_console_docked_iface_init (GimpDockedInterface *iface)
132 {
133 parent_docked_iface = g_type_interface_peek_parent (iface);
134
135 if (! parent_docked_iface)
136 parent_docked_iface = g_type_default_interface_peek (GIMP_TYPE_DOCKED);
137
138 iface->set_aux_info = gimp_error_console_set_aux_info;
139 iface->get_aux_info = gimp_error_console_get_aux_info;
140 }
141
142 static void
gimp_error_console_constructed(GObject * object)143 gimp_error_console_constructed (GObject *object)
144 {
145 GimpErrorConsole *console = GIMP_ERROR_CONSOLE (object);
146
147 G_OBJECT_CLASS (parent_class)->constructed (object);
148
149 console->clear_button =
150 gimp_editor_add_action_button (GIMP_EDITOR (console), "error-console",
151 "error-console-clear", NULL);
152
153 console->save_button =
154 gimp_editor_add_action_button (GIMP_EDITOR (console), "error-console",
155 "error-console-save-all",
156 "error-console-save-selection",
157 GDK_SHIFT_MASK,
158 NULL);
159 }
160
161 static void
gimp_error_console_dispose(GObject * object)162 gimp_error_console_dispose (GObject *object)
163 {
164 GimpErrorConsole *console = GIMP_ERROR_CONSOLE (object);
165
166 if (console->file_dialog)
167 gtk_widget_destroy (console->file_dialog);
168
169 console->gimp->message_handler = GIMP_MESSAGE_BOX;
170
171 G_OBJECT_CLASS (parent_class)->dispose (object);
172 }
173
174 static void
gimp_error_console_unmap(GtkWidget * widget)175 gimp_error_console_unmap (GtkWidget *widget)
176 {
177 GimpErrorConsole *console = GIMP_ERROR_CONSOLE (widget);
178
179 if (console->file_dialog)
180 gtk_widget_destroy (console->file_dialog);
181
182 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
183 }
184
185 GtkWidget *
gimp_error_console_new(Gimp * gimp,GimpMenuFactory * menu_factory)186 gimp_error_console_new (Gimp *gimp,
187 GimpMenuFactory *menu_factory)
188 {
189 GimpErrorConsole *console;
190
191 g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
192 g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
193
194 console = g_object_new (GIMP_TYPE_ERROR_CONSOLE,
195 "menu-factory", menu_factory,
196 "menu-identifier", "<ErrorConsole>",
197 "ui-path", "/error-console-popup",
198 NULL);
199
200 console->gimp = gimp;
201
202 console->gimp->message_handler = GIMP_ERROR_CONSOLE;
203
204 return GTK_WIDGET (console);
205 }
206
207 void
gimp_error_console_add(GimpErrorConsole * console,GimpMessageSeverity severity,const gchar * domain,const gchar * message)208 gimp_error_console_add (GimpErrorConsole *console,
209 GimpMessageSeverity severity,
210 const gchar *domain,
211 const gchar *message)
212 {
213 const gchar *desc;
214 GtkTextIter end;
215 GtkTextMark *end_mark;
216 GdkPixbuf *pixbuf;
217 gchar *str;
218
219 g_return_if_fail (GIMP_IS_ERROR_CONSOLE (console));
220 g_return_if_fail (domain != NULL);
221 g_return_if_fail (message != NULL);
222
223 gimp_enum_get_value (GIMP_TYPE_MESSAGE_SEVERITY, severity,
224 NULL, NULL, &desc, NULL);
225
226 gtk_text_buffer_get_end_iter (console->text_buffer, &end);
227
228 pixbuf = gimp_widget_load_icon (GTK_WIDGET (console),
229 gimp_get_message_icon_name (severity), 20);
230 gtk_text_buffer_insert_pixbuf (console->text_buffer, &end, pixbuf);
231 g_object_unref (pixbuf);
232
233 gtk_text_buffer_insert (console->text_buffer, &end, " ", -1);
234
235 str = g_strdup_printf ("%s %s", domain, desc);
236 gtk_text_buffer_insert_with_tags_by_name (console->text_buffer, &end,
237 str, -1,
238 "title",
239 NULL);
240 g_free (str);
241
242 gtk_text_buffer_insert (console->text_buffer, &end, "\n", -1);
243
244 gtk_text_buffer_insert_with_tags_by_name (console->text_buffer, &end,
245 message, -1,
246 "message",
247 NULL);
248
249 gtk_text_buffer_insert (console->text_buffer, &end, "\n\n", -1);
250
251 end_mark = gtk_text_buffer_create_mark (console->text_buffer,
252 NULL, &end, TRUE);
253 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (console->text_view), end_mark,
254 FALSE, TRUE, 1.0, 0.0);
255 gtk_text_buffer_delete_mark (console->text_buffer, end_mark);
256 }
257
258
259 /* private functions */
260
261 static gboolean
gimp_error_console_button_press(GtkWidget * widget,GdkEventButton * bevent,GimpErrorConsole * console)262 gimp_error_console_button_press (GtkWidget *widget,
263 GdkEventButton *bevent,
264 GimpErrorConsole *console)
265 {
266 if (gdk_event_triggers_context_menu ((GdkEvent *) bevent))
267 {
268 return gimp_editor_popup_menu (GIMP_EDITOR (console), NULL, NULL);
269 }
270
271 return FALSE;
272 }
273
274 static const gchar * const aux_info_highlight[] =
275 {
276 [GIMP_MESSAGE_ERROR] = "highlight-error",
277 [GIMP_MESSAGE_WARNING] = "highlight-warning",
278 [GIMP_MESSAGE_INFO] = "highlight-info"
279 };
280
281 static void
gimp_error_console_set_aux_info(GimpDocked * docked,GList * aux_info)282 gimp_error_console_set_aux_info (GimpDocked *docked,
283 GList *aux_info)
284 {
285 GimpErrorConsole *console = GIMP_ERROR_CONSOLE (docked);
286 GList *list;
287
288 parent_docked_iface->set_aux_info (docked, aux_info);
289
290 for (list = aux_info; list; list = g_list_next (list))
291 {
292 GimpSessionInfoAux *aux = list->data;
293 gint i;
294
295 for (i = 0; i < G_N_ELEMENTS (aux_info_highlight); i++)
296 {
297 if (! strcmp (aux->name, aux_info_highlight[i]))
298 {
299 console->highlight[i] = ! strcmp (aux->value, "yes");
300 break;
301 }
302 }
303 }
304 }
305
306 static GList *
gimp_error_console_get_aux_info(GimpDocked * docked)307 gimp_error_console_get_aux_info (GimpDocked *docked)
308 {
309 GimpErrorConsole *console = GIMP_ERROR_CONSOLE (docked);
310 GList *aux_info;
311 gint i;
312
313 aux_info = parent_docked_iface->get_aux_info (docked);
314
315 for (i = 0; i < G_N_ELEMENTS (aux_info_highlight); i++)
316 {
317 GimpSessionInfoAux *aux;
318
319 aux = gimp_session_info_aux_new (aux_info_highlight[i],
320 console->highlight[i] ? "yes" : "no");
321
322 aux_info = g_list_append (aux_info, aux);
323 }
324
325 return aux_info;
326 }
327