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_WINDOW_TYPE, "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_object_assert (xml,"help_about"),
237 G_CALLBACK (about_new),
240 g_signal_connect (get_object_assert (xml,"help_reference"),
242 G_CALLBACK (reference_manual),
245 g_signal_connect (get_object_assert (xml,"windows_minimise-all"),
247 G_CALLBACK (psppire_window_minimise_all),
250 GtkUIManager *uim = GTK_UI_MANAGER (get_object_assert (xml, "uimanager1"));
252 PSPPIRE_WINDOW (window)->menu =
253 GTK_MENU_SHELL (gtk_ui_manager_get_widget (uim,"/ui/menubar1/windows_menuitem/windows_minimise-all")->parent);
255 g_object_unref (xml);
257 g_signal_connect (window, "delete-event",
258 G_CALLBACK (on_delete), window);
263 psppire_output_window_new (void)
265 return GTK_WIDGET (g_object_new (psppire_output_window_get_type (),
266 "filename", "Output",
267 "description", _("Output Viewer"),
271 static void reload_viewer (PsppireOutputWindow *ow);
274 psppire_output_window_reload (void)
278 /* If there is no output, then don't do anything */
279 if (0 != stat (OUTPUT_FILE_NAME, &buf))
282 if ( NULL == the_output_viewer )
284 the_output_viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
285 gtk_widget_show (GTK_WIDGET (the_output_viewer));
288 reload_viewer (the_output_viewer);
294 reload_viewer (PsppireOutputWindow *ow)
296 GtkTextIter end_iter;
299 static char *line = NULL;
301 gboolean chars_inserted = FALSE;
303 gtk_text_buffer_get_end_iter (ow->buffer, &end_iter);
305 line = xrealloc (line, sizeof (char) * (viewer_width + 1));
307 mark = gtk_text_buffer_create_mark (ow->buffer, NULL, &end_iter, TRUE);
311 Apparently Windoze is not capabale of writing to a file whilst
312 another (or the same) process is reading from it. Therefore, we
313 must close the file after reading it, and clear the entire buffer
314 before writing to it.
315 This will be slower for large buffers, but should work
316 (in so far as anything ever works on windows).
319 GtkTextIter start_iter;
320 FILE *fp = fopen (OUTPUT_FILE_NAME, "r");
323 g_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
327 /* Delete all the entire buffer */
328 gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
329 gtk_text_buffer_delete (ov->buffer, &start_iter, &end_iter);
332 gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
333 /* Read in the next lot of text */
334 while (fgets (line, viewer_width + 1, fp) != NULL)
336 chars_inserted = TRUE;
337 gtk_text_buffer_insert (ov->buffer, &start_iter, line, -1);
346 ow->fp = fopen (OUTPUT_FILE_NAME, "r");
349 g_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
354 /* Read in the next lot of text */
355 while (fgets (line, viewer_width + 1, ow->fp) != NULL)
357 chars_inserted = TRUE;
358 gtk_text_buffer_insert (ow->buffer, &end_iter, line, -1);
363 /* Scroll to where the start of this lot of text begins */
364 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (ow->textview),
366 0.1, TRUE, 0.0, 0.0);
369 if ( chars_inserted )
370 gtk_window_set_urgency_hint ( GTK_WINDOW (ow), TRUE);