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