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 g_debug ("%s %p", __FUNCTION__, object);
84 GObjectClass *class = G_OBJECT_GET_CLASS (object);
86 GObjectClass *parent_class = g_type_class_peek_parent (class);
89 if (G_OBJECT_CLASS (parent_class)->finalize)
90 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
96 psppire_output_window_class_init (PsppireOutputWindowClass *class)
102 psppire_output_window_base_init (PsppireOutputWindowClass *class)
104 GObjectClass *object_class = G_OBJECT_CLASS (class);
106 object_class->finalize = psppire_output_window_finalize;
112 psppire_output_window_base_finalize (PsppireOutputWindowClass *class,
120 static PsppireOutputWindow *the_output_viewer = NULL;
123 int viewer_length = 16;
124 int viewer_width = 59;
126 /* Callback for the "delete" action (clicking the x on the top right
127 hand corner of the window) */
129 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
131 PsppireOutputWindow *ow = PSPPIRE_OUTPUT_WINDOW (user_data);
133 gtk_widget_destroy (GTK_WIDGET (ow));
135 the_output_viewer = NULL;
137 unlink (OUTPUT_FILE_NAME);
145 cancel_urgency (GtkWindow *window, gpointer data)
147 gtk_window_set_urgency_hint (window, FALSE);
149 /* Sets width and length according to the new size
150 of the output window */
152 on_textview_resize (GtkWidget *widget,
153 GtkAllocation *allocation,
156 PangoContext * context ;
157 PangoLayout *layout ;
158 PangoRectangle logical;
160 gint right_margin, left_margin;
161 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
163 context = gtk_widget_create_pango_context (widget);
164 layout = pango_layout_new (context);
166 style = gtk_widget_get_style (widget);
168 pango_layout_set_font_description (layout, style->font_desc);
170 /* Find the width of one character. We can use any character, because
171 the textview has a monospaced font */
172 pango_layout_set_text (layout, "M", 1);
174 pango_layout_get_extents (layout, NULL, &logical);
176 left_margin = gtk_text_view_get_left_margin (text_view);
177 right_margin = gtk_text_view_get_right_margin (text_view);
179 viewer_length = allocation->height / PANGO_PIXELS (logical.height);
180 viewer_width = (allocation->width - right_margin - left_margin)
181 / PANGO_PIXELS (logical.width);
183 g_object_unref (G_OBJECT (layout));
184 g_object_unref (G_OBJECT (context));
189 psppire_output_window_init (PsppireOutputWindow *window)
191 GladeXML *xml = XML_NEW ("output-viewer.glade");
193 GtkWidget *box = gtk_vbox_new (FALSE, 0);
195 GtkWidget *sw = get_widget_assert (xml, "scrolledwindow1");
197 GtkWidget *menubar = get_widget_assert (xml, "menubar1");
199 window->textview = get_widget_assert (xml, "output-viewer-textview");
202 gtk_container_add (GTK_CONTAINER (window), box);
205 g_object_ref (menubar);
206 gtk_widget_unparent (menubar);
209 gtk_widget_unparent (sw);
212 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
213 gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
216 gtk_widget_show_all (box);
220 window->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->textview));
222 g_signal_connect (window,
224 G_CALLBACK (cancel_urgency),
228 /* Output uses ascii characters for tabular material.
229 So we need a monospaced font otherwise it'll look silly */
230 PangoFontDescription *font_desc =
231 pango_font_description_from_string ("monospace");
233 gtk_widget_modify_font (window->textview, font_desc);
234 pango_font_description_free (font_desc);
237 g_signal_connect (window->textview, "size-allocate",
238 G_CALLBACK (on_textview_resize), NULL);
242 g_signal_connect (get_widget_assert (xml,"help_about"),
244 G_CALLBACK (about_new),
247 g_signal_connect (get_widget_assert (xml,"help_reference"),
249 G_CALLBACK (reference_manual),
253 g_signal_connect (get_widget_assert (xml,"windows_minimise-all"),
255 G_CALLBACK (minimise_all_windows),
259 g_object_unref (xml);
261 g_signal_connect (window, "delete-event",
262 G_CALLBACK (on_delete), window);
267 psppire_output_window_new (void)
269 return GTK_WIDGET (g_object_new (psppire_output_window_get_type (), NULL));
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 (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);
311 g_debug ("%s %p\n", __FUNCTION__, ow);
315 Apparently Windoze is not capabale of writing to a file whilst
316 another (or the same) process is reading from it. Therefore, we
317 must close the file after reading it, and clear the entire buffer
318 before writing to it.
319 This will be slower for large buffers, but should work
320 (in so far as anything ever works on windows).
323 GtkTextIter start_iter;
324 FILE *fp = fopen (OUTPUT_FILE_NAME, "r");
327 g_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
331 /* Delete all the entire buffer */
332 gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
333 gtk_text_buffer_delete (ov->buffer, &start_iter, &end_iter);
336 gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
337 /* Read in the next lot of text */
338 while (fgets (line, viewer_width + 1, fp) != NULL)
340 chars_inserted = TRUE;
341 gtk_text_buffer_insert (ov->buffer, &start_iter, line, -1);
350 ow->fp = fopen (OUTPUT_FILE_NAME, "r");
353 g_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
358 /* Read in the next lot of text */
359 while (fgets (line, viewer_width + 1, ow->fp) != NULL)
361 chars_inserted = TRUE;
362 gtk_text_buffer_insert (ow->buffer, &end_iter, line, -1);
367 /* Scroll to where the start of this lot of text begins */
368 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (ow->textview),
370 0.1, TRUE, 0.0, 0.0);
373 if ( chars_inserted )
374 gtk_window_set_urgency_hint ( GTK_WINDOW (ow), TRUE);