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>
21 #include <glade/glade.h>
24 #include <libpspp/message.h>
29 #include "psppire-output-window.h"
34 #include <sys/types.h>
39 #define _(msgid) gettext (msgid)
40 #define N_(msgid) msgid
44 static void psppire_output_window_base_finalize (PsppireOutputWindowClass *, gpointer);
45 static void psppire_output_window_base_init (PsppireOutputWindowClass *class);
46 static void psppire_output_window_class_init (PsppireOutputWindowClass *class);
47 static void psppire_output_window_init (PsppireOutputWindow *window);
51 psppire_output_window_get_type (void)
53 static GType psppire_output_window_type = 0;
55 if (!psppire_output_window_type)
57 static const GTypeInfo psppire_output_window_info =
59 sizeof (PsppireOutputWindowClass),
60 (GBaseInitFunc) psppire_output_window_base_init,
61 (GBaseFinalizeFunc) psppire_output_window_base_finalize,
62 (GClassInitFunc)psppire_output_window_class_init,
63 (GClassFinalizeFunc) NULL,
65 sizeof (PsppireOutputWindow),
67 (GInstanceInitFunc) psppire_output_window_init,
70 psppire_output_window_type =
71 g_type_register_static (PSPPIRE_WINDOW_TYPE, "PsppireOutputWindow",
72 &psppire_output_window_info, 0);
75 return psppire_output_window_type;
78 static GObjectClass *parent_class;
81 psppire_output_window_finalize (GObject *object)
83 GObjectClass *class = G_OBJECT_GET_CLASS (object);
86 if (G_OBJECT_CLASS (parent_class)->finalize)
87 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
92 psppire_output_window_class_init (PsppireOutputWindowClass *class)
94 parent_class = g_type_class_peek_parent (class);
99 psppire_output_window_base_init (PsppireOutputWindowClass *class)
101 GObjectClass *object_class = G_OBJECT_CLASS (class);
103 object_class->finalize = psppire_output_window_finalize;
109 psppire_output_window_base_finalize (PsppireOutputWindowClass *class,
117 static PsppireOutputWindow *the_output_viewer = NULL;
120 int viewer_length = 16;
121 int viewer_width = 59;
123 /* Callback for the "delete" action (clicking the x on the top right
124 hand corner of the window) */
126 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
128 PsppireOutputWindow *ow = PSPPIRE_OUTPUT_WINDOW (user_data);
130 gtk_widget_destroy (GTK_WIDGET (ow));
132 the_output_viewer = NULL;
134 unlink (OUTPUT_FILE_NAME);
142 cancel_urgency (GtkWindow *window, gpointer data)
144 gtk_window_set_urgency_hint (window, FALSE);
146 /* Sets width and length according to the new size
147 of the output window */
149 on_textview_resize (GtkWidget *widget,
150 GtkAllocation *allocation,
153 PangoContext * context ;
154 PangoLayout *layout ;
155 PangoRectangle logical;
157 gint right_margin, left_margin;
158 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
160 context = gtk_widget_create_pango_context (widget);
161 layout = pango_layout_new (context);
163 style = gtk_widget_get_style (widget);
165 pango_layout_set_font_description (layout, style->font_desc);
167 /* Find the width of one character. We can use any character, because
168 the textview has a monospaced font */
169 pango_layout_set_text (layout, "M", 1);
171 pango_layout_get_extents (layout, NULL, &logical);
173 left_margin = gtk_text_view_get_left_margin (text_view);
174 right_margin = gtk_text_view_get_right_margin (text_view);
176 viewer_length = allocation->height / PANGO_PIXELS (logical.height);
177 viewer_width = (allocation->width - right_margin - left_margin)
178 / PANGO_PIXELS (logical.width);
180 g_object_unref (G_OBJECT (layout));
181 g_object_unref (G_OBJECT (context));
186 psppire_output_window_init (PsppireOutputWindow *window)
188 GladeXML *xml = XML_NEW ("output-viewer.glade");
190 GtkWidget *box = gtk_vbox_new (FALSE, 0);
192 GtkWidget *sw = get_widget_assert (xml, "scrolledwindow1");
194 GtkWidget *menubar = get_widget_assert (xml, "menubar1");
196 window->textview = get_widget_assert (xml, "output-viewer-textview");
199 gtk_container_add (GTK_CONTAINER (window), box);
202 g_object_ref (menubar);
203 gtk_widget_unparent (menubar);
206 gtk_widget_unparent (sw);
209 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
210 gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
213 gtk_widget_show_all (box);
217 window->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->textview));
219 g_signal_connect (window,
221 G_CALLBACK (cancel_urgency),
225 /* Output uses ascii characters for tabular material.
226 So we need a monospaced font otherwise it'll look silly */
227 PangoFontDescription *font_desc =
228 pango_font_description_from_string ("monospace");
230 gtk_widget_modify_font (window->textview, font_desc);
231 pango_font_description_free (font_desc);
234 g_signal_connect (window->textview, "size-allocate",
235 G_CALLBACK (on_textview_resize), NULL);
239 g_signal_connect (get_widget_assert (xml,"help_about"),
241 G_CALLBACK (about_new),
244 g_signal_connect (get_widget_assert (xml,"help_reference"),
246 G_CALLBACK (reference_manual),
249 g_signal_connect (get_widget_assert (xml,"windows_minimise-all"),
251 G_CALLBACK (psppire_window_minimise_all),
254 PSPPIRE_WINDOW (window)->menu = GTK_MENU_SHELL (get_widget_assert (xml,"windows_menu"));
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 "usage", PSPPIRE_WINDOW_USAGE_OUTPUT,
272 static void reload_viewer (PsppireOutputWindow *ow);
275 psppire_output_window_reload (void)
279 /* If there is no output, then don't do anything */
280 if (0 != stat (OUTPUT_FILE_NAME, &buf))
283 if ( NULL == the_output_viewer )
285 the_output_viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
286 gtk_widget_show (GTK_WIDGET (the_output_viewer));
289 reload_viewer (the_output_viewer);
295 reload_viewer (PsppireOutputWindow *ow)
297 GtkTextIter end_iter;
300 static char *line = NULL;
302 gboolean chars_inserted = FALSE;
304 gtk_text_buffer_get_end_iter (ow->buffer, &end_iter);
306 line = xrealloc (line, sizeof (char) * (viewer_width + 1));
308 mark = gtk_text_buffer_create_mark (ow->buffer, NULL, &end_iter, TRUE);
312 Apparently Windoze is not capabale of writing to a file whilst
313 another (or the same) process is reading from it. Therefore, we
314 must close the file after reading it, and clear the entire buffer
315 before writing to it.
316 This will be slower for large buffers, but should work
317 (in so far as anything ever works on windows).
320 GtkTextIter start_iter;
321 FILE *fp = fopen (OUTPUT_FILE_NAME, "r");
324 g_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
328 /* Delete all the entire buffer */
329 gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
330 gtk_text_buffer_delete (ov->buffer, &start_iter, &end_iter);
333 gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
334 /* Read in the next lot of text */
335 while (fgets (line, viewer_width + 1, fp) != NULL)
337 chars_inserted = TRUE;
338 gtk_text_buffer_insert (ov->buffer, &start_iter, line, -1);
347 ow->fp = fopen (OUTPUT_FILE_NAME, "r");
350 g_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
355 /* Read in the next lot of text */
356 while (fgets (line, viewer_width + 1, ow->fp) != NULL)
358 chars_inserted = TRUE;
359 gtk_text_buffer_insert (ow->buffer, &end_iter, line, -1);
364 /* Scroll to where the start of this lot of text begins */
365 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (ow->textview),
367 0.1, TRUE, 0.0, 0.0);
370 if ( chars_inserted )
371 gtk_window_set_urgency_hint ( GTK_WINDOW (ow), TRUE);