Set the window title when opening a file on the command line
[pspp] / src / ui / gui / psppire-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/gtkwindow.h>
21 #include <gtk/gtkcheckmenuitem.h>
22
23 #include <stdlib.h>
24
25 #include <gettext.h>
26 #define _(msgid) gettext (msgid)
27 #define N_(msgid) msgid
28
29 #include "psppire-window.h"
30 #include "psppire-window-register.h"
31
32 static void psppire_window_base_finalize (PsppireWindowClass *, gpointer);
33 static void psppire_window_base_init     (PsppireWindowClass *class);
34 static void psppire_window_class_init    (PsppireWindowClass *class);
35 static void psppire_window_init          (PsppireWindow      *window);
36
37
38 static PsppireWindowClass *the_class;
39 static GObjectClass *parent_class;
40
41 GType
42 psppire_window_get_type (void)
43 {
44   static GType psppire_window_type = 0;
45
46   if (!psppire_window_type)
47     {
48       static const GTypeInfo psppire_window_info =
49       {
50         sizeof (PsppireWindowClass),
51         (GBaseInitFunc) psppire_window_base_init,
52         (GBaseFinalizeFunc) psppire_window_base_finalize,
53         (GClassInitFunc) psppire_window_class_init,
54         (GClassFinalizeFunc) NULL,
55         NULL,
56         sizeof (PsppireWindow),
57         0,
58         (GInstanceInitFunc) psppire_window_init,
59       };
60
61       psppire_window_type =
62         g_type_register_static (GTK_TYPE_WINDOW, "PsppireWindow",
63                                 &psppire_window_info, 0);
64     }
65
66   return psppire_window_type;
67 }
68
69
70 /* Properties */
71 enum
72 {
73   PROP_0,
74   PROP_FILENAME,
75   PROP_USAGE
76 };
77
78
79 gchar *
80 uniquify (const gchar *str, int *x)
81 {
82   return g_strdup_printf ("%s%d", str, (*x)++);
83 }
84
85
86
87 static void
88 psppire_window_set_property (GObject         *object,
89                              guint            prop_id,
90                              const GValue    *value,
91                              GParamSpec      *pspec)
92 {
93   PsppireWindow *window = PSPPIRE_WINDOW (object);
94
95   switch (prop_id)
96     {
97     case PROP_USAGE:
98       window->usage = g_value_get_enum (value);
99       break;
100     case PROP_FILENAME:
101       {
102         gchar mdash[6] = {0,0,0,0,0,0};
103         gchar *basename, *title;
104         const gchar *name = g_value_get_string (value);
105         gchar *candidate_name = strdup (name);
106         int x = 0;
107
108         PsppireWindowRegister *reg = psppire_window_register_new ();
109
110         while ( psppire_window_register_lookup (reg, candidate_name))
111           {
112             free (candidate_name);
113             candidate_name = uniquify (name, &x);
114           }
115
116         basename = g_path_get_basename (candidate_name);
117         g_unichar_to_utf8 (0x2014, mdash);
118
119         switch (window->usage)
120           {
121           case PSPPIRE_WINDOW_USAGE_SYNTAX:
122             title = g_strdup_printf ( _("%s %s PSPPIRE Syntax Editor"),
123                                       basename, mdash);
124             break;
125           case PSPPIRE_WINDOW_USAGE_OUTPUT:
126             title = g_strdup_printf ( _("%s %s PSPPIRE Output"),
127                                       basename, mdash);
128           case PSPPIRE_WINDOW_USAGE_DATA:
129             title = g_strdup_printf ( _("%s %s PSPPIRE Data Editor"),
130                                       basename, mdash);
131             break;
132           default:
133             g_assert_not_reached ();
134             break;
135           }
136
137         gtk_window_set_title (GTK_WINDOW (window), title);
138
139         if ( window->name)
140           psppire_window_register_remove (reg, window->name);
141
142         free (window->name);
143         window->name = candidate_name;
144
145         psppire_window_register_insert (reg, window, window->name);
146
147         free (basename);
148         free (title);
149       }
150       break;
151     default:
152       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
153       break;
154     };
155 }
156
157
158 static void
159 psppire_window_get_property (GObject         *object,
160                              guint            prop_id,
161                              GValue          *value,
162                              GParamSpec      *pspec)
163 {
164   PsppireWindow *window = PSPPIRE_WINDOW (object);
165
166   switch (prop_id)
167     {
168     case PROP_USAGE:
169       g_value_set_enum (value, window->usage);
170       break;
171     case PROP_FILENAME:
172       g_value_set_string (value, window->name);
173       break;
174     default:
175       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
176       break;
177     };
178 }
179
180
181
182 static void
183 psppire_window_finalize (GObject *object)
184 {
185   PsppireWindow *window = PSPPIRE_WINDOW (object);
186   
187   PsppireWindowRegister *reg = psppire_window_register_new ();
188
189   psppire_window_register_remove (reg, window->name);
190   free (window->name);
191
192   g_signal_handler_disconnect (psppire_window_register_new (),
193                                window->remove_handler);
194
195   g_signal_handler_disconnect (psppire_window_register_new (),
196                                window->insert_handler);
197
198   g_hash_table_destroy (window->menuitem_table);
199
200   if (G_OBJECT_CLASS (parent_class)->finalize)
201     G_OBJECT_CLASS (parent_class)->finalize (object);
202 }
203
204
205 static void
206 psppire_window_class_init (PsppireWindowClass *class)
207 {
208   GObjectClass *object_class = G_OBJECT_CLASS (class);
209
210   GParamSpec *use_class_spec =
211     g_param_spec_enum ("usage",
212                        "Usage",
213                        "What the window is used for",
214                        G_TYPE_PSPPIRE_WINDOW_USAGE,
215                        PSPPIRE_WINDOW_USAGE_SYNTAX /* default value */,
216                        G_PARAM_CONSTRUCT_ONLY |G_PARAM_READABLE | G_PARAM_WRITABLE);
217
218
219   GParamSpec *filename_spec =
220     g_param_spec_string ("filename",
221                        "File name",
222                        "The name of the file associated with this window, if any",
223                          "Untitled",
224                          G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT
225                          );
226
227
228   object_class->set_property = psppire_window_set_property;
229   object_class->get_property = psppire_window_get_property;
230
231   g_object_class_install_property (object_class,
232                                    PROP_FILENAME,
233                                    filename_spec);
234
235   g_object_class_install_property (object_class,
236                                    PROP_USAGE,
237                                    use_class_spec);
238
239
240   the_class = class;
241   parent_class = g_type_class_peek_parent (class);
242 }
243
244
245 static void
246 psppire_window_base_init (PsppireWindowClass *class)
247 {
248   GObjectClass *object_class = G_OBJECT_CLASS (class);
249
250   object_class->finalize = psppire_window_finalize;
251 }
252
253
254
255 static void
256 psppire_window_base_finalize (PsppireWindowClass *class,
257                                 gpointer class_data)
258 {
259 }
260
261 static void
262 menu_toggled (GtkCheckMenuItem *mi, gpointer data)
263 {
264   /* Prohibit changes to the state */
265   mi->active = !mi->active;
266 }
267
268
269 /* Look up the window associated with this menuitem and present it to the user */
270 static void
271 menu_activate (GtkMenuItem *mi, gpointer data)
272 {
273   const gchar *key = data;
274
275   PsppireWindowRegister *reg = psppire_window_register_new ();
276
277   PsppireWindow *window = psppire_window_register_lookup (reg, key);
278
279   gtk_window_present (GTK_WINDOW (window));
280 }
281
282 static void
283 insert_menuitem_into_menu (PsppireWindow *window, gpointer key)
284 {
285   GtkWidget *item = gtk_check_menu_item_new_with_label (key);
286
287   g_signal_connect (item, "toggled", G_CALLBACK (menu_toggled), NULL);
288   g_signal_connect (item, "activate", G_CALLBACK (menu_activate), key);
289
290   gtk_widget_show (item);
291   
292   gtk_menu_shell_append (window->menu, item);
293
294   /* Set the state without emitting a signal */
295   GTK_CHECK_MENU_ITEM (item)->active =
296    (psppire_window_register_lookup (psppire_window_register_new (), key) == window);
297
298   g_hash_table_insert (window->menuitem_table, key, item);
299 }
300
301 static void
302 insert_item (gpointer key, gpointer value, gpointer data)
303 {
304   PsppireWindow *window = PSPPIRE_WINDOW (data);
305
306   if ( NULL != g_hash_table_lookup (window->menuitem_table, key))
307     return;
308
309   insert_menuitem_into_menu (window, key);
310 }
311
312 /* Insert a new item into the window menu */
313 static void
314 insert_menuitem (GObject *reg, const gchar *key, gpointer data)
315 {
316   PsppireWindow *window = PSPPIRE_WINDOW (data);
317   
318   insert_menuitem_into_menu (window, (gpointer) key);
319 }
320
321
322 static void
323 remove_menuitem (PsppireWindowRegister *reg, const gchar *key, gpointer data)
324 {
325   PsppireWindow *window = PSPPIRE_WINDOW (data);
326   GtkWidget *item ;
327
328   item = g_hash_table_lookup (window->menuitem_table, key);
329
330   g_hash_table_remove (window->menuitem_table, key);
331
332   if (GTK_IS_CONTAINER (window->menu))
333     gtk_container_remove (GTK_CONTAINER (window->menu), item);
334 }
335
336 static void
337 insert_existing_items (PsppireWindow *window)
338 {
339   psppire_window_register_foreach (psppire_window_register_new (), insert_item, window);
340 }
341
342 static void
343 psppire_window_init (PsppireWindow *window)
344 {
345   window->name = NULL;
346   window->menu = NULL;
347
348   window->menuitem_table  = g_hash_table_new (g_str_hash, g_str_equal);
349
350
351   g_signal_connect (window,  "realize", G_CALLBACK (insert_existing_items), NULL);
352
353   window->insert_handler = g_signal_connect (psppire_window_register_new (),
354                                              "inserted",
355                                              G_CALLBACK (insert_menuitem),
356                                              window);
357
358   window->remove_handler = g_signal_connect (psppire_window_register_new (),
359                                              "removed",
360                                              G_CALLBACK (remove_menuitem),
361                                              window);
362 }
363
364
365 GtkWidget*
366 psppire_window_new (PsppireWindowUsage usage)
367 {
368   return GTK_WIDGET (g_object_new (psppire_window_get_type (),
369                                    "type", GTK_WINDOW_TOPLEVEL,
370                                    "usage", usage,
371                                    NULL));
372 }
373
374
375 const gchar *
376 psppire_window_get_filename (PsppireWindow *w)
377 {
378   const gchar *name = NULL;
379   g_object_get (w, "filename", &name, NULL);
380   return name;
381 }
382
383
384 void
385 psppire_window_set_filename (PsppireWindow *w, const gchar *filename)
386 {
387   g_object_set (w, "filename", filename, NULL);
388 }
389
390 \f
391
392 GType
393 psppire_window_usage_get_type (void)
394 {
395   static GType etype = 0;
396   if (etype == 0)
397     {
398       static const GEnumValue values[] = {
399         { PSPPIRE_WINDOW_USAGE_SYNTAX, "PSPPIRE_WINDOW_USAGE_SYNTAX",
400           "Syntax" },
401
402         { PSPPIRE_WINDOW_USAGE_OUTPUT, "PSPPIRE_WINDOW_USAGE_OUTPUT",
403           "Output" },
404
405         { PSPPIRE_WINDOW_USAGE_DATA,   "PSPPIRE_WINDOW_USAGE_DATA",
406           "Data" },
407
408         { 0, NULL, NULL }
409       };
410
411       etype = g_enum_register_static (g_intern_static_string ("PsppireWindowUsage"),
412                                       values);
413     }
414
415   return etype;
416 }
417
418
419
420 static void
421 minimise_window (gpointer key, gpointer value, gpointer data)
422 {
423   gtk_window_iconify (GTK_WINDOW (value));
424 }
425
426
427 void
428 psppire_window_minimise_all (void)
429 {
430   PsppireWindowRegister *reg = psppire_window_register_new ();
431
432   g_hash_table_foreach (reg->name_table, minimise_window, NULL);
433 }