Fix warnings
[pspp] / src / ui / gui / psppire-output-window.c
1 /* PSPPIRE - a graphical user interface for PSPP.
2    Copyright (C) 2008  Free Software Foundation
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
19 #include <gtk/gtksignal.h>
20 #include <gtk/gtkbox.h>
21 #include <glade/glade.h>
22 #include "helper.h"
23
24 #include <libpspp/message.h>
25 #include <stdlib.h>
26
27 #include "about.h"
28
29 #include "psppire-output-window.h"
30
31
32 #include "xalloc.h"
33
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37
38 #include <gettext.h>
39 #define _(msgid) gettext (msgid)
40 #define N_(msgid) msgid
41
42
43
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);
48
49
50 GType
51 psppire_output_window_get_type (void)
52 {
53   static GType psppire_output_window_type = 0;
54
55   if (!psppire_output_window_type)
56     {
57       static const GTypeInfo psppire_output_window_info =
58       {
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,
64         NULL,
65         sizeof (PsppireOutputWindow),
66         0,
67         (GInstanceInitFunc) psppire_output_window_init,
68       };
69
70       psppire_output_window_type =
71         g_type_register_static (PSPPIRE_WINDOW_TYPE, "PsppireOutputWindow",
72                                 &psppire_output_window_info, 0);
73     }
74
75   return psppire_output_window_type;
76 }
77
78 static GObjectClass *parent_class;
79
80 static void
81 psppire_output_window_finalize (GObject *object)
82 {
83   if (G_OBJECT_CLASS (parent_class)->finalize)
84     (*G_OBJECT_CLASS (parent_class)->finalize) (object);
85 }
86
87
88 static void
89 psppire_output_window_class_init (PsppireOutputWindowClass *class)
90 {
91   parent_class = g_type_class_peek_parent (class);
92 }
93
94
95 static void
96 psppire_output_window_base_init (PsppireOutputWindowClass *class)
97 {
98   GObjectClass *object_class = G_OBJECT_CLASS (class);
99
100   object_class->finalize = psppire_output_window_finalize;
101 }
102
103
104
105 static void
106 psppire_output_window_base_finalize (PsppireOutputWindowClass *class,
107                                      gpointer class_data)
108 {
109 }
110
111
112 \f
113
114 static PsppireOutputWindow *the_output_viewer = NULL;
115
116
117 int viewer_length = 16;
118 int viewer_width = 59;
119
120 /* Callback for the "delete" action (clicking the x on the top right
121    hand corner of the window) */
122 static gboolean
123 on_delete (GtkWidget *w, GdkEvent *event, gpointer user_data)
124 {
125   PsppireOutputWindow *ow = PSPPIRE_OUTPUT_WINDOW (user_data);
126
127   gtk_widget_destroy (GTK_WIDGET (ow));
128
129   the_output_viewer = NULL;
130
131   unlink (OUTPUT_FILE_NAME);
132
133   return FALSE;
134 }
135
136
137
138 static void
139 cancel_urgency (GtkWindow *window,  gpointer data)
140 {
141   gtk_window_set_urgency_hint (window, FALSE);
142 }
143 /* Sets width and length according to the new size
144    of the output window */
145 static void
146 on_textview_resize (GtkWidget     *widget,
147                     GtkAllocation *allocation,
148                     gpointer       user_data)
149 {
150   PangoContext * context ;
151   PangoLayout *layout ;
152   PangoRectangle logical;
153   GtkStyle *style;
154   gint right_margin, left_margin;
155   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
156
157   context = gtk_widget_create_pango_context (widget);
158   layout = pango_layout_new (context);
159
160   style = gtk_widget_get_style (widget);
161
162   pango_layout_set_font_description (layout, style->font_desc);
163
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);
167
168   pango_layout_get_extents (layout,  NULL, &logical);
169
170   left_margin = gtk_text_view_get_left_margin (text_view);
171   right_margin = gtk_text_view_get_right_margin (text_view);
172
173   viewer_length = allocation->height / PANGO_PIXELS (logical.height);
174   viewer_width = (allocation->width - right_margin - left_margin)
175     / PANGO_PIXELS (logical.width);
176
177   g_object_unref (G_OBJECT (layout));
178   g_object_unref (G_OBJECT (context));
179 }
180
181
182 static void
183 psppire_output_window_init (PsppireOutputWindow *window)
184 {
185   GladeXML *xml = XML_NEW ("output-viewer.glade");
186
187   GtkWidget *box = gtk_vbox_new (FALSE, 0);
188
189   GtkWidget *sw = get_widget_assert (xml, "scrolledwindow1");
190
191   GtkWidget *menubar = get_widget_assert (xml, "menubar1");
192
193   window->textview = get_widget_assert (xml, "output-viewer-textview");
194
195
196   gtk_container_add (GTK_CONTAINER (window), box);
197
198
199   g_object_ref (menubar);
200   gtk_widget_unparent (menubar);
201
202   g_object_ref (sw);
203   gtk_widget_unparent (sw);
204
205
206   gtk_box_pack_start (GTK_BOX (box), menubar, FALSE, TRUE, 0);
207   gtk_box_pack_start (GTK_BOX (box), sw, TRUE, TRUE, 0);
208
209
210   gtk_widget_show_all (box);
211
212   connect_help (xml);
213
214   window->buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->textview));
215
216   g_signal_connect (window,
217                     "focus-in-event",
218                     G_CALLBACK (cancel_urgency),
219                     NULL);
220
221   {
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");
226
227     gtk_widget_modify_font (window->textview, font_desc);
228     pango_font_description_free (font_desc);
229   }
230
231   g_signal_connect (window->textview, "size-allocate",
232                     G_CALLBACK (on_textview_resize), NULL);
233
234   window->fp = NULL;
235
236   g_signal_connect (get_widget_assert (xml,"help_about"),
237                     "activate",
238                     G_CALLBACK (about_new),
239                     window);
240
241   g_signal_connect (get_widget_assert (xml,"help_reference"),
242                     "activate",
243                     G_CALLBACK (reference_manual),
244                     NULL);
245
246   g_signal_connect (get_widget_assert (xml,"windows_minimise-all"),
247                     "activate",
248                     G_CALLBACK (psppire_window_minimise_all),
249                     NULL);
250
251   PSPPIRE_WINDOW (window)->menu = GTK_MENU_SHELL (get_widget_assert (xml,"windows_menu"));
252
253
254   g_object_unref (xml);
255
256   g_signal_connect (window, "delete-event",
257                     G_CALLBACK (on_delete), window);
258 }
259
260
261 GtkWidget*
262 psppire_output_window_new (void)
263 {
264   return GTK_WIDGET (g_object_new (psppire_output_window_get_type (),
265                                    "usage", PSPPIRE_WINDOW_USAGE_OUTPUT,
266                                    NULL));
267 }
268
269 static void reload_viewer (PsppireOutputWindow *ow);
270
271 void
272 psppire_output_window_reload (void)
273 {
274   struct stat buf;
275
276   /* If there is no output, then don't do anything */
277   if (0 != stat (OUTPUT_FILE_NAME, &buf))
278     return ;
279
280   if ( NULL == the_output_viewer )
281     {
282       the_output_viewer = PSPPIRE_OUTPUT_WINDOW (psppire_output_window_new ());
283       gtk_widget_show (GTK_WIDGET (the_output_viewer));
284     }
285
286   reload_viewer (the_output_viewer);
287
288 }
289
290
291 static void
292 reload_viewer (PsppireOutputWindow *ow)
293 {
294   GtkTextIter end_iter;
295   GtkTextMark *mark ;
296
297   static char *line = NULL;
298
299   gboolean chars_inserted = FALSE;
300
301   gtk_text_buffer_get_end_iter (ow->buffer, &end_iter);
302
303   line = xrealloc (line, sizeof (char) * (viewer_width + 1));
304
305   mark = gtk_text_buffer_create_mark (ow->buffer, NULL, &end_iter, TRUE);
306
307 #ifdef __CYGWIN__
308   /*
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).
315   */
316   {
317     GtkTextIter start_iter;
318     FILE *fp = fopen (OUTPUT_FILE_NAME, "r");
319     if ( !fp)
320       {
321         g_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
322         return;
323       }
324
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);
328
329
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)
333       {
334         chars_inserted = TRUE;
335         gtk_text_buffer_insert (ov->buffer, &start_iter, line, -1);
336       }
337
338     fclose (fp);
339   }
340 #else
341   {
342     if ( ow->fp == NULL)
343       {
344         ow->fp = fopen (OUTPUT_FILE_NAME, "r");
345         if ( ow->fp == NULL)
346           {
347             g_print ("Cannot open %s\n", OUTPUT_FILE_NAME);
348             return;
349           }
350       }
351
352     /* Read in the next lot of text */
353     while (fgets (line, viewer_width + 1, ow->fp) != NULL)
354       {
355         chars_inserted = TRUE;
356         gtk_text_buffer_insert (ow->buffer, &end_iter, line, -1);
357       }
358   }
359 #endif
360
361   /* Scroll to where the start of this lot of text begins */
362   gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (ow->textview),
363                                 mark,
364                                 0.1, TRUE, 0.0, 0.0);
365
366
367   if ( chars_inserted )
368     gtk_window_set_urgency_hint ( GTK_WINDOW (ow), TRUE);
369 }
370
371
372