1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * gedit-output_window.c
4 * This file is part of gedit
6 * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
7 * Copyright (C) 2000, 2002 Chema Celorio, Paolo Maggi
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330,
22 * Boston, MA 02111-1307, USA.
26 * Modified by the gedit Team, 1998-2002. See the AUTHORS file for a
27 * list of people on the gedit Team.
28 * See the ChangeLog files for a list of changes.
36 #include <gdk/gdkkeysyms.h>
37 #include <glib/gi18n.h>
39 #include "gedit-output-window.h"
41 struct _GeditOutputWindowPrivate
43 GtkWidget *close_button;
44 GtkWidget *copy_button;
45 GtkWidget *clear_button;
47 GtkWidget *close_menu_item;
48 GtkWidget *copy_menu_item;
49 GtkWidget *clear_menu_item;
61 static guint signals [LAST_SIGNAL];
70 static void gedit_output_window_finalize (GObject *object);
71 static void gedit_output_window_destroy (GtkObject *object);
73 G_DEFINE_TYPE(GeditOutputWindow, gedit_output_window, GTK_TYPE_HBOX)
76 gedit_output_window_class_init (GeditOutputWindowClass *klass)
78 GObjectClass *object_class = G_OBJECT_CLASS (klass);
80 object_class->finalize = gedit_output_window_finalize;
82 GTK_OBJECT_CLASS (klass)->destroy = gedit_output_window_destroy;
84 signals[CLOSE_REQUESTED] =
85 g_signal_new ("close_requested",
86 G_OBJECT_CLASS_TYPE (object_class),
88 G_STRUCT_OFFSET (GeditOutputWindowClass, close_requested),
91 g_cclosure_marshal_VOID__VOID,
94 signals[SELECTION_CHANGED] =
95 g_signal_new ("selection_changed",
96 G_OBJECT_CLASS_TYPE (object_class),
98 G_STRUCT_OFFSET (GeditOutputWindowClass, selection_changed),
101 g_cclosure_marshal_VOID__STRING,
108 gedit_output_window_copy_selection (GeditOutputWindow *ow)
112 GtkTreeSelection *selection;
114 GString *string = NULL;
116 g_return_if_fail (GEDIT_IS_OUTPUT_WINDOW (ow));
118 selection = gtk_tree_view_get_selection (
119 GTK_TREE_VIEW (ow->priv->treeview));
121 ret = gtk_tree_model_get_iter_first (ow->priv->model, &iter);
125 if (gtk_tree_selection_iter_is_selected (selection, &iter))
129 gtk_tree_model_get (ow->priv->model, &iter, COLUMN_LINES, &line, -1);
132 string = g_string_new (line);
134 string = g_string_append (string, line);
136 string = g_string_append_c (string, '\n');
141 ret = gtk_tree_model_iter_next (ow->priv->model, &iter);
148 pango_parse_markup (string->str, string->len, 0, NULL, &text, NULL, NULL);
150 gtk_clipboard_set_text (gtk_widget_get_clipboard (
151 GTK_WIDGET (ow), GDK_SELECTION_CLIPBOARD),
158 g_string_free (string, TRUE);
162 close_clicked_callback (GtkWidget *widget, gpointer user_data)
164 GeditOutputWindow *ow;
166 ow = GEDIT_OUTPUT_WINDOW (user_data);
168 g_signal_emit (ow, signals [CLOSE_REQUESTED], 0);
172 clear_clicked_callback (GtkWidget *widget, gpointer user_data)
174 GeditOutputWindow *ow;
176 ow = GEDIT_OUTPUT_WINDOW (user_data);
178 gedit_output_window_clear (ow);
182 copy_clicked_callback (GtkWidget *widget, gpointer user_data)
184 GeditOutputWindow *ow;
186 ow = GEDIT_OUTPUT_WINDOW (user_data);
188 gedit_output_window_copy_selection (ow);
192 gedit_output_window_key_press_event_cb (GtkTreeView *widget, GdkEventKey *event,
193 GeditOutputWindow *ow)
195 if (event->keyval == GDK_Delete)
197 gedit_output_window_clear (ow);
201 if (event->keyval == 'c')
203 gedit_output_window_copy_selection (ow);
211 create_popup_menu (GeditOutputWindow *output_window)
214 GtkWidget *menu_item;
216 menu = gtk_menu_new ();
218 /* Add the clear button */
219 output_window->priv->clear_menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLEAR, NULL);
220 gtk_widget_show (output_window->priv->clear_menu_item);
221 g_signal_connect (G_OBJECT (output_window->priv->clear_menu_item), "activate",
222 G_CALLBACK (clear_clicked_callback), output_window);
223 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), output_window->priv->clear_menu_item);
225 /* Add the copy button */
226 output_window->priv->copy_menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_COPY, NULL);
227 gtk_widget_show (output_window->priv->copy_menu_item);
228 g_signal_connect (G_OBJECT (output_window->priv->copy_menu_item), "activate",
229 G_CALLBACK (copy_clicked_callback), output_window);
230 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), output_window->priv->copy_menu_item);
232 /* Add the separator */
233 menu_item = gtk_separator_menu_item_new ();
234 gtk_widget_show (menu_item);
235 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
237 /* Add the close button */
238 output_window->priv->close_menu_item = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLOSE, NULL);
239 gtk_widget_show (output_window->priv->close_menu_item);
240 g_signal_connect (G_OBJECT (output_window->priv->close_menu_item), "activate",
241 G_CALLBACK (close_clicked_callback), output_window);
242 gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), output_window->priv->close_menu_item);
244 gtk_widget_set_sensitive (output_window->priv->copy_menu_item, FALSE);
245 gtk_widget_set_sensitive (output_window->priv->clear_menu_item, FALSE);
251 my_popup_handler (GtkWidget *widget, GdkEvent *event)
254 GdkEventButton *event_button;
256 g_return_val_if_fail (widget != NULL, FALSE);
257 g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
258 g_return_val_if_fail (event != NULL, FALSE);
260 /* The "widget" is the menu that was supplied when
261 * g_signal_connect_swapped() was called.
263 menu = GTK_MENU (widget);
265 if (event->type == GDK_BUTTON_PRESS)
267 event_button = (GdkEventButton *) event;
268 if (event_button->button == 3)
270 gtk_menu_popup (menu, NULL, NULL, NULL, NULL,
271 event_button->button, event_button->time);
280 gedit_output_window_treeview_selection_changed (GtkTreeSelection *selection,
281 GeditOutputWindow *output_window)
288 g_return_if_fail (output_window != NULL);
289 g_return_if_fail (selection != NULL);
291 selected = (gtk_tree_selection_count_selected_rows (selection) > 0);
293 gtk_widget_set_sensitive (output_window->priv->copy_menu_item, selected);
294 gtk_widget_set_sensitive (output_window->priv->copy_button, selected);
296 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
297 gtk_tree_model_get (model, &iter, COLUMN_LINES, &line, -1);
298 g_signal_emit (output_window, signals [SELECTION_CHANGED], 0, line);
303 gedit_output_window_format_button (GtkButton* button, gint w, gint h)
305 GtkRcStyle* rc = gtk_widget_get_modifier_style (GTK_WIDGET (button));
308 gtk_widget_modify_style (GTK_WIDGET (button), rc);
309 gtk_button_set_relief (button, GTK_RELIEF_NONE);
310 gtk_button_set_focus_on_click (button, FALSE);
314 gedit_output_window_init (GeditOutputWindow *output_window)
316 GtkSettings *settings;
321 GtkWidget *vseparator;
323 GtkWidget *scrolledwindow;
324 GtkTreeViewColumn *column;
325 GtkCellRenderer *cell;
326 GtkTreeSelection *selection;
327 GtkWidget *popup_menu;
329 GList *focusable_widgets = NULL;
331 output_window->priv = g_new0 (GeditOutputWindowPrivate, 1);
333 settings = gtk_widget_get_settings (GTK_WIDGET (output_window));
335 gtk_icon_size_lookup_for_settings (settings,
339 vbox1 = gtk_vbox_new (FALSE, 2);
340 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
342 /* Create the close button */
343 output_window->priv->close_button = gtk_button_new ();
344 gtk_box_pack_start (GTK_BOX (vbox1), output_window->priv->close_button, FALSE, FALSE, 0);
346 gtk_widget_set_tooltip_text (output_window->priv->close_button,
347 _("Close the output window"));
349 gedit_output_window_format_button (GTK_BUTTON (output_window->priv->close_button), w, h);
351 image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
352 gtk_container_add (GTK_CONTAINER (output_window->priv->close_button), image);
354 g_signal_connect (output_window->priv->close_button,
356 G_CALLBACK (close_clicked_callback),
359 /* Create the 3 vertical separators */
360 hbox2 = gtk_hbox_new (TRUE, 0);
361 gtk_box_pack_start (GTK_BOX (vbox1), hbox2, TRUE, TRUE, 0);
362 gtk_container_set_border_width (GTK_CONTAINER (hbox2), 4);
364 vseparator = gtk_vseparator_new ();
365 gtk_box_pack_start (GTK_BOX (hbox2), vseparator, FALSE, FALSE, 0);
367 vseparator = gtk_vseparator_new ();
368 gtk_box_pack_start (GTK_BOX (hbox2), vseparator, FALSE, FALSE, 0);
370 vseparator = gtk_vseparator_new ();
371 gtk_box_pack_start (GTK_BOX (hbox2), vseparator, FALSE, TRUE, 0);
373 /* Create the vbox for the copy and clear buttons */
374 vbox2 = gtk_vbox_new (TRUE, 0);
375 gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, TRUE, 0);
377 /* Create the copy button */
378 output_window->priv->copy_button = gtk_button_new ();
379 gtk_box_pack_start (GTK_BOX (vbox2), output_window->priv->copy_button, FALSE, FALSE, 0);
381 gtk_widget_set_tooltip_text (output_window->priv->copy_button,
382 _("Copy selected lines"));
384 gedit_output_window_format_button (GTK_BUTTON (output_window->priv->copy_button), w, h);
386 image = gtk_image_new_from_stock (GTK_STOCK_COPY, GTK_ICON_SIZE_MENU);
387 gtk_container_add (GTK_CONTAINER (output_window->priv->copy_button), image);
389 g_signal_connect (output_window->priv->copy_button,
391 G_CALLBACK (copy_clicked_callback),
394 /* Create the clear button */
395 output_window->priv->clear_button = gtk_button_new ();
396 gtk_box_pack_start (GTK_BOX (vbox2), output_window->priv->clear_button, FALSE, FALSE, 0);
398 gtk_widget_set_tooltip_text (output_window->priv->clear_button,
399 _("Clear the output window"));
401 gedit_output_window_format_button (GTK_BUTTON (output_window->priv->clear_button), w, h);
403 image = gtk_image_new_from_stock (GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU);
404 gtk_container_add (GTK_CONTAINER (output_window->priv->clear_button), image);
406 g_signal_connect (output_window->priv->clear_button,
408 G_CALLBACK (clear_clicked_callback),
411 gtk_widget_set_sensitive (output_window->priv->copy_button, FALSE);
412 gtk_widget_set_sensitive (output_window->priv->clear_button, FALSE);
414 /* Create the scrolled window */
415 scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
417 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
418 GTK_POLICY_AUTOMATIC,
419 GTK_POLICY_AUTOMATIC);
421 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow),
422 GTK_SHADOW_ETCHED_IN);
424 output_window->priv->treeview = gtk_tree_view_new ();
425 gtk_container_add (GTK_CONTAINER (scrolledwindow), output_window->priv->treeview);
426 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (output_window->priv->treeview), FALSE);
430 output_window->priv->model = GTK_TREE_MODEL (
431 gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING));
433 gtk_tree_view_set_model (GTK_TREE_VIEW (output_window->priv->treeview),
434 output_window->priv->model);
436 /* Add the suggestions column */
437 cell = gtk_cell_renderer_text_new ();
438 column = gtk_tree_view_column_new_with_attributes (_("Output Lines"), cell,
439 "markup", COLUMN_LINES, NULL);
441 gtk_tree_view_append_column (GTK_TREE_VIEW (output_window->priv->treeview), column);
443 gtk_tree_view_set_search_column (GTK_TREE_VIEW (output_window->priv->treeview),
446 selection = gtk_tree_view_get_selection (
447 GTK_TREE_VIEW (output_window->priv->treeview));
449 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
451 gtk_box_pack_end (GTK_BOX (output_window), scrolledwindow, TRUE, TRUE, 0);
452 gtk_box_pack_start (GTK_BOX (output_window), vbox1, FALSE, FALSE, 0);
454 gtk_widget_set_size_request (GTK_WIDGET (output_window), 3 * w, 5 * (h + 2));
456 g_signal_connect (G_OBJECT (output_window->priv->treeview), "key_press_event",
457 G_CALLBACK (gedit_output_window_key_press_event_cb), output_window);
459 g_signal_connect (G_OBJECT (selection), "changed",
460 G_CALLBACK (gedit_output_window_treeview_selection_changed),
463 focusable_widgets = g_list_append (focusable_widgets, output_window->priv->treeview);
464 focusable_widgets = g_list_append (focusable_widgets, output_window->priv->close_button);
465 focusable_widgets = g_list_append (focusable_widgets, output_window->priv->copy_button);
466 focusable_widgets = g_list_append (focusable_widgets, output_window->priv->clear_button);
468 gtk_container_set_focus_chain (GTK_CONTAINER (output_window), focusable_widgets);
470 g_list_free (focusable_widgets);
472 popup_menu = create_popup_menu (output_window);
474 gtk_menu_attach_to_widget(GTK_MENU(popup_menu), output_window->priv->treeview, NULL);
476 g_signal_connect_swapped (output_window->priv->treeview, "button_press_event", G_CALLBACK (my_popup_handler), popup_menu);
482 gedit_output_window_finalize (GObject *object)
484 GeditOutputWindow *ow;
486 ow = GEDIT_OUTPUT_WINDOW (object);
488 if (ow->priv != NULL)
493 G_OBJECT_CLASS (gedit_output_window_parent_class)->finalize (object);
497 gedit_output_window_destroy (GtkObject *object)
499 GTK_OBJECT_CLASS (gedit_output_window_parent_class)->destroy (object);
503 gedit_output_window_new (void)
505 return gtk_widget_new (GEDIT_TYPE_OUTPUT_WINDOW, NULL);
509 gedit_output_window_clear (GeditOutputWindow *ow)
511 g_return_if_fail (GEDIT_IS_OUTPUT_WINDOW (ow));
513 gtk_list_store_clear (GTK_LIST_STORE (ow->priv->model));
515 gtk_widget_set_sensitive (ow->priv->clear_button, FALSE);
516 gtk_widget_set_sensitive (ow->priv->clear_menu_item, FALSE);
520 gedit_output_window_append_line (GeditOutputWindow *ow, const gchar *line, gboolean scroll)
526 g_return_if_fail (GEDIT_IS_OUTPUT_WINDOW (ow));
527 g_return_if_fail (line != NULL);
529 store = GTK_LIST_STORE (ow->priv->model);
530 g_return_if_fail (store != NULL);
532 gtk_list_store_append (store, &iter);
534 gtk_list_store_set (store, &iter, COLUMN_LINES, line, -1);
536 gtk_widget_set_sensitive (ow->priv->clear_button, TRUE);
537 gtk_widget_set_sensitive (ow->priv->clear_menu_item, TRUE);
542 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
543 g_return_if_fail (path != NULL);
545 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (ow->priv->treeview),
552 gtk_tree_path_free (path);
556 gedit_output_window_prepend_line (GeditOutputWindow *ow, const gchar *line, gboolean scroll)
562 g_return_if_fail (GEDIT_IS_OUTPUT_WINDOW (ow));
563 g_return_if_fail (line != NULL);
565 store = GTK_LIST_STORE (ow->priv->model);
566 g_return_if_fail (store != NULL);
568 gtk_list_store_prepend (store, &iter);
570 gtk_list_store_set (store, &iter, COLUMN_LINES, line, -1);
572 gtk_widget_set_sensitive (ow->priv->clear_button, TRUE);
573 gtk_widget_set_sensitive (ow->priv->clear_menu_item, TRUE);
578 path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
579 g_return_if_fail (path != NULL);
581 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (ow->priv->treeview),
588 gtk_tree_path_free (path);
595 gedit_output_window_set_select_multiple (GeditOutputWindow *ow, const GtkSelectionMode type)
597 GtkTreeSelection *selection;
599 g_return_if_fail (GEDIT_IS_OUTPUT_WINDOW (ow));
601 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ow->priv->treeview));
602 gtk_tree_selection_set_mode (selection, type);