1/* testfilechooser.c
2 * Copyright (C) 2003 Red Hat, Inc.
3 * Author: Owen Taylor
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library 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 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18#include "config.h"
19
20#include <string.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <stdlib.h>
24#include <time.h>
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28#include <gtk/gtk.h>
29
30#ifdef G_OS_WIN32
31# include <io.h>
32# define localtime_r(t,b) *(b) = *localtime (t)
33# ifndef S_ISREG
34# define S_ISREG(m) ((m) & _S_IFREG)
35# endif
36#endif
37
38#if 0
39static GtkWidget *preview_label;
40static GtkWidget *preview_image;
41#endif
42static GtkFileChooserAction action;
43
44static void
45response_cb (GtkDialog *dialog,
46 int response_id,
47 gpointer data)
48{
49 gboolean *done = data;
50
51 if (response_id == GTK_RESPONSE_OK)
52 {
53 GListModel *files;
54 guint i, n;
55
56 files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (dialog));
57 n = g_list_model_get_n_items (list: files);
58
59 g_print (format: "Selected files:\n");
60 for (i = 0; i < n; i++)
61 {
62 GFile *file = g_list_model_get_item (list: files, position: i);
63 char *uri = g_file_get_uri (file);
64 g_print (format: " %s\n", uri ? uri : "(null)");
65 g_free (mem: uri);
66 g_object_unref (object: file);
67 }
68
69 g_object_unref (object: files);
70 }
71 else
72 g_print (format: "Dialog was closed\n");
73
74 *done = TRUE;
75
76 g_main_context_wakeup (NULL);
77}
78
79static void
80filter_changed (GtkFileChooserDialog *dialog,
81 gpointer data)
82{
83 g_print (format: "file filter changed\n");
84}
85
86#include <stdio.h>
87#include <errno.h>
88#define _(s) (s)
89
90
91static void
92set_current_folder (GtkFileChooser *chooser,
93 const char *name)
94{
95 GFile *file = g_file_new_for_path (path: name);
96 if (!gtk_file_chooser_set_current_folder (chooser, file, NULL))
97 {
98 GtkWidget *dialog;
99
100 dialog = gtk_message_dialog_new (GTK_WINDOW (chooser),
101 flags: GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
102 type: GTK_MESSAGE_ERROR,
103 buttons: GTK_BUTTONS_CLOSE,
104 message_format: "Could not set the folder to %s",
105 name);
106 gtk_widget_show (widget: dialog);
107 g_signal_connect (dialog, "response",
108 G_CALLBACK (gtk_window_destroy),
109 NULL);
110 }
111 g_object_unref (object: file);
112}
113
114static void
115set_folder_nonexistent_cb (GtkButton *button,
116 GtkFileChooser *chooser)
117{
118 set_current_folder (chooser, name: "/nonexistent");
119}
120
121static void
122set_folder_existing_nonexistent_cb (GtkButton *button,
123 GtkFileChooser *chooser)
124{
125 set_current_folder (chooser, name: "/usr/nonexistent");
126}
127
128static void
129set_filename (GtkFileChooser *chooser,
130 const char *name)
131{
132 GFile *file = g_file_new_for_path (path: name);
133 if (!gtk_file_chooser_set_file (chooser, file, NULL))
134 {
135 GtkWidget *dialog;
136
137 dialog = gtk_message_dialog_new (GTK_WINDOW (chooser),
138 flags: GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
139 type: GTK_MESSAGE_ERROR,
140 buttons: GTK_BUTTONS_CLOSE,
141 message_format: "Could not select %s",
142 name);
143 gtk_widget_show (widget: dialog);
144 g_signal_connect (dialog, "response",
145 G_CALLBACK (gtk_window_destroy),
146 NULL);
147 }
148 g_object_unref (object: file);
149}
150
151static void
152set_filename_nonexistent_cb (GtkButton *button,
153 GtkFileChooser *chooser)
154{
155 set_filename (chooser, name: "/nonexistent");
156}
157
158static void
159set_filename_existing_nonexistent_cb (GtkButton *button,
160 GtkFileChooser *chooser)
161{
162 set_filename (chooser, name: "/usr/nonexistent");
163}
164
165static void
166get_selection_cb (GtkButton *button,
167 GtkFileChooser *chooser)
168{
169 GListModel *selection;
170 guint i, n;
171
172 selection = gtk_file_chooser_get_files (chooser);
173 n = g_list_model_get_n_items (list: selection);
174
175 g_print (format: "Selection: ");
176
177 for (i = 0; i < n; i++)
178 {
179 GFile *file = g_list_model_get_item (list: selection, position: i);
180 char *uri = g_file_get_uri (file);
181 g_print (format: "%s\n", uri);
182 g_free (mem: uri);
183 g_object_unref (object: file);
184 }
185
186 g_object_unref (object: selection);
187}
188
189static void
190get_current_name_cb (GtkButton *button,
191 GtkFileChooser *chooser)
192{
193 char *name;
194
195 name = gtk_file_chooser_get_current_name (chooser);
196 g_print (format: "Current name: %s\n", name ? name : "NULL");
197 g_free (mem: name);
198}
199
200static void
201unmap_and_remap_cb (GtkButton *button,
202 GtkFileChooser *chooser)
203{
204 gtk_widget_hide (GTK_WIDGET (chooser));
205 gtk_widget_show (GTK_WIDGET (chooser));
206}
207
208static void
209kill_dependent (GtkWindow *win, GtkWidget *dep)
210{
211 gtk_window_destroy (GTK_WINDOW (dep));
212}
213
214int
215main (int argc, char **argv)
216{
217 GtkWidget *control_window;
218 GtkWidget *vbbox;
219 GtkWidget *button;
220 GtkWidget *dialog;
221 GtkFileFilter *filter;
222 gboolean force_rtl = FALSE;
223 gboolean multiple = FALSE;
224 char *action_arg = NULL;
225 char *initial_filename = NULL;
226 char *initial_folder = NULL;
227 GFile *file;
228 GError *error = NULL;
229 GOptionEntry options[] = {
230 { "action", 'a', 0, G_OPTION_ARG_STRING, &action_arg, "Filechooser action", "ACTION" },
231 { "multiple", 'm', 0, G_OPTION_ARG_NONE, &multiple, "Select multiple", NULL },
232 { "right-to-left", 'r', 0, G_OPTION_ARG_NONE, &force_rtl, "Force right-to-left layout.", NULL },
233 { "initial-filename", 'f', 0, G_OPTION_ARG_FILENAME, &initial_filename, "Initial filename to select", "FILENAME" },
234 { "initial-folder", 'F', 0, G_OPTION_ARG_FILENAME, &initial_folder, "Initial folder to show", "FILENAME" },
235 { NULL }
236 };
237 GOptionContext *context;
238 gboolean done = FALSE;
239
240 context = g_option_context_new (parameter_string: "");
241 g_option_context_add_main_entries (context, entries: options, NULL);
242 if (!g_option_context_parse (context, argc: &argc, argv: &argv, error: &error))
243 {
244 g_print (format: "Failed to parse args: %s\n", error->message);
245 g_error_free (error);
246 return 1;
247 }
248 g_option_context_free (context);
249
250 gtk_init ();
251
252 if (initial_filename && initial_folder)
253 {
254 g_print (format: "Only one of --initial-filename and --initial-folder may be specified");
255 return 1;
256 }
257
258 if (force_rtl)
259 gtk_widget_set_default_direction (dir: GTK_TEXT_DIR_RTL);
260
261 action = GTK_FILE_CHOOSER_ACTION_OPEN;
262
263 if (action_arg != NULL)
264 {
265 if (! strcmp (s1: "open", s2: action_arg))
266 action = GTK_FILE_CHOOSER_ACTION_OPEN;
267 else if (! strcmp (s1: "save", s2: action_arg))
268 action = GTK_FILE_CHOOSER_ACTION_SAVE;
269 else if (! strcmp (s1: "select_folder", s2: action_arg))
270 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
271 else
272 {
273 g_print (format: "--action must be one of \"open\", \"save\", \"select_folder\"\n");
274 return 1;
275 }
276
277 g_free (mem: action_arg);
278 }
279
280 dialog = g_object_new (GTK_TYPE_FILE_CHOOSER_DIALOG,
281 first_property_name: "action", action,
282 "select-multiple", multiple,
283 NULL);
284
285 switch (action)
286 {
287 case GTK_FILE_CHOOSER_ACTION_OPEN:
288 case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
289 gtk_window_set_title (GTK_WINDOW (dialog), title: "Select a file");
290 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
291 _("_Cancel"), GTK_RESPONSE_CANCEL,
292 _("_Open"), GTK_RESPONSE_OK,
293 NULL);
294 break;
295 case GTK_FILE_CHOOSER_ACTION_SAVE:
296 gtk_window_set_title (GTK_WINDOW (dialog), title: "Save a file");
297 gtk_dialog_add_buttons (GTK_DIALOG (dialog),
298 _("_Cancel"), GTK_RESPONSE_CANCEL,
299 _("_Save"), GTK_RESPONSE_OK,
300 NULL);
301 break;
302 default:
303 g_assert_not_reached ();
304 }
305 gtk_dialog_set_default_response (GTK_DIALOG (dialog), response_id: GTK_RESPONSE_OK);
306
307 g_signal_connect (dialog, "response",
308 G_CALLBACK (response_cb), &done);
309
310 /* Filters */
311 filter = gtk_file_filter_new ();
312 gtk_file_filter_set_name (filter, name: "All Files");
313 gtk_file_filter_add_pattern (filter, pattern: "*");
314 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
315
316 /* Make this filter the default */
317 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
318 g_object_unref (object: filter);
319
320 filter = gtk_file_filter_new ();
321 gtk_file_filter_set_name (filter, name: "Starts with D");
322 gtk_file_filter_add_pattern (filter, pattern: "D*");
323 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
324 g_object_unref (object: filter);
325
326 g_signal_connect (dialog, "notify::filter",
327 G_CALLBACK (filter_changed), NULL);
328
329 filter = gtk_file_filter_new ();
330 gtk_file_filter_set_name (filter, name: "PNG and JPEG");
331 gtk_file_filter_add_mime_type (filter, mime_type: "image/jpeg");
332 gtk_file_filter_add_mime_type (filter, mime_type: "image/png");
333 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
334 g_object_unref (object: filter);
335
336 filter = gtk_file_filter_new ();
337 gtk_file_filter_set_name (filter, name: "Images");
338 gtk_file_filter_add_pixbuf_formats (filter);
339 gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
340 g_object_unref (object: filter);
341
342 /* Choices */
343
344 gtk_file_chooser_add_choice (GTK_FILE_CHOOSER (dialog), id: "choice1",
345 label: "Choose one:",
346 options: (const char *[]){"one", "two", "three", NULL},
347 option_labels: (const char *[]){"One", "Two", "Three", NULL});
348 gtk_file_chooser_set_choice (GTK_FILE_CHOOSER (dialog), id: "choice1", option: "two");
349
350 /* Shortcuts */
351
352 file = g_file_new_for_uri (uri: "file:///usr/share/pixmaps");
353 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog), folder: file, NULL);
354 g_object_unref (object: file);
355
356 file = g_file_new_for_path (path: g_get_user_special_dir (directory: G_USER_DIRECTORY_MUSIC));
357 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog), folder: file, NULL);
358 g_object_unref (object: file);
359
360 /* Initial filename or folder */
361
362 if (initial_filename)
363 set_filename (GTK_FILE_CHOOSER (dialog), name: initial_filename);
364
365 if (initial_folder)
366 set_current_folder (GTK_FILE_CHOOSER (dialog), name: initial_folder);
367
368 /* show_all() to reveal bugs in composite widget handling */
369 gtk_widget_show (widget: dialog);
370
371 /* Extra controls for manipulating the test environment
372 */
373
374 control_window = gtk_window_new ();
375
376 vbbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 0);
377 gtk_window_set_child (GTK_WINDOW (control_window), child: vbbox);
378
379 button = gtk_button_new_with_label (label: "set_current_folder (\"/nonexistent\")");
380 gtk_box_append (GTK_BOX (vbbox), child: button);
381 g_signal_connect (button, "clicked",
382 G_CALLBACK (set_folder_nonexistent_cb), dialog);
383
384 button = gtk_button_new_with_label (label: "set_current_folder (\"/usr/nonexistent\")");
385 gtk_box_append (GTK_BOX (vbbox), child: button);
386 g_signal_connect (button, "clicked",
387 G_CALLBACK (set_folder_existing_nonexistent_cb), dialog);
388
389 button = gtk_button_new_with_label (label: "set_filename (\"/nonexistent\")");
390 gtk_box_append (GTK_BOX (vbbox), child: button);
391 g_signal_connect (button, "clicked",
392 G_CALLBACK (set_filename_nonexistent_cb), dialog);
393
394 button = gtk_button_new_with_label (label: "set_filename (\"/usr/nonexistent\")");
395 gtk_box_append (GTK_BOX (vbbox), child: button);
396 g_signal_connect (button, "clicked",
397 G_CALLBACK (set_filename_existing_nonexistent_cb), dialog);
398
399 button = gtk_button_new_with_label (label: "Get selection");
400 gtk_box_append (GTK_BOX (vbbox), child: button);
401 g_signal_connect (button, "clicked",
402 G_CALLBACK (get_selection_cb), dialog);
403
404 button = gtk_button_new_with_label (label: "Get current name");
405 gtk_box_append (GTK_BOX (vbbox), child: button);
406 g_signal_connect (button, "clicked",
407 G_CALLBACK (get_current_name_cb), dialog);
408
409 button = gtk_button_new_with_label (label: "Unmap and remap");
410 gtk_box_append (GTK_BOX (vbbox), child: button);
411 g_signal_connect (button, "clicked",
412 G_CALLBACK (unmap_and_remap_cb), dialog);
413
414 gtk_widget_show (widget: control_window);
415
416 g_signal_connect (dialog, "destroy",
417 G_CALLBACK (kill_dependent), control_window);
418
419 /* We need to hold a ref until we have destroyed the widgets, just in case
420 * someone else destroys them. We explicitly destroy windows to catch leaks.
421 */
422 g_object_ref (dialog);
423 while (!done)
424 g_main_context_iteration (NULL, TRUE);
425 gtk_window_destroy (GTK_WINDOW (dialog));
426 g_object_unref (object: dialog);
427
428 return 0;
429}
430

source code of gtk/tests/testfilechooser.c