1 /* PSPPIRE - a graphical user interface for PSPP.
2 Copyright (C) 2008 Free Software Foundation
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <gtk/gtksignal.h>
20 #include <gtk/gtkbox.h>
23 #include <libpspp/message.h>
28 #include "psppire-output-window.h"
33 #include <sys/types.h>
38 #define _(msgid) gettext (msgid)
39 #define N_(msgid) msgid
43 static void psppire_output_window_base_finalize (PsppireOutputWindowClass *, gpointer);
44 static void psppire_output_window_base_init (PsppireOutputWindowClass *class);
45 static void psppire_output_window_class_init (PsppireOutputWindowClass *class);
46 static void psppire_output_window_init (PsppireOutputWindow *window);
50 psppire_output_window_get_type (void)
52 static GType psppire_output_window_type = 0;
54 if (!psppire_output_window_type)
56 static const GTypeInfo psppire_output_window_info =
58 sizeof (PsppireOutputWindowClass),
59 (GBaseInitFunc) psppire_output_window_base_init,
60 (GBaseFinalizeFunc) psppire_output_window_base_finalize,
61 (GClassInitFunc)psppire_output_window_class_init,
62 (GClassFinalizeFunc) NULL,
64 sizeof (PsppireOutputWindow),
66 (GInstanceInitFunc) psppire_output_window_init,
69 psppire_output_window_type =
70 g_type_register_static (PSPPIRE_TYPE_WINDOW, "PsppireOutputWindow",
71 &psppire_output_window_info, 0);
74 return psppire_output_window_type;
77 static GObjectClass *parent_class;
80 psppire_output_window_finalize (GObject *object)
82 if (G_OBJECT_CLASS (parent_class)->finalize)
83 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
88 psppire_output_window_class_init (PsppireOutputWindowClass *class)
90 parent_class = g_type_class_peek_parent (class);
95 psppire_output_window_base_init (PsppireOutputWindowClass *class)
97 GObjectClass *object_class = G_OBJECT_CLASS (class);
99 object_class->finalize = psppire_output_window_finalize;
105 psppire_output_window_base_finalize (PsppireOutputWindowClass *class,
113 static PsppireOutputWindow *the_output_viewer = NULL;
116 int viewer_length = 16;
117 int viewer_width = 59;
119 /* Callback for the "delete" action (clicking the x on the top right
120 hand corner of the window) */
122 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
124 PsppireOutputWindow *ow = PSPPIRE_OUTPUT_WINDOW (user_data);
126 gtk_widget_destroy (GTK_WIDGET (ow));
128 the_output_viewer = NULL;
130 unlink (output_file_name());
138 cancel_urgency (GtkWindow *window, gpointer data)
140 gtk_window_set_urgency_hint (window, FALSE);
142 /* Sets width and length according to the new size
143 of the output window */
145 on_textview_resize (GtkWidget *widget,
146 GtkAllocation *allocation,
149 PangoContext * context ;
150 PangoLayout *layout ;
151 PangoRectangle logical;
153 gint right_margin, left_margin;
154 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
156 context = gtk_widget_create_pango_context (widget);
157 layout = pango_layout_new (context);
159 style = gtk_widget_get_style (widget);
161 pango_layout_set_font_description (layout, style->font_desc);
163 /* Find the width of one character. We can use any character, because
164 the textview has a monospaced font */
165 pango_layout_set_text (layout, "M", 1);
167 pango_layout_get_extents (layout, NULL, &logical);
169 left_margin = gtk_text_view_get_left_margin (text_view);
170 right_margin = gtk_text_view_get_right_margin (text_view);
172 viewer_length = allocation->height / PANGO_PIXELS (logical.height);
173 viewer_width = (allocation->width - right_margin - left_margin)
174 / PANGO_PIXELS (logical.width);
176 g_object_unref (G_OBJECT (layout));
177 g_object_unref (G_OBJECT (context));
182 psppire_output_window_init (PsppireOutputWindow *window)
184 GtkBuilder *xml = builder_new ("output-viewer.ui");
186 GtkWidget *box = gtk_vbox_new (FALSE, 0);
188 GtkWidget *sw = get_widget_assert (xml, "scrolledwindow1");
190 GtkWidget *menubar = get_widget_assert (xml, "menubar1");
192 window->textview = get_widget_assert (xml, "output-viewer-textview");
195 gtk_container_add (GTK_CONTAINER (window), box);
198 g_object_ref (menubar);
199 gtk_widget_unparent (menubar);
202 gtk_widget_unparent (sw);
205 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
206 gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
209 gtk_widget_show_all (box);
213 window->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->textview));
215 g_signal_connect (window,
217 G_CALLBACK (cancel_urgency),
221 /* Output uses ascii characters for tabular material.
222 So we need a monospaced font otherwise it'll look silly */
223 PangoFontDescription *font_desc =
224 pango_font_description_from_string ("monospace");
226 gtk_widget_modify_font (window->textview, font_desc);
227 pango_font_description_free (font_desc);
230 g_signal_connect (window->textview, "size-allocate",
231 G_CALLBACK (on_textview_resize), NULL);
235 g_signal_connect (get_action_assert (xml,"help_about"),
237 G_CALLBACK (about_new),
240 g_signal_connect (get_action_assert (xml,"help_reference"),
242 G_CALLBACK (reference_manual),
245 g_signal_connect (get_action_assert (xml,"windows_minimise-all"),
247 G_CALLBACK (psppire_window_minimise_all),
251 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (xml, "uimanager1", GTK_TYPE_UI_MANAGER));
253 PSPPIRE_WINDOW (window)->menu =
254 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar1/windows_menuitem/windows_minimise-all")->parent);
257 g_object_unref (xml);
259 g_signal_connect (window, "delete-event",
260 G_CALLBACK (on_delete), window);
265 psppire_output_window_new (void)
267 return GTK_WIDGET (g_object_new (psppire_output_window_get_type (),
268 "filename", "Output",
269 "description", _("Output Viewer"),
273 static void reload_viewer (PsppireOutputWindow *ow);
276 psppire_output_window_reload (void)
280 /* If there is no output, then don't do anything */
281 if (0 != stat (output_file_name(), &buf))
284 if ( NULL == the_output_viewer )
286 the_output_viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
287 gtk_widget_show (GTK_WIDGET (the_output_viewer));
290 reload_viewer (the_output_viewer);
296 reload_viewer (PsppireOutputWindow *ow)
298 GtkTextIter end_iter;
303 gboolean chars_inserted = FALSE;
305 gtk_text_buffer_get_end_iter (ow->buffer, &end_iter);
307 line = xrealloc (line, sizeof (char) * (viewer_width + 1));
309 mark = gtk_text_buffer_create_mark (ow->buffer, NULL, &end_iter, TRUE);
313 Apparently Windoze is not capabale of writing to a file whilst
314 another (or the same) process is reading from it. Therefore, we
315 must close the file after reading it, and clear the entire buffer
316 before writing to it.
317 This will be slower for large buffers, but should work
318 (in so far as anything ever works on windows).
321 GtkTextIter start_iter;
322 FILE *fp = fopen (output_file_name(), "r");
325 g_critical ("Cannot open %s\n", output_file_name());
329 /* Delete all the entire buffer */
330 gtk_text_buffer_get_start_iter (ow->buffer, &start_iter);
331 gtk_text_buffer_delete (ow->buffer, &start_iter, &end_iter);
334 gtk_text_buffer_get_start_iter (ow->buffer, &start_iter);
335 /* Read in the next lot of text */
336 while (fgets (line, viewer_width + 1, fp) != NULL)
338 chars_inserted = TRUE;
339 gtk_text_buffer_insert (ow->buffer, &start_iter, line, -1);
348 ow->fp = fopen (output_file_name(), "r");
351 g_critical ("Cannot open %s\n", output_file_name());
356 /* Read in the next lot of text */
357 while (fgets (line, viewer_width + 1, ow->fp) != NULL)
359 chars_inserted = TRUE;
360 gtk_text_buffer_insert (ow->buffer, &end_iter, line, -1);
365 /* Scroll to where the start of this lot of text begins */
366 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (ow->textview),
368 0.1, TRUE, 0.0, 0.0);
371 if ( chars_inserted )
372 gtk_window_set_urgency_hint ( GTK_WINDOW (ow), TRUE);