]> Pileus Git - ~andy/gtk/blob - gtk/gtkfilechooserdialog.c
Remove old file-system property. Add new file-system-backend string
[~andy/gtk] / gtk / gtkfilechooserdialog.c
1 /* GTK - The GIMP Toolkit
2  * gtkfilechooserdialog.c: File selector dialog
3  * Copyright (C) 2003, Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "gtkfilechooserdialog.h"
22 #include "gtkfilechooserwidget.h"
23 #include "gtkfilechooserutils.h"
24 #include "gtkfilesystem.h"
25 #include "gtktypebuiltins.h"
26
27 #include <stdarg.h>
28
29 #define NUM_LINES 40
30 #define NUM_CHARS 50
31
32 struct _GtkFileChooserDialogPrivate
33 {
34   GtkWidget *widget;
35
36   char *file_system;
37 };
38
39 #define GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE(o)  (GTK_FILE_CHOOSER_DIALOG (o)->priv)
40
41 static void gtk_file_chooser_dialog_class_init (GtkFileChooserDialogClass *class);
42 static void gtk_file_chooser_dialog_init       (GtkFileChooserDialog      *dialog);
43 static void gtk_file_chooser_dialog_finalize   (GObject                   *object);
44
45 static GObject* gtk_file_chooser_dialog_constructor  (GType                  type,
46                                                       guint                  n_construct_properties,
47                                                       GObjectConstructParam *construct_params);
48 static void     gtk_file_chooser_dialog_set_property (GObject               *object,
49                                                       guint                  prop_id,
50                                                       const GValue          *value,
51                                                       GParamSpec            *pspec);
52 static void     gtk_file_chooser_dialog_get_property (GObject               *object,
53                                                       guint                  prop_id,
54                                                       GValue                *value,
55                                                       GParamSpec            *pspec);
56
57 static void gtk_file_chooser_dialog_realize        (GtkWidget *widget);
58 static void gtk_file_chooser_dialog_style_set      (GtkWidget *widget,
59                                                     GtkStyle  *previous_style);
60 static void gtk_file_chooser_dialog_screen_changed (GtkWidget *widget,
61                                                     GdkScreen *previous_screen);
62
63 static GObjectClass *parent_class;
64
65 GType
66 gtk_file_chooser_dialog_get_type (void)
67 {
68   static GType file_chooser_dialog_type = 0;
69
70   if (!file_chooser_dialog_type)
71     {
72       static const GTypeInfo file_chooser_dialog_info =
73       {
74         sizeof (GtkFileChooserDialogClass),
75         NULL,           /* base_init */
76         NULL,           /* base_finalize */
77         (GClassInitFunc) gtk_file_chooser_dialog_class_init,
78         NULL,           /* class_finalize */
79         NULL,           /* class_data */
80         sizeof (GtkFileChooserDialog),
81         0,              /* n_preallocs */
82         (GInstanceInitFunc) gtk_file_chooser_dialog_init,
83       };
84
85       static const GInterfaceInfo file_chooser_info =
86       {
87         (GInterfaceInitFunc) _gtk_file_chooser_delegate_iface_init, /* interface_init */
88         NULL,                                                       /* interface_finalize */
89         NULL                                                        /* interface_data */
90       };
91
92       file_chooser_dialog_type = g_type_register_static (GTK_TYPE_DIALOG, "GtkFileChooserDialog",
93                                                          &file_chooser_dialog_info, 0);
94       g_type_add_interface_static (file_chooser_dialog_type,
95                                    GTK_TYPE_FILE_CHOOSER,
96                                    &file_chooser_info);
97     }
98
99   return file_chooser_dialog_type;
100 }
101
102 static void
103 gtk_file_chooser_dialog_class_init (GtkFileChooserDialogClass *class)
104 {
105   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
106   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
107
108   parent_class = g_type_class_peek_parent (class);
109
110   gobject_class->constructor = gtk_file_chooser_dialog_constructor;
111   gobject_class->set_property = gtk_file_chooser_dialog_set_property;
112   gobject_class->get_property = gtk_file_chooser_dialog_get_property;
113   gobject_class->finalize = gtk_file_chooser_dialog_finalize;
114
115   widget_class->realize = gtk_file_chooser_dialog_realize;
116   widget_class->style_set = gtk_file_chooser_dialog_style_set;
117   widget_class->screen_changed = gtk_file_chooser_dialog_screen_changed;
118
119   _gtk_file_chooser_install_properties (gobject_class);
120
121   g_type_class_add_private (class, sizeof (GtkFileChooserDialogPrivate));
122 }
123
124 static void
125 gtk_file_chooser_dialog_init (GtkFileChooserDialog *dialog)
126 {
127   GtkFileChooserDialogPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
128                                                                    GTK_TYPE_FILE_CHOOSER_DIALOG,
129                                                                    GtkFileChooserDialogPrivate);
130   dialog->priv = priv;
131
132   gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
133 }
134
135 static void
136 gtk_file_chooser_dialog_finalize (GObject *object)
137 {
138   GtkFileChooserDialog *dialog = GTK_FILE_CHOOSER_DIALOG (object);
139
140   g_free (dialog->priv->file_system);
141 }
142
143 /* Callback used when the user activates a file in the file chooser widget */
144 static void
145 file_chooser_widget_file_activated (GtkFileChooser       *chooser,
146                                     GtkFileChooserDialog *dialog)
147 {
148   gtk_window_activate_default (GTK_WINDOW (dialog));
149 }
150
151 static GObject*
152 gtk_file_chooser_dialog_constructor (GType                  type,
153                                      guint                  n_construct_properties,
154                                      GObjectConstructParam *construct_params)
155 {
156   GtkFileChooserDialogPrivate *priv;
157   GObject *object;
158
159   object = parent_class->constructor (type,
160                                       n_construct_properties,
161                                       construct_params);
162   priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (object);
163
164   gtk_widget_push_composite_child ();
165
166   if (priv->file_system)
167     priv->widget = g_object_new (GTK_TYPE_FILE_CHOOSER_WIDGET,
168                                  "file-system-backend", priv->file_system,
169                                  NULL);
170   else
171     priv->widget = g_object_new (GTK_TYPE_FILE_CHOOSER_WIDGET, NULL);
172
173   g_signal_connect (priv->widget, "file-activated",
174                     G_CALLBACK (file_chooser_widget_file_activated), object);
175
176   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (object)->vbox), priv->widget, TRUE, TRUE, 0);
177   gtk_widget_show (priv->widget);
178
179   _gtk_file_chooser_set_delegate (GTK_FILE_CHOOSER (object),
180                                   GTK_FILE_CHOOSER (priv->widget));
181
182   gtk_widget_pop_composite_child ();
183
184   return object;
185 }
186
187 static void
188 gtk_file_chooser_dialog_set_property (GObject         *object,
189                                       guint            prop_id,
190                                       const GValue    *value,
191                                       GParamSpec      *pspec)
192
193 {
194   GtkFileChooserDialogPrivate *priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (object);
195
196   switch (prop_id)
197     {
198     case GTK_FILE_CHOOSER_PROP_FILE_SYSTEM_BACKEND:
199       g_free (priv->file_system);
200       priv->file_system = g_value_dup_string (value);
201       break;
202     default:
203       g_object_set_property (G_OBJECT (priv->widget), pspec->name, value);
204       break;
205     }
206 }
207
208 static void
209 gtk_file_chooser_dialog_get_property (GObject         *object,
210                                       guint            prop_id,
211                                       GValue          *value,
212                                       GParamSpec      *pspec)
213 {
214   GtkFileChooserDialogPrivate *priv = GTK_FILE_CHOOSER_DIALOG_GET_PRIVATE (object);
215
216   g_object_get_property (G_OBJECT (priv->widget), pspec->name, value);
217 }
218
219 static void
220 set_default_size (GtkFileChooserDialog *dialog)
221 {
222   GtkWidget *widget;
223   GtkWindow *window;
224   int default_width, default_height;
225   int width, height;
226   int font_size;
227   GdkScreen *screen;
228   int monitor_num;
229   GtkRequisition req;
230   GdkRectangle monitor;
231
232   widget = GTK_WIDGET (dialog);
233   window = GTK_WINDOW (dialog);
234
235   /* Size based on characters */
236
237   font_size = pango_font_description_get_size (widget->style->font_desc);
238   font_size = PANGO_PIXELS (font_size);
239
240   width = font_size * NUM_CHARS;
241   height = font_size * NUM_LINES;
242
243   /* Use at least the requisition size... */
244
245   gtk_widget_size_request (widget, &req);
246   width = MAX (width, req.width);
247   height = MAX (height, req.height);
248
249   /* ... but no larger than the monitor */
250
251   screen = gtk_widget_get_screen (widget);
252   monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window);
253
254   gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
255
256   width = MIN (width, monitor.width * 3 / 4);
257   height = MIN (height, monitor.height * 3 / 4);
258
259   /* Set size */
260
261   gtk_window_get_default_size (window, &default_width, &default_height);
262
263   gtk_window_set_default_size (window,
264                                (default_width == -1) ? width : default_width,
265                                (default_height == -1) ? height : default_height);
266 }
267
268 static void
269 gtk_file_chooser_dialog_realize (GtkWidget *widget)
270 {
271   GTK_WIDGET_CLASS (parent_class)->realize (widget);
272   set_default_size (GTK_FILE_CHOOSER_DIALOG (widget));
273 }
274
275 static void
276 gtk_file_chooser_dialog_style_set (GtkWidget *widget,
277                                    GtkStyle  *previous_style)
278 {
279   GtkDialog *dialog;
280
281   if (GTK_WIDGET_CLASS (parent_class)->style_set)
282     GTK_WIDGET_CLASS (parent_class)->style_set (widget, previous_style);
283
284   if (GTK_WIDGET_REALIZED (widget))
285     set_default_size (GTK_FILE_CHOOSER_DIALOG (widget));
286
287   dialog = GTK_DIALOG (widget);
288
289   /* Override the style properties with HIG-compliant spacings.  Ugh.
290    * http://developer.gnome.org/projects/gup/hig/1.0/layout.html#layout-dialogs
291    * http://developer.gnome.org/projects/gup/hig/1.0/windows.html#alert-spacing
292    */
293
294   gtk_container_set_border_width (GTK_CONTAINER (dialog->vbox), 12);
295   gtk_box_set_spacing (GTK_BOX (dialog->vbox), 24);
296
297   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 0);
298   gtk_box_set_spacing (GTK_BOX (dialog->action_area), 6);
299 }
300
301 static void
302 gtk_file_chooser_dialog_screen_changed (GtkWidget *widget,
303                                         GdkScreen *previous_screen)
304 {
305   if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
306     GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, previous_screen);
307
308   if (GTK_WIDGET_REALIZED (widget))
309     set_default_size (GTK_FILE_CHOOSER_DIALOG (widget));
310 }
311
312 static GtkWidget *
313 gtk_file_chooser_dialog_new_valist (const gchar          *title,
314                                     GtkWindow            *parent,
315                                     GtkFileChooserAction  action,
316                                     const gchar          *backend,
317                                     const gchar          *first_button_text,
318                                     va_list               varargs)
319 {
320   GtkWidget *result;
321   const char *button_text = first_button_text;
322   gint response_id;
323
324   result = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
325                          "title", title,
326                          "action", action,
327                          "file-system-backend", backend,
328                          NULL);
329
330   if (parent)
331     gtk_window_set_transient_for (GTK_WINDOW (result), parent);
332
333   while (button_text)
334     {
335       response_id = va_arg (varargs, gint);
336       gtk_dialog_add_button (GTK_DIALOG (result), button_text, response_id);
337       button_text = va_arg (varargs, const gchar *);
338     }
339
340   return result;
341 }
342
343 /**
344  * gtk_file_chooser_dialog_new:
345  * @title: Title of the dialog, or %NULL
346  * @parent: Transient parent of the dialog, or %NULL
347  * @action: Open or save mode for the dialog
348  * @first_button_text: stock ID or text to go in the first button, or %NULL
349  * @Varargs: response ID for the first button, then additional (button, id) pairs, ending with %NULL
350  *
351  * Creates a new #GtkFileChooserDialog.  This function is analogous to
352  * gtk_dialog_new_with_buttons().
353  *
354  * Return value: a new #GtkFileChooserDialog
355  *
356  * Since: 2.4
357  **/
358 GtkWidget *
359 gtk_file_chooser_dialog_new (const gchar         *title,
360                              GtkWindow           *parent,
361                              GtkFileChooserAction action,
362                              const gchar         *first_button_text,
363                              ...)
364 {
365   GtkWidget *result;
366   va_list varargs;
367   
368   va_start (varargs, first_button_text);
369   result = gtk_file_chooser_dialog_new_valist (title, parent, action,
370                                                NULL, first_button_text,
371                                                varargs);
372   va_end (varargs);
373
374   return result;
375 }
376
377 /**
378  * gtk_file_chooser_dialog_new_with_backend:
379  * @title: Title of the dialog, or %NULL
380  * @parent: Transient parent of the dialog, or %NULL
381  * @backend: The name of the specific filesystem backend to use.
382  * @action: Open or save mode for the dialog
383  * @first_button_text: stock ID or text to go in the first button, or %NULL
384  * @Varargs: response ID for the first button, then additional (button, id) pairs, ending with %NULL
385  *
386  * Creates a new #GtkFileChooserDialog with a specified backend. This is
387  * especially useful if you use gtk_file_chooser_set_local_only() to allow
388  * non-local files and you use a more expressive vfs, such as gnome-vfs,
389  * to load files.
390  *
391  * Return value: a new #GtkFileChooserDialog
392  *
393  * Since: 2.4
394  **/
395 GtkWidget *
396 gtk_file_chooser_dialog_new_with_backend (const gchar          *title,
397                                           GtkWindow            *parent,
398                                           GtkFileChooserAction  action,
399                                           const gchar          *backend,
400                                           const gchar          *first_button_text,
401                                           ...)
402 {
403   GtkWidget *result;
404   va_list varargs;
405   
406   va_start (varargs, first_button_text);
407   result = gtk_file_chooser_dialog_new_valist (title, parent, action,
408                                                backend, first_button_text,
409                                                varargs);
410   va_end (varargs);
411
412   return result;
413 }