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 if (G_OBJECT_CLASS (parent_class)->finalize)
84 (*G_OBJECT_CLASS (parent_class)->finalize) (object);
89 psppire_output_window_class_init (PsppireOutputWindowClass *class)
91 parent_class = g_type_class_peek_parent (class);
96 psppire_output_window_base_init (PsppireOutputWindowClass *class)
98 GObjectClass *object_class = G_OBJECT_CLASS (class);
100 object_class->finalize = psppire_output_window_finalize;
106 psppire_output_window_base_finalize (PsppireOutputWindowClass *class,
114 static PsppireOutputWindow *the_output_viewer = NULL;
117 int viewer_length = 16;
118 int viewer_width = 59;
120 /* Callback for the "delete" action (clicking the x on the top right
121 hand corner of the window) */
123 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
125 PsppireOutputWindow *ow = PSPPIRE_OUTPUT_WINDOW (user_data);
127 gtk_widget_destroy (GTK_WIDGET (ow));
129 the_output_viewer = NULL;
131 unlink (OUTPUT_FILE_NAME);
139 cancel_urgency (GtkWindow *window, gpointer data)
141 gtk_window_set_urgency_hint (window, FALSE);
143 /* Sets width and length according to the new size
144 of the output window */
146 on_textview_resize (GtkWidget *widget,
147 GtkAllocation *allocation,
150 PangoContext * context ;
151 PangoLayout *layout ;
152 PangoRectangle logical;
154 gint right_margin, left_margin;
155 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
157 context = gtk_widget_create_pango_context (widget);
158 layout = pango_layout_new (context);
160 style = gtk_widget_get_style (widget);
162 pango_layout_set_font_description (layout, style->font_desc);
164 /* Find the width of one character. We can use any character, because
165 the textview has a monospaced font */
166 pango_layout_set_text (layout, "M", 1);
168 pango_layout_get_extents (layout, NULL, &logical);
170 left_margin = gtk_text_view_get_left_margin (text_view);
171 right_margin = gtk_text_view_get_right_margin (text_view);
173 viewer_length = allocation->height / PANGO_PIXELS (logical.height);
174 viewer_width = (allocation->width - right_margin - left_margin)
175 / PANGO_PIXELS (logical.width);
177 g_object_unref (G_OBJECT (layout));
178 g_object_unref (G_OBJECT (context));
183 psppire_output_window_init (PsppireOutputWindow *window)
185 GladeXML *xml = XML_NEW ("output-viewer.glade");
187 GtkWidget *box = gtk_vbox_new (FALSE, 0);
189 GtkWidget *sw = get_widget_assert (xml, "scrolledwindow1");
191 GtkWidget *menubar = get_widget_assert (xml, "menubar1");
193 window->textview = get_widget_assert (xml, "output-viewer-textview");
196 gtk_container_add (GTK_CONTAINER (window), box);
199 g_object_ref (menubar);
200 gtk_widget_unparent (menubar);
203 gtk_widget_unparent (sw);
206 gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
207 gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
210 gtk_widget_show_all (box);
214 window->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->textview));
216 g_signal_connect (window,
218 G_CALLBACK (cancel_urgency),
222 /* Output uses ascii characters for tabular material.
223 So we need a monospaced font otherwise it'll look silly */
224 PangoFontDescription *font_desc =
225 pango_font_description_from_string ("monospace");
227 gtk_widget_modify_font (window->textview, font_desc);
228 pango_font_description_free (font_desc);
231 g_signal_connect (window->textview, "size-allocate",
232 G_CALLBACK (on_textview_resize), NULL);
236 g_signal_connect (get_widget_assert (xml,"help_about"),
238 G_CALLBACK (about_new),
241 g_signal_connect (get_widget_assert (xml,"help_reference"),
243 G_CALLBACK (reference_manual),
246 g_signal_connect (get_widget_assert (xml,"windows_minimise-all"),
248 G_CALLBACK (psppire_window_minimise_all),
251 PSPPIRE_WINDOW (window)->menu = GTK_MENU_SHELL (get_widget_assert (xml,"windows_menu"));
254 g_object_unref (xml);
256 g_signal_connect (window, "delete-event",
257 G_CALLBACK (on_delete), window);
262 psppire_output_window_new (void)
264 return GTK_WIDGET (g_object_new (psppire_output_window_get_type (),
265 "usage", PSPPIRE_WINDOW_USAGE_OUTPUT,
269 static void reload_viewer (PsppireOutputWindow *ow);
272 psppire_output_window_reload (void)
276 /* If there is no output, then don't do anything */
277 if (0 != stat (OUTPUT_FILE_NAME, &buf))
280 if ( NULL == the_output_viewer )
282 the_output_viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
283 gtk_widget_show (GTK_WIDGET (the_output_viewer));
286 reload_viewer (the_output_viewer);
292 reload_viewer (PsppireOutputWindow *ow)
294 GtkTextIter end_iter;
297 static char *line = NULL;
299 gboolean chars_inserted = FALSE;
301 gtk_text_buffer_get_end_iter (ow->buffer, &end_iter);
303 line = xrealloc (line, sizeof (char) * (viewer_width + 1));
305 mark = gtk_text_buffer_create_mark (ow->buffer, NULL, &end_iter, TRUE);
309 Apparently Windoze is not capabale of writing to a file whilst
310 another (or the same) process is reading from it. Therefore, we
311 must close the file after reading it, and clear the entire buffer
312 before writing to it.
313 This will be slower for large buffers, but should work
314 (in so far as anything ever works on windows).
317 GtkTextIter start_iter;
318 FILE *fp = fopen (OUTPUT_FILE_NAME, "r");
321 g_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
325 /* Delete all the entire buffer */
326 gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
327 gtk_text_buffer_delete (ov->buffer, &start_iter, &end_iter);
330 gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
331 /* Read in the next lot of text */
332 while (fgets (line, viewer_width + 1, fp) != NULL)
334 chars_inserted = TRUE;
335 gtk_text_buffer_insert (ov->buffer, &start_iter, line, -1);
344 ow->fp = fopen (OUTPUT_FILE_NAME, "r");
347 g_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
352 /* Read in the next lot of text */
353 while (fgets (line, viewer_width + 1, ow->fp) != NULL)
355 chars_inserted = TRUE;
356 gtk_text_buffer_insert (ow->buffer, &end_iter, line, -1);
361 /* Scroll to where the start of this lot of text begins */
362 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (ow->textview),
364 0.1, TRUE, 0.0, 0.0);
367 if ( chars_inserted )
368 gtk_window_set_urgency_hint ( GTK_WINDOW (ow), TRUE);