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;
80 psppire_output_window_finalize (GObject *object)
82 GObjectClass *class = G_OBJECT_GET_CLASS (object);
84 GObjectClass *parent_class = g_type_class_peek_parent (class);
87 if (G_OBJECT_CLASS (parent_class)->finalize)
88 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
94 psppire_output_window_class_init (PsppireOutputWindowClass *class)
100 psppire_output_window_base_init (PsppireOutputWindowClass *class)
102 GObjectClass *object_class = G_OBJECT_CLASS (class);
104 object_class->finalize = psppire_output_window_finalize;
110 psppire_output_window_base_finalize (PsppireOutputWindowClass *class,
118 static PsppireOutputWindow *the_output_viewer = NULL;
121 int viewer_length = 16;
122 int viewer_width = 59;
124 /* Callback for the "delete" action (clicking the x on the top right
125 hand corner of the window) */
127 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
129 PsppireOutputWindow *ow = PSPPIRE_OUTPUT_WINDOW (user_data);
131 gtk_widget_destroy (GTK_WIDGET (ow));
133 the_output_viewer = NULL;
135 unlink (OUTPUT_FILE_NAME);
143 cancel_urgency (GtkWindow *window, gpointer data)
145 gtk_window_set_urgency_hint (window, FALSE);
147 /* Sets width and length according to the new size
148 of the output window */
150 on_textview_resize (GtkWidget *widget,
151 GtkAllocation *allocation,
154 PangoContext * context ;
155 PangoLayout *layout ;
156 PangoRectangle logical;
158 gint right_margin, left_margin;
159 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
161 context = gtk_widget_create_pango_context (widget);
162 layout = pango_layout_new (context);
164 style = gtk_widget_get_style (widget);
166 pango_layout_set_font_description (layout, style->font_desc);
168 /* Find the width of one character. We can use any character, because
169 the textview has a monospaced font */
170 pango_layout_set_text (layout, "M", 1);
172 pango_layout_get_extents (layout, NULL, &logical);
174 left_margin = gtk_text_view_get_left_margin (text_view);
175 right_margin = gtk_text_view_get_right_margin (text_view);
177 viewer_length = allocation->height / PANGO_PIXELS (logical.height);
178 viewer_width = (allocation->width - right_margin - left_margin)
179 / PANGO_PIXELS (logical.width);
181 g_object_unref (G_OBJECT (layout));
182 g_object_unref (G_OBJECT (context));
187 psppire_output_window_init (PsppireOutputWindow *window)
189 GladeXML *xml = XML_NEW ("output-viewer.glade");
191 GtkWidget *box = gtk_vbox_new (FALSE, 0);
193 GtkWidget *sw = get_widget_assert (xml, "scrolledwindow1");
195 GtkWidget *menubar = get_widget_assert (xml, "menubar1");
197 window->textview = get_widget_assert (xml, "output-viewer-textview");
200 gtk_container_add (GTK_CONTAINER (window), box);
203 g_object_ref (menubar);
204 gtk_widget_unparent (menubar);
207 gtk_widget_unparent (sw);
210 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
211 gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
214 gtk_widget_show_all (box);
218 window->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->textview));
220 g_signal_connect (window,
222 G_CALLBACK (cancel_urgency),
226 /* Output uses ascii characters for tabular material.
227 So we need a monospaced font otherwise it'll look silly */
228 PangoFontDescription *font_desc =
229 pango_font_description_from_string ("monospace");
231 gtk_widget_modify_font (window->textview, font_desc);
232 pango_font_description_free (font_desc);
235 g_signal_connect (window->textview, "size-allocate",
236 G_CALLBACK (on_textview_resize), NULL);
240 g_signal_connect (get_widget_assert (xml,"help_about"),
242 G_CALLBACK (about_new),
245 g_signal_connect (get_widget_assert (xml,"help_reference"),
247 G_CALLBACK (reference_manual),
250 g_signal_connect (get_widget_assert (xml,"windows_minimise-all"),
252 G_CALLBACK (psppire_window_minimise_all),
255 PSPPIRE_WINDOW (window)->menu = GTK_MENU_SHELL (get_widget_assert (xml,"windows_menu"));
258 g_object_unref (xml);
260 g_signal_connect (window, "delete-event",
261 G_CALLBACK (on_delete), window);
266 psppire_output_window_new (void)
268 return GTK_WIDGET (g_object_new (psppire_output_window_get_type (),
269 "usage", PSPPIRE_WINDOW_USAGE_OUTPUT,
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;
301 static char *line = NULL;
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_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
329 /* Delete all the entire buffer */
330 gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
331 gtk_text_buffer_delete (ov->buffer, &start_iter, &end_iter);
334 gtk_text_buffer_get_start_iter (ov->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 (ov->buffer, &start_iter, line, -1);
348 ow->fp = fopen (OUTPUT_FILE_NAME, "r");
351 g_print ("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);