Fixed bug reporting the significance of paired value t-test.
[pspp-builds.git] / src / ui / gui / output-viewer.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2007 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18 #include <gtk/gtk.h>
19 #include <data/file-name.h>
20 #include "window-manager.h"
21 #include "output-viewer.h"
22 #include "helper.h"
23 #include "about.h"
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28
29 #include <glade/glade.h>
30 #include <ctype.h>
31
32 #include "xalloc.h"
33
34 struct output_viewer
35 {
36   struct editor_window parent;
37   GtkTextBuffer *buffer;  /* The buffer which contains the text */
38   GtkWidget *textview ;
39   FILE *fp;               /* The file it's viewing */
40 };
41
42
43 static void
44 cancel_urgency (GtkWindow *window,  gpointer data)
45 {
46   gtk_window_set_urgency_hint (window, FALSE);
47 }
48
49
50 static struct output_viewer *the_output_viewer = NULL;
51
52 int viewer_length = 16;
53 int viewer_width = 59;
54
55 /* Callback for the "delete" action (clicking the x on the top right
56    hand corner of the window) */
57 static gboolean
58 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
59 {
60   struct output_viewer *ov = user_data;
61
62   g_free (ov);
63
64   the_output_viewer = NULL;
65
66   unlink (output_file_name ());
67
68   return FALSE;
69 }
70
71
72 /* Sets width and length according to the new size
73    of the output window */
74 static void
75 on_textview_resize (GtkWidget     *widget,
76                     GtkAllocation *allocation,
77                     gpointer       user_data)
78 {
79   PangoContext * context ;
80   PangoLayout *layout ;
81   PangoRectangle logical;
82   GtkStyle *style;
83   gint right_margin, left_margin;
84   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
85
86   context = gtk_widget_create_pango_context (widget);
87   layout = pango_layout_new (context);
88
89   style = gtk_widget_get_style (widget);
90
91   pango_layout_set_font_description (layout, style->font_desc);
92
93   /* Find the width of one character.  We can use any character, because
94      the textview has a monospaced font */
95   pango_layout_set_text (layout, "M", 1);
96
97   pango_layout_get_extents (layout,  NULL, &logical);
98
99   left_margin = gtk_text_view_get_left_margin (text_view);
100   right_margin = gtk_text_view_get_right_margin (text_view);
101
102   viewer_length = allocation->height / PANGO_PIXELS (logical.height);
103   viewer_width = (allocation->width - right_margin - left_margin)
104     / PANGO_PIXELS (logical.width);
105
106   g_object_unref (G_OBJECT (layout));
107   g_object_unref (G_OBJECT (context));
108 }
109
110
111
112 /*
113   Create a new output viewer
114 */
115 struct output_viewer *
116 new_output_viewer (void)
117 {
118   GladeXML *xml = XML_NEW ("output-viewer.glade");
119
120   struct output_viewer *ov ;
121   struct editor_window *e;
122
123   connect_help (xml);
124
125   ov = g_malloc (sizeof (*ov));
126
127   e = (struct editor_window *)ov;
128
129
130   e->window = GTK_WINDOW (get_widget_assert (xml, "output-viewer-window"));
131   ov->textview = get_widget_assert (xml, "output-viewer-textview");
132   ov->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (ov->textview));
133
134   g_signal_connect (e->window,
135                     "focus-in-event",
136                     G_CALLBACK (cancel_urgency),
137                     NULL);
138
139   {
140     /* Output uses ascii characters for tabular material.
141        So we need a monospaced font otherwise it'll look silly */
142     PangoFontDescription *font_desc =
143       pango_font_description_from_string ("monospace");
144
145     gtk_widget_modify_font (ov->textview, font_desc);
146     pango_font_description_free (font_desc);
147   }
148
149   g_signal_connect (ov->textview, "size-allocate",
150                     G_CALLBACK (on_textview_resize), NULL);
151
152   ov->fp = NULL;
153
154   g_signal_connect (get_widget_assert (xml,"help_about"),
155                     "activate",
156                     G_CALLBACK (about_new),
157                     e->window);
158
159   g_signal_connect (get_widget_assert (xml,"help_reference"),
160                     "activate",
161                     G_CALLBACK (reference_manual),
162                     NULL);
163
164   g_signal_connect (get_widget_assert (xml,"windows_minimise-all"),
165                     "activate",
166                     G_CALLBACK (minimise_all_windows),
167                     NULL);
168
169   g_object_unref (xml);
170
171
172   g_signal_connect (e->window, "delete-event",
173                     G_CALLBACK (on_delete), ov);
174
175   return ov;
176 }
177
178
179 void
180 reload_the_viewer (void)
181 {
182   struct stat buf;
183
184   /* If there is no output, then don't do anything */
185   if (0 != stat (output_file_name (), &buf))
186     return ;
187
188   if ( NULL == the_output_viewer )
189     {
190       the_output_viewer =
191         (struct output_viewer *) window_create (WINDOW_OUTPUT, NULL);
192     }
193
194   reload_viewer (the_output_viewer);
195 }
196
197
198
199 void
200 reload_viewer (struct output_viewer *ov)
201 {
202   GtkTextIter end_iter;
203   GtkTextMark *mark ;
204
205   static char *line = NULL;
206
207   gboolean chars_inserted = FALSE;
208
209   gtk_text_buffer_get_end_iter (ov->buffer, &end_iter);
210
211   line = xrealloc (line, sizeof (char) * (viewer_width + 1));
212
213
214   mark = gtk_text_buffer_create_mark (ov->buffer, NULL, &end_iter, TRUE);
215
216 #ifdef __CYGWIN__
217   /*
218     Apparently Windoze is not capabale of writing to a file whilst
219     another (or the same) process is reading from it.   Therefore, we
220     must close the file after reading it, and clear the entire buffer
221     before writing to it.
222     This will be slower for large buffers, but should work
223     (in so far as anything ever works on windows).
224   */
225   {
226     GtkTextIter start_iter;
227     FILE *fp = fopen (output_file_name (), "r");
228     if ( !fp)
229       {
230         g_warning ("Cannot open %s\n", output_file_name ());
231         return;
232       }
233
234     /* Delete all the entire buffer */
235     gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
236     gtk_text_buffer_delete (ov->buffer, &start_iter, &end_iter);
237
238
239     gtk_text_buffer_get_start_iter (ov->buffer, &start_iter);
240     /* Read in the next lot of text */
241     while (fgets (line, viewer_width + 1, fp) != NULL)
242       {
243         chars_inserted = TRUE;
244         gtk_text_buffer_insert (ov->buffer, &start_iter, line, -1);
245       }
246
247     fclose (fp);
248   }
249 #else
250   {
251     if ( ov->fp == NULL)
252       {
253         ov->fp = fopen (output_file_name (), "r");
254         if ( ov->fp == NULL)
255           {
256             g_warning ("Cannot open %s\n", output_file_name ());
257             return;
258           }
259       }
260
261     /* Read in the next lot of text */
262     while (fgets (line, viewer_width + 1, ov->fp) != NULL)
263       {
264         chars_inserted = TRUE;
265         gtk_text_buffer_insert (ov->buffer, &end_iter, line, -1);
266       }
267   }
268 #endif
269
270   /* Scroll to where the start of this lot of text begins */
271   gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (ov->textview),
272                                 mark,
273                                 0.1, TRUE, 0.0, 0.0);
274
275
276   if ( chars_inserted )
277     gtk_window_set_urgency_hint ( ((struct editor_window *)ov)->window, TRUE);
278 }
279
280
281 #define OUTPUT_FILE_NAME "psppire.txt"
282
283 const char *
284 output_file_name (void)
285 {
286   const char *dir = default_output_path ();
287   static char *filename = NULL;
288
289   if ( NULL == filename )
290     filename = xasprintf ("%s%s", dir, OUTPUT_FILE_NAME);
291
292
293   return filename;
294 }