c1333769802671d1fcd612cb3194ece3a38bffff
[pspp-builds.git] / 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   if ( !GTK_WIDGET_REALIZED (window))
329     return;
330
331   item = g_hash_table_lookup (window->menuitem_table, key);
332
333   g_hash_table_remove (window->menuitem_table, key);
334
335   gtk_container_remove (GTK_CONTAINER (window->menu), item);
336 }
337
338 static void
339 insert_existing_items (PsppireWindow *window)
340 {
341   psppire_window_register_foreach (psppire_window_register_new (), insert_item, window);
342 }
343
344 static void
345 psppire_window_init (PsppireWindow *window)
346 {
347   window->name = NULL;
348   window->menu = NULL;
349
350   window->menuitem_table  = g_hash_table_new (g_str_hash, g_str_equal);
351
352
353   g_signal_connect (window,  "realize", G_CALLBACK (insert_existing_items), NULL);
354
355   window->insert_handler = g_signal_connect (psppire_window_register_new (),
356                                              "inserted",
357                                              G_CALLBACK (insert_menuitem),
358                                              window);
359
360   window->remove_handler = g_signal_connect (psppire_window_register_new (),
361                                              "removed",
362                                              G_CALLBACK (remove_menuitem),
363                                              window);
364 }
365
366
367 GtkWidget*
368 psppire_window_new (PsppireWindowUsage usage)
369 {
370   return GTK_WIDGET (g_object_new (psppire_window_get_type (),
371                                    "type", GTK_WINDOW_TOPLEVEL,
372                                    "usage", usage,
373                                    NULL));
374 }
375
376
377 const gchar *
378 psppire_window_get_filename (PsppireWindow *w)
379 {
380   const gchar *name = NULL;
381   g_object_get (w, "filename", &name, NULL);
382   return name;
383 }
384
385
386 void
387 psppire_window_set_filename (PsppireWindow *w, const gchar *filename)
388 {
389   g_object_set (w, "filename", filename, NULL);
390 }
391
392 \f
393
394 GType
395 psppire_window_usage_get_type (void)
396 {
397   static GType etype = 0;
398   if (etype == 0)
399     {
400       static const GEnumValue values[] = {
401         { PSPPIRE_WINDOW_USAGE_SYNTAX, "PSPPIRE_WINDOW_USAGE_SYNTAX",
402           "Syntax" },
403
404         { PSPPIRE_WINDOW_USAGE_OUTPUT, "PSPPIRE_WINDOW_USAGE_OUTPUT",
405           "Output" },
406
407         { PSPPIRE_WINDOW_USAGE_DATA,   "PSPPIRE_WINDOW_USAGE_DATA",
408           "Data" },
409
410         { 0, NULL, NULL }
411       };
412
413       etype = g_enum_register_static (g_intern_static_string ("PsppireWindowUsage"),
414                                       values);
415     }
416
417   return etype;
418 }
419
420
421
422 static void
423 minimise_window (gpointer key, gpointer value, gpointer data)
424 {
425   gtk_window_iconify (GTK_WINDOW (value));
426 }
427
428
429 void
430 psppire_window_minimise_all (void)
431 {
432   PsppireWindowRegister *reg = psppire_window_register_new ();
433
434   g_hash_table_foreach (reg->name_table, minimise_window, NULL);
435 }