]> Pileus Git - ~andy/gtk/blob - gtk/gtkrecentchooserdialog.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkrecentchooserdialog.c
1 /* GTK - The GIMP Toolkit
2  * gtkrecentchooserdialog.c: Recent files selector dialog
3  * Copyright (C) 2006 Emmanuele Bassi
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, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "config.h"
20
21 #include "gtkrecentchooserdialog.h"
22 #include "gtkrecentchooserwidget.h"
23 #include "gtkrecentchooserutils.h"
24 #include "gtkrecentmanager.h"
25 #include "gtktypebuiltins.h"
26
27 #include <stdarg.h>
28
29
30 /**
31  * SECTION:gtkrecentchooserdialog
32  * @Short_description: Displays recently used files in a dialog
33  * @Title: GtkRecentChooserDialog
34  * @See_also:#GtkRecentChooser, #GtkDialog
35  *
36  * #GtkRecentChooserDialog is a dialog box suitable for displaying the recently
37  * used documents.  This widgets works by putting a #GtkRecentChooserWidget inside
38  * a #GtkDialog.  It exposes the #GtkRecentChooserIface interface, so you can use
39  * all the #GtkRecentChooser functions on the recent chooser dialog as well as
40  * those for #GtkDialog.
41  *
42  * Note that #GtkRecentChooserDialog does not have any methods of its own.
43  * Instead, you should use the functions that work on a #GtkRecentChooser.
44  *
45  * <example id="gtkrecentchooser-typical-usage">
46  * <title>Typical usage</title>
47  * In the simplest of cases, you can use the following code to use
48  * a #GtkRecentChooserDialog to select a recently used file:
49  * <programlisting>
50  * GtkWidget *dialog;
51  *
52  * dialog = gtk_recent_chooser_dialog_new ("Recent Documents",
53  *                                         parent_window,
54  *                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
55  *                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
56  *                                         NULL);
57  *
58  * if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
59  *   {
60  *     GtkRecentInfo *info;
61  *
62  *     info = gtk_recent_chooser_get_current_item (GTK_RECENT_CHOOSER (dialog));
63  *     open_file (gtk_recent_info_get_uri (info));
64  *     gtk_recent_info_unref (info);
65  *   }
66  *
67  * gtk_widget_destroy (dialog);
68  * </programlisting>
69  * </example>
70  *
71  * Recently used files are supported since GTK+ 2.10.
72  */
73
74
75 struct _GtkRecentChooserDialogPrivate
76 {
77   GtkRecentManager *manager;
78   
79   GtkWidget *chooser;
80 };
81
82 #define GTK_RECENT_CHOOSER_DIALOG_GET_PRIVATE(obj)      (GTK_RECENT_CHOOSER_DIALOG (obj)->priv)
83
84 static void gtk_recent_chooser_dialog_class_init (GtkRecentChooserDialogClass *klass);
85 static void gtk_recent_chooser_dialog_init       (GtkRecentChooserDialog      *dialog);
86 static void gtk_recent_chooser_dialog_finalize   (GObject                     *object);
87
88 static GObject *gtk_recent_chooser_dialog_constructor (GType                  type,
89                                                        guint                  n_construct_properties,
90                                                        GObjectConstructParam *construct_params);
91
92 static void gtk_recent_chooser_dialog_set_property (GObject      *object,
93                                                     guint         prop_id,
94                                                     const GValue *value,
95                                                     GParamSpec   *pspec);
96 static void gtk_recent_chooser_dialog_get_property (GObject      *object,
97                                                     guint         prop_id,
98                                                     GValue       *value,
99                                                     GParamSpec   *pspec);
100
101 G_DEFINE_TYPE_WITH_CODE (GtkRecentChooserDialog,
102                          gtk_recent_chooser_dialog,
103                          GTK_TYPE_DIALOG,
104                          G_IMPLEMENT_INTERFACE (GTK_TYPE_RECENT_CHOOSER,
105                                                 _gtk_recent_chooser_delegate_iface_init))
106
107 static void
108 gtk_recent_chooser_dialog_class_init (GtkRecentChooserDialogClass *klass)
109 {
110   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
111   
112   gobject_class->set_property = gtk_recent_chooser_dialog_set_property;
113   gobject_class->get_property = gtk_recent_chooser_dialog_get_property;
114   gobject_class->constructor = gtk_recent_chooser_dialog_constructor;
115   gobject_class->finalize = gtk_recent_chooser_dialog_finalize;
116   
117   _gtk_recent_chooser_install_properties (gobject_class);
118   
119   g_type_class_add_private (klass, sizeof (GtkRecentChooserDialogPrivate));
120 }
121
122 static void
123 gtk_recent_chooser_dialog_init (GtkRecentChooserDialog *dialog)
124 {
125   GtkWidget *content_area, *action_area;
126
127   GtkRecentChooserDialogPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
128                                                                      GTK_TYPE_RECENT_CHOOSER_DIALOG,
129                                                                      GtkRecentChooserDialogPrivate);
130   GtkDialog *rc_dialog = GTK_DIALOG (dialog);
131   
132   dialog->priv = priv;
133
134   content_area = gtk_dialog_get_content_area (rc_dialog);
135   action_area = gtk_dialog_get_action_area (rc_dialog);
136
137   gtk_container_set_border_width (GTK_CONTAINER (rc_dialog), 5);
138   gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
139   gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
140
141 }
142
143 /* we intercept the GtkRecentChooser::item_activated signal and try to
144  * make the dialog emit a valid response signal
145  */
146 static void
147 gtk_recent_chooser_item_activated_cb (GtkRecentChooser *chooser,
148                                       gpointer          user_data)
149 {
150   GtkDialog *rc_dialog;
151   GtkRecentChooserDialog *dialog;
152   GtkWidget *action_area;
153   GList *children, *l;
154
155   dialog = GTK_RECENT_CHOOSER_DIALOG (user_data);
156   rc_dialog = GTK_DIALOG (dialog);
157
158   if (gtk_window_activate_default (GTK_WINDOW (dialog)))
159     return;
160
161   action_area = gtk_dialog_get_action_area (rc_dialog);
162   children = gtk_container_get_children (GTK_CONTAINER (action_area));
163   
164   for (l = children; l; l = l->next)
165     {
166       GtkWidget *widget;
167       gint response_id;
168       
169       widget = GTK_WIDGET (l->data);
170       response_id = gtk_dialog_get_response_for_widget (rc_dialog, widget);
171       
172       if (response_id == GTK_RESPONSE_ACCEPT ||
173           response_id == GTK_RESPONSE_OK     ||
174           response_id == GTK_RESPONSE_YES    ||
175           response_id == GTK_RESPONSE_APPLY)
176         {
177           g_list_free (children);
178           
179           gtk_dialog_response (GTK_DIALOG (dialog), response_id);
180
181           return;
182         }
183     }
184   
185   g_list_free (children);
186 }
187
188 static GObject *
189 gtk_recent_chooser_dialog_constructor (GType                  type,
190                                        guint                  n_construct_properties,
191                                        GObjectConstructParam *construct_params)
192 {
193   GtkRecentChooserDialogPrivate *priv;
194   GtkWidget *content_area;
195   GObject *object;
196
197   object = G_OBJECT_CLASS (gtk_recent_chooser_dialog_parent_class)->constructor (type,
198                                                                                  n_construct_properties,
199                                                                                  construct_params);
200   priv = GTK_RECENT_CHOOSER_DIALOG_GET_PRIVATE (object);
201   
202   gtk_widget_push_composite_child ();
203   
204   if (priv->manager)
205     priv->chooser = g_object_new (GTK_TYPE_RECENT_CHOOSER_WIDGET,
206                                   "recent-manager", priv->manager,
207                                   NULL);
208   else
209     priv->chooser = g_object_new (GTK_TYPE_RECENT_CHOOSER_WIDGET, NULL);
210   
211   g_signal_connect (priv->chooser, "item-activated",
212                     G_CALLBACK (gtk_recent_chooser_item_activated_cb),
213                     object);
214
215   content_area = gtk_dialog_get_content_area (GTK_DIALOG (object));
216
217   gtk_container_set_border_width (GTK_CONTAINER (priv->chooser), 5);
218   gtk_box_pack_start (GTK_BOX (content_area),
219                       priv->chooser, TRUE, TRUE, 0);
220   gtk_widget_show (priv->chooser);
221   
222   _gtk_recent_chooser_set_delegate (GTK_RECENT_CHOOSER (object),
223                                     GTK_RECENT_CHOOSER (priv->chooser));
224   
225   gtk_widget_pop_composite_child ();
226   
227   return object;
228 }
229
230 static void
231 gtk_recent_chooser_dialog_set_property (GObject      *object,
232                                         guint         prop_id,
233                                         const GValue *value,
234                                         GParamSpec   *pspec)
235 {
236   GtkRecentChooserDialogPrivate *priv;
237   
238   priv = GTK_RECENT_CHOOSER_DIALOG_GET_PRIVATE (object);
239   
240   switch (prop_id)
241     {
242     case GTK_RECENT_CHOOSER_PROP_RECENT_MANAGER:
243       priv->manager = g_value_get_object (value);
244       break;
245     default:
246       g_object_set_property (G_OBJECT (priv->chooser), pspec->name, value);
247       break;
248     }
249 }
250
251 static void
252 gtk_recent_chooser_dialog_get_property (GObject      *object,
253                                         guint         prop_id,
254                                         GValue       *value,
255                                         GParamSpec   *pspec)
256 {
257   GtkRecentChooserDialogPrivate *priv;
258   
259   priv = GTK_RECENT_CHOOSER_DIALOG_GET_PRIVATE (object);
260   
261   g_object_get_property (G_OBJECT (priv->chooser), pspec->name, value);
262 }
263
264 static void
265 gtk_recent_chooser_dialog_finalize (GObject *object)
266 {
267   GtkRecentChooserDialog *dialog = GTK_RECENT_CHOOSER_DIALOG (object);
268  
269   dialog->priv->manager = NULL;
270   
271   G_OBJECT_CLASS (gtk_recent_chooser_dialog_parent_class)->finalize (object);
272 }
273
274 static GtkWidget *
275 gtk_recent_chooser_dialog_new_valist (const gchar      *title,
276                                       GtkWindow        *parent,
277                                       GtkRecentManager *manager,
278                                       const gchar      *first_button_text,
279                                       va_list           varargs)
280 {
281   GtkWidget *result;
282   const char *button_text = first_button_text;
283   gint response_id;
284   
285   result = g_object_new (GTK_TYPE_RECENT_CHOOSER_DIALOG,
286                          "title", title,
287                          "recent-manager", manager,
288                          NULL);
289   
290   if (parent)
291     gtk_window_set_transient_for (GTK_WINDOW (result), parent);
292   
293   while (button_text)
294     {
295       response_id = va_arg (varargs, gint);
296       gtk_dialog_add_button (GTK_DIALOG (result), button_text, response_id);
297       button_text = va_arg (varargs, const gchar *);
298     }
299   
300   return result;
301 }
302
303 /**
304  * gtk_recent_chooser_dialog_new:
305  * @title: (allow-none): Title of the dialog, or %NULL
306  * @parent: (allow-none): Transient parent of the dialog, or %NULL,
307  * @first_button_text: (allow-none): stock ID or text to go in the first button, or %NULL
308  * @...: response ID for the first button, then additional (button, id)
309  *   pairs, ending with %NULL
310  *
311  * Creates a new #GtkRecentChooserDialog.  This function is analogous to
312  * gtk_dialog_new_with_buttons().
313  *
314  * Return value: a new #GtkRecentChooserDialog
315  *
316  * Since: 2.10
317  */
318 GtkWidget *
319 gtk_recent_chooser_dialog_new (const gchar *title,
320                                GtkWindow   *parent,
321                                const gchar *first_button_text,
322                                ...)
323 {
324   GtkWidget *result;
325   va_list varargs;
326   
327   va_start (varargs, first_button_text);
328   result = gtk_recent_chooser_dialog_new_valist (title,
329                                                  parent,
330                                                  NULL,
331                                                  first_button_text,
332                                                  varargs);
333   va_end (varargs);
334   
335   return result;
336 }
337
338 /**
339  * gtk_recent_chooser_dialog_new_for_manager:
340  * @title: (allow-none): Title of the dialog, or %NULL
341  * @parent: (allow-none): Transient parent of the dialog, or %NULL,
342  * @manager: a #GtkRecentManager
343  * @first_button_text: (allow-none): stock ID or text to go in the first button, or %NULL
344  * @...: response ID for the first button, then additional (button, id)
345  *   pairs, ending with %NULL
346  *
347  * Creates a new #GtkRecentChooserDialog with a specified recent manager.
348  *
349  * This is useful if you have implemented your own recent manager, or if you
350  * have a customized instance of a #GtkRecentManager object.
351  *
352  * Return value: a new #GtkRecentChooserDialog
353  *
354  * Since: 2.10
355  */
356 GtkWidget *
357 gtk_recent_chooser_dialog_new_for_manager (const gchar      *title,
358                                            GtkWindow        *parent,
359                                            GtkRecentManager *manager,
360                                            const gchar      *first_button_text,
361                                            ...)
362 {
363   GtkWidget *result;
364   va_list varargs;
365   
366   va_start (varargs, first_button_text);
367   result = gtk_recent_chooser_dialog_new_valist (title,
368                                                  parent,
369                                                  manager,
370                                                  first_button_text,
371                                                  varargs);
372   va_end (varargs);
373   
374   return result;
375 }