diff --git a/ChangeLog b/ChangeLog index 034e7e2ff4..1a6e2421b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,140 @@ +2006-05-03 Federico Mena Quintero + + Merged the federico-filename-entry branch, to fix bug #136541. + Combined ChangeLogs: + + 2006-04-17 Federico Mena Quintero + + * gtk/gtkfilechooserdefault.c (pending_select_paths_process): + Oops, we *do* need to check that we are in OPEN mode before + selecting the first row in the file list. See + https://bugzilla.novell.com/show_bug.cgi?id=166906 + (gtk_file_chooser_default_get_paths): If we are in the case for + the file list, and the list has no selected rows, jump to the case + for the filename entry. This is so that + + 1. The user types a filename in the SAVE filename entry + ("foo.txt"). + + 2. He then double-clicks on a folder ("bar") in the file + list. + + will yield the expected "bar/foo.txt" selection. + + 2006-03-29 Federico Mena Quintero + + * gtk/gtkpathbar.c (gtk_path_bar_init): Reduce the inter-button + spacing to 0. + + * gtk/gtkfilechooserdefault.c (browse_widgets_create): Make the + location label bold. + + 2006-03-29 Federico Mena Quintero + + * gtk/gtkfilechooserdefault.c (location_mode_set): Just change the + location_mode field if we are in SAVE/CREATE_FOLDER modes. + (gtk_file_chooser_default_get_paths): Get the path based on the + currently focused widget, or the last-focused widget. This is + what we should have been doing in the beginning, but it worked out + fine because we didn't have the possibility of a filename entry in + OPEN mode. + (gtk_file_chooser_default_should_respond): Handle the case where + the last focused widget is the location_entry. + + 2006-03-28 Federico Mena Quintero + + * gtk/gtkfilechoosersettings.[ch]: New files with a simple + framework for saving/loading settings from the file chooser in + $XDG_CONFIG_HOME/gtk-2.0/gtkfilechooser. + + * gtk/gtkfilechooserdefault.c (gtk_file_chooser_default_unmap): + Save the current settings. + (settings_save): New helper function. We save the location_mode + and show_hidden flags. + (gtk_file_chooser_default_map): Load the settings. + (settings_load): New helper function. + + * gtk/gtkfilechooserentry.c + (_gtk_file_chooser_entry_set_file_part): Oops, don't modify + in_change. Our handlers are what set the file_part, so they + *must* be run when we modify the text. + + 2006-03-27 Federico Mena Quintero + + * gtk/gtkfilechooserprivate.h (struct _GtkFileChooserDefault): + Removed the save_file_name_entry. We'll make this be the same as + the location_entry widget. + (struct _GtkFileChooserDefault): Leave only location_button, + location_entry_box, location_label, location_entry. We'll use a + single toggle button for the location entry, which will appear + below the path bar. + (struct _GtkFileChooserDefault): Added a + processing_pending_selections flag. + + * gtk/gtkfilechooserdefault.c (save_widgets_create): Destroy the + old location_entry if necessary, and hide the location toggle + widgets. + (update_chooser_entry): In multiple selection mode, just clear the + location_entry. + (check_save_entry): Allow running in OPEN or SELECT_FOLDER modes + if we are in LOCATION_MODE_FILENAME_ENTRY. + (gtk_file_chooser_default_should_respond): Switch to a folder if + the location_entry contains a folder name in OPEN and SAVE mode, + not just SAVE mode. If the entry doesn't contain a folder name, + but is otherwise well-formed, and we are in OPEN mode, return that + we should respond with that filename. + (gtk_file_chooser_default_initial_focus): Focus the location_entry + if appropriate. + (browse_widgets_create): Create the location_entry_box and the + location_label here. + (update_appearance): Call location_mode_set() when switching back + to OPEN/SELECT_FOLDER mode. Hide the location_button when + switching to SAVE/CREATE_FOLDER mode. + (pending_select_paths_process): Turn the + processing_pending_selections flag on and off around changes to + the current selection. Don't special-case OPEN mode anymore, + since the new flag will take care of things in + update_chooser_entry(). + (update_chooser_entry): Don't do anything if + processing_pending_selections is TRUE. This keeps the entry from + being polluted when changing folders. + (location_popup_handler): In OPEN/SELECT_FOLDER modes, toggle + between the path bar and the entry. In SAVE/CREATE_FOLDER modes, simply focus the + location_entry. + (update_from_entry): Removed. + (location_entry_create): Removed. + (open_location_cb): Removed. + (file_list_build_popup_menu): Don't add an "Open _Location" menu item. + (location_entry_set_initial_text): Don't do anything if + current_folder is NULL. + + * gtk/gtkfilechooserentry.c + (_gtk_file_chooser_entry_set_file_part): Turn in_change on and off + around the call to gtk_entry_set_text(). This makes completion + not happen when the caller has explicitly set a name. + + 2006-03-24 Federico Mena Quintero + + * gtk/gtkfilechooserprivate.h (struct _GtkFileChooserDefault): + Added fields location_mode_box, location_pathbar_radio, + location_filename_radio, location_widget_box, location_label, + location_entry. The radio buttons will switch between the pathbar + and the location entry; the other boxes are for layout purposes. + (enum LocationMode): New enum. + (struct _GtkFileChooserDefault): Added a location_mode field. + + * gtk/gtkfilechooserdefault.c (browse_widgets_create): Create the + location radio buttons to switch between the pathbar and the + location entry. Pack the browse_path_bar in the new + location_widget_box instead of a generic hbox. + (location_buttons_create): New function. + (gtk_file_chooser_default_init): Initialize impl->location_mode. + (location_switch_to_path_bar): New function. + (location_switch_to_filename_entry): New function. + + * gtk/gtkfilechooserbutton.c (model_add_special): The display_name + should not be const. + 2006-05-03 Matthias Clasen * gtk/gtkprintunixdialog.c: Replace the xpm collate icons diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 034e7e2ff4..1a6e2421b1 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,140 @@ +2006-05-03 Federico Mena Quintero + + Merged the federico-filename-entry branch, to fix bug #136541. + Combined ChangeLogs: + + 2006-04-17 Federico Mena Quintero + + * gtk/gtkfilechooserdefault.c (pending_select_paths_process): + Oops, we *do* need to check that we are in OPEN mode before + selecting the first row in the file list. See + https://bugzilla.novell.com/show_bug.cgi?id=166906 + (gtk_file_chooser_default_get_paths): If we are in the case for + the file list, and the list has no selected rows, jump to the case + for the filename entry. This is so that + + 1. The user types a filename in the SAVE filename entry + ("foo.txt"). + + 2. He then double-clicks on a folder ("bar") in the file + list. + + will yield the expected "bar/foo.txt" selection. + + 2006-03-29 Federico Mena Quintero + + * gtk/gtkpathbar.c (gtk_path_bar_init): Reduce the inter-button + spacing to 0. + + * gtk/gtkfilechooserdefault.c (browse_widgets_create): Make the + location label bold. + + 2006-03-29 Federico Mena Quintero + + * gtk/gtkfilechooserdefault.c (location_mode_set): Just change the + location_mode field if we are in SAVE/CREATE_FOLDER modes. + (gtk_file_chooser_default_get_paths): Get the path based on the + currently focused widget, or the last-focused widget. This is + what we should have been doing in the beginning, but it worked out + fine because we didn't have the possibility of a filename entry in + OPEN mode. + (gtk_file_chooser_default_should_respond): Handle the case where + the last focused widget is the location_entry. + + 2006-03-28 Federico Mena Quintero + + * gtk/gtkfilechoosersettings.[ch]: New files with a simple + framework for saving/loading settings from the file chooser in + $XDG_CONFIG_HOME/gtk-2.0/gtkfilechooser. + + * gtk/gtkfilechooserdefault.c (gtk_file_chooser_default_unmap): + Save the current settings. + (settings_save): New helper function. We save the location_mode + and show_hidden flags. + (gtk_file_chooser_default_map): Load the settings. + (settings_load): New helper function. + + * gtk/gtkfilechooserentry.c + (_gtk_file_chooser_entry_set_file_part): Oops, don't modify + in_change. Our handlers are what set the file_part, so they + *must* be run when we modify the text. + + 2006-03-27 Federico Mena Quintero + + * gtk/gtkfilechooserprivate.h (struct _GtkFileChooserDefault): + Removed the save_file_name_entry. We'll make this be the same as + the location_entry widget. + (struct _GtkFileChooserDefault): Leave only location_button, + location_entry_box, location_label, location_entry. We'll use a + single toggle button for the location entry, which will appear + below the path bar. + (struct _GtkFileChooserDefault): Added a + processing_pending_selections flag. + + * gtk/gtkfilechooserdefault.c (save_widgets_create): Destroy the + old location_entry if necessary, and hide the location toggle + widgets. + (update_chooser_entry): In multiple selection mode, just clear the + location_entry. + (check_save_entry): Allow running in OPEN or SELECT_FOLDER modes + if we are in LOCATION_MODE_FILENAME_ENTRY. + (gtk_file_chooser_default_should_respond): Switch to a folder if + the location_entry contains a folder name in OPEN and SAVE mode, + not just SAVE mode. If the entry doesn't contain a folder name, + but is otherwise well-formed, and we are in OPEN mode, return that + we should respond with that filename. + (gtk_file_chooser_default_initial_focus): Focus the location_entry + if appropriate. + (browse_widgets_create): Create the location_entry_box and the + location_label here. + (update_appearance): Call location_mode_set() when switching back + to OPEN/SELECT_FOLDER mode. Hide the location_button when + switching to SAVE/CREATE_FOLDER mode. + (pending_select_paths_process): Turn the + processing_pending_selections flag on and off around changes to + the current selection. Don't special-case OPEN mode anymore, + since the new flag will take care of things in + update_chooser_entry(). + (update_chooser_entry): Don't do anything if + processing_pending_selections is TRUE. This keeps the entry from + being polluted when changing folders. + (location_popup_handler): In OPEN/SELECT_FOLDER modes, toggle + between the path bar and the entry. In SAVE/CREATE_FOLDER modes, simply focus the + location_entry. + (update_from_entry): Removed. + (location_entry_create): Removed. + (open_location_cb): Removed. + (file_list_build_popup_menu): Don't add an "Open _Location" menu item. + (location_entry_set_initial_text): Don't do anything if + current_folder is NULL. + + * gtk/gtkfilechooserentry.c + (_gtk_file_chooser_entry_set_file_part): Turn in_change on and off + around the call to gtk_entry_set_text(). This makes completion + not happen when the caller has explicitly set a name. + + 2006-03-24 Federico Mena Quintero + + * gtk/gtkfilechooserprivate.h (struct _GtkFileChooserDefault): + Added fields location_mode_box, location_pathbar_radio, + location_filename_radio, location_widget_box, location_label, + location_entry. The radio buttons will switch between the pathbar + and the location entry; the other boxes are for layout purposes. + (enum LocationMode): New enum. + (struct _GtkFileChooserDefault): Added a location_mode field. + + * gtk/gtkfilechooserdefault.c (browse_widgets_create): Create the + location radio buttons to switch between the pathbar and the + location entry. Pack the browse_path_bar in the new + location_widget_box instead of a generic hbox. + (location_buttons_create): New function. + (gtk_file_chooser_default_init): Initialize impl->location_mode. + (location_switch_to_path_bar): New function. + (location_switch_to_filename_entry): New function. + + * gtk/gtkfilechooserbutton.c (model_add_special): The display_name + should not be const. + 2006-05-03 Matthias Clasen * gtk/gtkprintunixdialog.c: Replace the xpm collate icons diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 91fa48c46b..6b1439ec0b 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -329,6 +329,7 @@ gtk_private_h_sources = \ gtkfilechooserembed.h \ gtkfilechooserentry.h \ gtkfilechooserprivate.h \ + gtkfilechoosersettings.h \ gtkfilechooserutils.h \ gtkfilesystemmodel.h \ gtkfilesystemunix.h \ @@ -414,6 +415,7 @@ gtk_c_sources = \ gtkfilechooserdialog.c \ gtkfilechooserembed.c \ gtkfilechooserentry.c \ + gtkfilechoosersettings.c \ gtkfilechooserutils.c \ gtkfilechooserwidget.c \ gtkfilefilter.c \ diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c index 3d46c1cc10..a8b199fe69 100644 --- a/gtk/gtkfilechooserdefault.c +++ b/gtk/gtkfilechooserdefault.c @@ -36,6 +36,7 @@ #include "gtkfilechooserdefault.h" #include "gtkfilechooserembed.h" #include "gtkfilechooserentry.h" +#include "gtkfilechoosersettings.h" #include "gtkfilechooserutils.h" #include "gtkfilechooser.h" #include "gtkfilesystemmodel.h" @@ -53,6 +54,7 @@ #include "gtkmessagedialog.h" #include "gtkpathbar.h" #include "gtkprivate.h" +#include "gtkradiobutton.h" #include "gtkscrolledwindow.h" #include "gtkseparatormenuitem.h" #include "gtksizegroup.h" @@ -410,6 +412,10 @@ static const GtkFileInfo *get_list_file_info (GtkFileChooserDefault *impl, static void load_remove_timer (GtkFileChooserDefault *impl); static void browse_files_center_selected_row (GtkFileChooserDefault *impl); +static void location_button_toggled_cb (GtkToggleButton *toggle, + GtkFileChooserDefault *impl); +static void location_switch_to_path_bar (GtkFileChooserDefault *impl); + @@ -527,7 +533,8 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class) GDK_l, GDK_CONTROL_MASK, "location-popup", 1, G_TYPE_STRING, ""); - + /* FMQ: remove this? */ +#if 0 gtk_binding_entry_add_signal (binding_set, GDK_slash, 0, "location-popup", @@ -542,6 +549,7 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class) GDK_asciitilde, 0, "location-popup", 1, G_TYPE_STRING, "~"); +#endif #endif gtk_binding_entry_add_signal (binding_set, @@ -640,6 +648,7 @@ _gtk_file_chooser_default_init (GtkFileChooserDefault *impl) impl->load_state = LOAD_EMPTY; impl->reload_state = RELOAD_EMPTY; impl->pending_select_paths = NULL; + impl->location_mode = LOCATION_MODE_PATH_BAR; gtk_box_set_spacing (GTK_BOX (impl), 12); @@ -3133,6 +3142,8 @@ tree_view_keybinding_cb (GtkWidget *tree_view, GdkEventKey *event, GtkFileChooserDefault *impl) { + /* FMQ: remove this? */ +#if 0 if ((event->keyval == GDK_slash || event->keyval == GDK_KP_Divide #ifdef G_OS_UNIX @@ -3143,7 +3154,7 @@ tree_view_keybinding_cb (GtkWidget *tree_view, location_popup_handler (impl, event->string); return TRUE; } - +#endif return FALSE; } @@ -3514,7 +3525,9 @@ trap_activate_cb (GtkWidget *widget, impl = (GtkFileChooserDefault *) data; modifiers = gtk_accelerator_get_default_mod_mask (); - + + /* FMQ: remove this? */ +#if 0 if ((event->keyval == GDK_slash || event->keyval == GDK_KP_Divide #ifdef G_OS_UNIX @@ -3525,6 +3538,7 @@ trap_activate_cb (GtkWidget *widget, location_popup_handler (impl, event->string); return TRUE; } +#endif if ((event->keyval == GDK_Return || event->keyval == GDK_ISO_Enter @@ -3573,14 +3587,6 @@ add_to_shortcuts_cb (GtkMenuItem *item, bookmarks_add_selected_folder (impl); } -/* Callback used when the "Open Location" menu item is activated */ -static void -open_location_cb (GtkMenuItem *item, - GtkFileChooserDefault *impl) -{ - location_popup_handler (impl, ""); -} - /* Callback used when the "Show Hidden Files" menu item is toggled */ static void show_hidden_toggled_cb (GtkCheckMenuItem *item, @@ -3802,14 +3808,6 @@ file_list_build_popup_menu (GtkFileChooserDefault *impl) gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item); - item = gtk_image_menu_item_new_with_mnemonic (_("Open _Location")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), - gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU)); - g_signal_connect (item, "activate", - G_CALLBACK (open_location_cb), impl); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item); - item = gtk_separator_menu_item_new (); gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (impl->browse_files_popup_menu), item); @@ -4024,7 +4022,7 @@ create_file_list (GtkFileChooserDefault *impl) gtk_tree_view_column_set_title (column, _("Size")); renderer = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (column, renderer, TRUE); + gtk_tree_view_column_pack_start (column, renderer, TRUE); /* bug: it doesn't expand */ gtk_tree_view_column_set_cell_data_func (column, renderer, list_size_data_func, impl, NULL); gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_SIZE); @@ -4202,6 +4200,8 @@ save_widgets_create (GtkFileChooserDefault *impl) if (impl->save_widgets != NULL) return; + location_switch_to_path_bar (impl); + vbox = gtk_vbox_new (FALSE, 12); table = gtk_table_new (2, 2, FALSE); @@ -4210,7 +4210,7 @@ save_widgets_create (GtkFileChooserDefault *impl) gtk_table_set_row_spacings (GTK_TABLE (table), 12); gtk_table_set_col_spacings (GTK_TABLE (table), 12); - /* Name entry */ + /* Label */ widget = gtk_label_new_with_mnemonic (_("_Name:")); gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); @@ -4220,17 +4220,19 @@ save_widgets_create (GtkFileChooserDefault *impl) 0, 0); gtk_widget_show (widget); - impl->save_file_name_entry = _gtk_file_chooser_entry_new (TRUE); - _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), + /* Location entry */ + + impl->location_entry = _gtk_file_chooser_entry_new (TRUE); + _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->file_system); - gtk_entry_set_width_chars (GTK_ENTRY (impl->save_file_name_entry), 45); - gtk_entry_set_activates_default (GTK_ENTRY (impl->save_file_name_entry), TRUE); - gtk_table_attach (GTK_TABLE (table), impl->save_file_name_entry, + gtk_entry_set_width_chars (GTK_ENTRY (impl->location_entry), 45); + gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE); + gtk_table_attach (GTK_TABLE (table), impl->location_entry, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); - gtk_widget_show (impl->save_file_name_entry); - gtk_label_set_mnemonic_widget (GTK_LABEL (widget), impl->save_file_name_entry); + gtk_widget_show (impl->location_entry); + gtk_label_set_mnemonic_widget (GTK_LABEL (widget), impl->location_entry); /* Folder combo */ impl->save_folder_label = gtk_label_new (NULL); @@ -4274,12 +4276,226 @@ save_widgets_destroy (GtkFileChooserDefault *impl) gtk_widget_destroy (impl->save_widgets); impl->save_widgets = NULL; - impl->save_file_name_entry = NULL; + impl->location_entry = NULL; impl->save_folder_label = NULL; impl->save_folder_combo = NULL; impl->save_expander = NULL; } +/* Turns on the path bar widget. Can be called even if we are already in that + * mode. + */ +static void +location_switch_to_path_bar (GtkFileChooserDefault *impl) +{ + if (impl->location_entry) + { + gtk_widget_destroy (impl->location_entry); + impl->location_entry = NULL; + } + + gtk_widget_hide (impl->location_entry_box); +} + +/* Sets the full path of the current folder as the text in the location entry. */ +static void +location_entry_set_initial_text (GtkFileChooserDefault *impl) +{ + char *text; + + if (!impl->current_folder) + return; + + if (gtk_file_system_path_is_local (impl->file_system, impl->current_folder)) + { + char *filename; + + filename = gtk_file_system_path_to_filename (impl->file_system, impl->current_folder); + if (filename) + { + text = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL); + g_free (filename); + } + else + text = NULL; + } + else + text = gtk_file_system_path_to_uri (impl->file_system, impl->current_folder); + + if (text) + { + gboolean need_slash; + int len; + + len = strlen (text); + need_slash = (text[len - 1] != G_DIR_SEPARATOR); + + if (need_slash) + { + char *slash_text; + + slash_text = g_new (char, len + 2); + strcpy (slash_text, text); + slash_text[len] = G_DIR_SEPARATOR; + slash_text[len + 1] = 0; + + g_free (text); + text = slash_text; + } + + _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), text); + g_free (text); + } +} + +/* Turns on the location entry. Can be called even if we are already in that + * mode. + */ +static void +location_switch_to_filename_entry (GtkFileChooserDefault *impl) +{ + if (impl->location_entry) + gtk_widget_destroy (impl->location_entry); + + /* Box */ + + gtk_widget_show (impl->location_entry_box); + + /* Entry */ + + impl->location_entry = _gtk_file_chooser_entry_new (TRUE); + _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), + impl->file_system); + gtk_entry_set_activates_default (GTK_ENTRY (impl->location_entry), TRUE); + _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action); + + gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_entry, TRUE, TRUE, 0); + gtk_label_set_mnemonic_widget (GTK_LABEL (impl->location_label), impl->location_entry); + + /* Configure the entry */ + + _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->current_folder); + location_entry_set_initial_text (impl); + + /* Done */ + + gtk_widget_show (impl->location_entry); + gtk_widget_grab_focus (impl->location_entry); +} + +/* Sets a new location mode. set_buttons determines whether the toggle button + * for the mode will also be changed. + */ +static void +location_mode_set (GtkFileChooserDefault *impl, + LocationMode new_mode, + gboolean set_button) +{ + if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN + || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) + { + GtkWindow *toplevel; + GtkWidget *current_focus; + gboolean button_active; + gboolean switch_to_file_list; + + switch (new_mode) + { + case LOCATION_MODE_PATH_BAR: + button_active = FALSE; + + /* The location_entry will disappear when we switch to path bar mode. So, + * we'll focus the file list in that case, to avoid having a window with + * no focused widget. + */ + toplevel = get_toplevel (GTK_WIDGET (impl)); + switch_to_file_list = FALSE; + if (toplevel) + { + current_focus = gtk_window_get_focus (toplevel); + if (!current_focus || current_focus == impl->location_entry) + switch_to_file_list = TRUE; + } + + location_switch_to_path_bar (impl); + + if (switch_to_file_list) + gtk_widget_grab_focus (impl->browse_files_tree_view); + + break; + + case LOCATION_MODE_FILENAME_ENTRY: + button_active = TRUE; + location_switch_to_filename_entry (impl); + break; + + default: + g_assert_not_reached (); + return; + } + + if (set_button) + { + g_signal_handlers_block_by_func (impl->location_button, + G_CALLBACK (location_button_toggled_cb), impl); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (impl->location_button), button_active); + + g_signal_handlers_unblock_by_func (impl->location_button, + G_CALLBACK (location_button_toggled_cb), impl); + } + } + + impl->location_mode = new_mode; +} + +/* Callback used when one of the location mode buttons is toggled */ +static void +location_button_toggled_cb (GtkToggleButton *toggle, + GtkFileChooserDefault *impl) +{ + gboolean is_active; + LocationMode new_mode; + + is_active = gtk_toggle_button_get_active (toggle); + + if (is_active) + { + g_assert (impl->location_mode == LOCATION_MODE_PATH_BAR); + new_mode = LOCATION_MODE_FILENAME_ENTRY; + } + else + { + g_assert (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY); + new_mode = LOCATION_MODE_PATH_BAR; + } + + location_mode_set (impl, new_mode, FALSE); +} + +/* Creates a toggle button for the location entry. */ +static void +location_button_create (GtkFileChooserDefault *impl) +{ + GtkWidget *image; + const char *str; + + image = gtk_image_new_from_stock (GTK_STOCK_EDIT, GTK_ICON_SIZE_BUTTON); + gtk_widget_show (image); + + impl->location_button = g_object_new (GTK_TYPE_TOGGLE_BUTTON, + "image", image, + NULL); + + g_signal_connect (impl->location_button, "toggled", + G_CALLBACK (location_button_toggled_cb), impl); + + str = _("Type a file name"); + + gtk_tooltips_set_tip (impl->tooltips, impl->location_button, str, NULL); + atk_object_set_name (gtk_widget_get_accessible (impl->location_button), str); +} + /* Creates the main hpaned with the widgets shared by Open and Save mode */ static GtkWidget * browse_widgets_create (GtkFileChooserDefault *impl) @@ -4294,11 +4510,16 @@ browse_widgets_create (GtkFileChooserDefault *impl) size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); vbox = gtk_vbox_new (FALSE, 12); - /* The path bar and 'Create Folder' button */ + /* Location widgets */ hbox = gtk_hbox_new (FALSE, 12); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); + location_button_create (impl); + gtk_box_pack_start (GTK_BOX (hbox), impl->location_button, FALSE, FALSE, 0); + + /* Path bar */ + impl->browse_path_bar = create_path_bar (impl); g_signal_connect (impl->browse_path_bar, "path-clicked", G_CALLBACK (path_bar_clicked), impl); gtk_widget_show_all (impl->browse_path_bar); @@ -4310,6 +4531,16 @@ browse_widgets_create (GtkFileChooserDefault *impl) G_CALLBACK (new_folder_button_clicked), impl); gtk_box_pack_end (GTK_BOX (hbox), impl->browse_new_folder_button, FALSE, FALSE, 0); + /* Box for the location label and entry */ + + impl->location_entry_box = gtk_hbox_new (FALSE, 12); + gtk_box_pack_start (GTK_BOX (vbox), impl->location_entry_box, FALSE, FALSE, 0); + + impl->location_label = gtk_label_new_with_mnemonic ("_Location:"); + gtk_label_set_use_markup (GTK_LABEL (impl->location_label), TRUE); + gtk_widget_show (impl->location_label); + gtk_box_pack_start (GTK_BOX (impl->location_entry_box), impl->location_label, FALSE, FALSE, 0); + /* Paned widget */ hpaned = gtk_hpaned_new (); gtk_widget_show (hpaned); @@ -4539,6 +4770,7 @@ update_appearance (GtkFileChooserDefault *impl) { const char *text; + gtk_widget_hide (impl->location_button); save_widgets_create (impl); if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) @@ -4548,8 +4780,6 @@ update_appearance (GtkFileChooserDefault *impl) gtk_label_set_text_with_mnemonic (GTK_LABEL (impl->save_folder_label), text); - _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), impl->action); - if (gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander))) { gtk_widget_set_sensitive (impl->save_folder_label, FALSE); @@ -4575,10 +4805,15 @@ update_appearance (GtkFileChooserDefault *impl) else if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) { + gtk_widget_show (impl->location_button); save_widgets_destroy (impl); gtk_widget_show (impl->browse_widgets); + location_mode_set (impl, impl->location_mode, TRUE); } + if (impl->location_entry) + _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->action); + if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN) gtk_widget_hide (impl->browse_new_folder_button); else @@ -5089,6 +5324,40 @@ get_is_file_filtered (GtkFileChooserDefault *impl, return !result; } +static void +settings_load (GtkFileChooserDefault *impl) +{ + GtkFileChooserSettings *settings; + LocationMode location_mode; + gboolean show_hidden; + + settings = _gtk_file_chooser_settings_new (); + + location_mode = _gtk_file_chooser_settings_get_location_mode (settings); + show_hidden = _gtk_file_chooser_settings_get_show_hidden (settings); + + g_object_unref (settings); + + location_mode_set (impl, location_mode, TRUE); + gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden); +} + +static void +settings_save (GtkFileChooserDefault *impl) +{ + GtkFileChooserSettings *settings; + + settings = _gtk_file_chooser_settings_new (); + + _gtk_file_chooser_settings_set_location_mode (settings, impl->location_mode); + _gtk_file_chooser_settings_set_show_hidden (settings, gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl))); + + /* NULL GError */ + _gtk_file_chooser_settings_save (settings, NULL); + + g_object_unref (settings); +} + /* GtkWidget::map method */ static void gtk_file_chooser_default_map (GtkWidget *widget) @@ -5130,6 +5399,8 @@ gtk_file_chooser_default_map (GtkWidget *widget) bookmarks_changed_cb (impl->file_system, impl); + settings_load (impl); + profile_end ("end", NULL); } @@ -5141,6 +5412,8 @@ gtk_file_chooser_default_unmap (GtkWidget *widget) impl = GTK_FILE_CHOOSER_DEFAULT (widget); + settings_save (impl); + GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->unmap (widget); impl->reload_state = RELOAD_WAS_UNMAPPED; @@ -5575,6 +5848,8 @@ pending_select_paths_process (GtkFileChooserDefault *impl) g_assert (impl->browse_files_model != NULL); g_assert (impl->sort_model != NULL); + impl->processing_pending_selections = TRUE; + if (impl->pending_select_paths) { /* NULL GError */ @@ -5601,6 +5876,8 @@ pending_select_paths_process (GtkFileChooserDefault *impl) browse_files_select_first_row (impl); } + impl->processing_pending_selections = FALSE; + g_assert (impl->pending_select_paths == NULL); } @@ -5693,22 +5970,53 @@ set_list_model (GtkFileChooserDefault *impl, return TRUE; } +struct update_chooser_entry_selected_foreach_closure { + int num_selected; + GtkTreeIter first_selected_iter; +}; + +static void +update_chooser_entry_selected_foreach (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + struct update_chooser_entry_selected_foreach_closure *closure; + + closure = data; + closure->num_selected++; + + if (closure->num_selected == 1) + closure->first_selected_iter = *iter; +} + static void update_chooser_entry (GtkFileChooserDefault *impl) { GtkTreeSelection *selection; - const GtkFileInfo *info; - GtkTreeIter iter; - GtkTreeIter child_iter; - gboolean change_entry; + struct update_chooser_entry_selected_foreach_closure closure; + const char *file_part; - if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)) + if (impl->processing_pending_selections) return; - g_assert (!impl->select_multiple); + if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE + || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER + || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN + || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) + && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY))) + return; + + g_assert (impl->location_entry != NULL); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); - if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) + closure.num_selected = 0; + gtk_tree_selection_selected_foreach (selection, update_chooser_entry_selected_foreach, &closure); + + file_part = NULL; + + if (closure.num_selected == 0) { /* If nothing is selected, we only reset the file name entry if we are in * CREATE_FOLDER mode. In SAVE mode, nothing will be selected when the @@ -5717,24 +6025,38 @@ update_chooser_entry (GtkFileChooserDefault *impl) * for a folder name. See http://bugzilla.gnome.org/show_bug.cgi?id=308332 */ if (impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) - _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), ""); - return; + file_part = ""; + } + else if (closure.num_selected == 1) + { + GtkTreeIter child_iter; + const GtkFileInfo *info; + gboolean change_entry; + + gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, + &child_iter, + &closure.first_selected_iter); + + info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter); + + if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN + || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE + || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) + change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */ + else + change_entry = TRUE; /* ... unless we are in CREATE_FOLDER mode */ + + if (change_entry) + file_part = gtk_file_info_get_display_name (info); + } + else + { + /* Multiple selection, so just clear the entry. */ + file_part = ""; } - gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, - &child_iter, - &iter); - - info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter); - - if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) - change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */ - else - change_entry = TRUE; /* ... unless we are in CREATE_FOLDER mode */ - - if (change_entry) - _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), - gtk_file_info_get_display_name (info)); + if (file_part) + _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), file_part); } static gboolean @@ -5808,8 +6130,8 @@ update_current_folder_get_info_cb (GtkFileSystemHandle *handle, /* Set the folder on the save entry */ - if (impl->save_file_name_entry) - _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), + if (impl->location_entry) + _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->current_folder); /* Create a new list model. This is slightly evil; we store the result value @@ -5914,7 +6236,7 @@ gtk_file_chooser_default_set_current_name (GtkFileChooser *chooser, || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER); pending_select_paths_free (impl); - _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry), name); + _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), name); } static void @@ -6083,9 +6405,12 @@ check_save_entry (GtkFileChooserDefault *impl, GError *error; g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE - || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER); + || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER + || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN + || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) + && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)); - chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry); + chooser_entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry); if (strlen (gtk_entry_get_text (GTK_ENTRY (chooser_entry))) == 0) { @@ -6168,16 +6493,45 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser) { GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser); struct get_paths_closure info; + GtkWindow *toplevel; + GtkWidget *current_focus; info.impl = impl; info.result = NULL; info.path_from_entry = NULL; - if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE - || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) + toplevel = get_toplevel (GTK_WIDGET (impl)); + if (toplevel) + current_focus = gtk_window_get_focus (toplevel); + else + current_focus = NULL; + + if (current_focus == impl->browse_files_tree_view) + { + GtkTreeSelection *selection; + + file_list: + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); + gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info); + + /* If there is no selection in the file list, we probably have this situation: + * + * 1. The user typed a filename in the SAVE filename entry ("foo.txt"). + * 2. He then double-clicked on a folder ("bar") in the file list + * + * So we want the selection to be "bar/foo.txt". Jump to the case for the + * filename entry to see if that is the case. + */ + if (info.result == NULL && impl->location_entry) + goto file_entry; + } + else if (impl->location_entry && current_focus == impl->location_entry) { gboolean is_well_formed, is_empty, is_file_part_empty, is_folder; + file_entry: + check_save_entry (impl, &info.path_from_entry, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder); if (!is_well_formed) @@ -6191,19 +6545,23 @@ gtk_file_chooser_default_get_paths (GtkFileChooser *chooser) return NULL; } } - } - if (!info.path_from_entry || impl->select_multiple) + info.result = g_slist_prepend (info.result, info.path_from_entry); + } + else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view) + goto file_list; + else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry) + goto file_entry; + else { - GtkTreeSelection *selection; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view)); - gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info); + /* The focus is on a dialog's action area button or something else */ + if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE + || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) + goto file_entry; + else + goto file_list; } - if (info.path_from_entry) - info.result = g_slist_prepend (info.result, info.path_from_entry); - /* If there's no folder selected, and we're in SELECT_FOLDER mode, then we * fall back to the current directory */ if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER && @@ -6938,7 +7296,7 @@ save_entry_get_info_cb (GtkFileSystemHandle *handle, gboolean retval; const char *file_part; - file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (data->impl->save_file_name_entry)); + file_part = _gtk_file_chooser_entry_get_file_part (GTK_FILE_CHOOSER_ENTRY (data->impl->location_entry)); retval = should_respond_after_confirm_overwrite (data->impl, file_part, data->parent_path); if (retval) @@ -7066,7 +7424,7 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed) g_assert_not_reached (); } } - else if ((impl->save_file_name_entry != NULL) && (current_focus == impl->save_file_name_entry)) + else if ((impl->location_entry != NULL) && (current_focus == impl->location_entry)) { GtkFilePath *path; gboolean is_well_formed, is_empty, is_file_part_empty; @@ -7078,9 +7436,12 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed) save_entry: g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE - || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER); + || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER + || ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN + || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) + && impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)); - entry = GTK_FILE_CHOOSER_ENTRY (impl->save_file_name_entry); + entry = GTK_FILE_CHOOSER_ENTRY (impl->location_entry); check_save_entry (impl, &path, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder); if (is_empty || !is_well_formed) @@ -7091,19 +7452,26 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed) error = NULL; if (is_folder) { - if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) + if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN + || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE) { _gtk_file_chooser_entry_set_file_part (entry, ""); change_folder_and_display_error (impl, path); retval = FALSE; } - else /* GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER */ + else if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER + || GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) { /* The folder already exists, so we do not need to create it. * Just respond to terminate the dialog. */ retval = TRUE; } + else + { + g_assert_not_reached (); + retval = FALSE; + } } else { @@ -7111,7 +7479,9 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed) file_exists_and_is_not_folder = g_error_matches (error, GTK_FILE_SYSTEM_ERROR, GTK_FILE_SYSTEM_ERROR_NOT_FOLDER); - if (impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER && file_exists_and_is_not_folder) + if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN) + retval = TRUE; /* user typed a filename; we are done */ + else if (impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER && file_exists_and_is_not_folder) { /* Oops, the user typed the name of an existing path which is not a folder */ error_creating_folder_over_existing_file_dialog (impl, path, error); @@ -7179,6 +7549,13 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed) */ goto file_list; } + else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry) + { + /* The focus is on a dialog's action area button, *and* the widget that + * was focused immediately before it is the location entry. + */ + goto save_entry; + } else /* The focus is on a dialog's action area button or something else */ if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE @@ -7202,16 +7579,22 @@ gtk_file_chooser_default_initial_focus (GtkFileChooserEmbed *chooser_embed) if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) - widget = impl->browse_files_tree_view; + { + if (impl->location_mode == LOCATION_MODE_PATH_BAR) + widget = impl->browse_files_tree_view; + else + widget = impl->location_entry; + } else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) - widget = impl->save_file_name_entry; + widget = impl->location_entry; else { g_assert_not_reached (); widget = NULL; } + g_assert (widget != NULL); gtk_widget_grab_focus (widget); } @@ -7765,21 +8148,25 @@ list_size_data_func (GtkTreeViewColumn *tree_column, if (!info || gtk_file_info_get_is_folder (info)) { - g_object_set (cell,"sensitive", sensitive, NULL); + g_object_set (cell, + "text", NULL, + "sensitive", sensitive, + NULL); return; } size = gtk_file_info_get_size (info); - +#if 0 if (size < (gint64)1024) str = g_strdup_printf (ngettext ("%d byte", "%d bytes", (gint)size), (gint)size); else if (size < (gint64)1024*1024) - str = g_strdup_printf (_("%.1f K"), size / (1024.)); + str = g_strdup_printf (_("%.1f KB"), size / (1024.)); else if (size < (gint64)1024*1024*1024) - str = g_strdup_printf (_("%.1f M"), size / (1024.*1024.)); + str = g_strdup_printf (_("%.1f MB"), size / (1024.*1024.)); else - str = g_strdup_printf (_("%.1f G"), size / (1024.*1024.*1024.)); - + str = g_strdup_printf (_("%.1f GB"), size / (1024.*1024.*1024.)); +#endif + str = g_strdup_printf ("%" G_GINT64_FORMAT, size); if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) sensitive = FALSE; @@ -7787,6 +8174,7 @@ list_size_data_func (GtkTreeViewColumn *tree_column, g_object_set (cell, "text", str, "sensitive", sensitive, + "alignment", PANGO_ALIGN_RIGHT, NULL); g_free (str); @@ -7870,281 +8258,32 @@ _gtk_file_chooser_default_new (const char *file_system) NULL); } -static GtkWidget * -location_entry_create (GtkFileChooserDefault *impl, - const gchar *path) -{ - GtkWidget *entry; - - entry = _gtk_file_chooser_entry_new (TRUE); - /* Pick a good width for the entry */ - gtk_entry_set_width_chars (GTK_ENTRY (entry), 30); - gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); - _gtk_file_chooser_entry_set_file_system (GTK_FILE_CHOOSER_ENTRY (entry), impl->file_system); - _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (entry), impl->action); - _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (entry), impl->current_folder); - if (path[0]) - gtk_entry_set_text (GTK_ENTRY (entry), path); - else - { - if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN - || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) - _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (entry), ""); - else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE - || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) - _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (entry), - gtk_entry_get_text (GTK_ENTRY (impl->save_file_name_entry))); - else - g_assert_not_reached (); - } - - return GTK_WIDGET (entry); -} - -struct UpdateFromEntryData -{ - GtkFileChooserDefault *impl; - GtkFilePath *subfolder_path; - GtkFilePath *folder_path; - char *file_part; -}; - -static void -update_from_entry_get_info_cb (GtkFileSystemHandle *handle, - const GtkFileInfo *file_info, - const GError *error, - gpointer user_data) -{ - gboolean cancelled = handle->cancelled; - struct UpdateFromEntryData *data = user_data; - - if (handle != data->impl->update_from_entry_handle) - goto out; - - data->impl->update_from_entry_handle = NULL; - - if (cancelled) - goto out; - - if (!file_info) - { - if (data->impl->action == GTK_FILE_CHOOSER_ACTION_SAVE - || data->impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) - { - if (!change_folder_and_display_error (data->impl, data->folder_path)) - goto out; - - gtk_file_chooser_default_set_current_name (GTK_FILE_CHOOSER (data->impl), data->file_part); - } - else - { - GError *err = g_error_copy (error); - - error_getting_info_dialog (data->impl, data->subfolder_path, err); - } - - goto out; - } - - if (gtk_file_info_get_is_folder (file_info)) - change_folder_and_display_error (data->impl, data->subfolder_path); - else - { - gboolean result; - GError *select_error = NULL; - - result = _gtk_file_chooser_select_path (GTK_FILE_CHOOSER (data->impl), data->subfolder_path, &select_error); - - if (!result) - error_dialog (data->impl, _("Could not select item"), - data->subfolder_path, select_error); - } - -out: - g_object_unref (data->impl); - gtk_file_path_free (data->subfolder_path); - gtk_file_path_free (data->folder_path); - g_free (data->file_part); - g_free (data); - - g_object_unref (handle); -} - -static gboolean -update_from_entry (GtkFileChooserDefault *impl, - GtkWindow *parent, - GtkFileChooserEntry *chooser_entry) -{ - const GtkFilePath *folder_path; - const char *file_part; - - folder_path = _gtk_file_chooser_entry_get_current_folder (chooser_entry); - file_part = _gtk_file_chooser_entry_get_file_part (chooser_entry); - - if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN && !folder_path) - { - error_message_with_parent (parent, - _("Cannot change folder"), - _("The folder you specified is an invalid path.")); - return FALSE; - } - - if (file_part[0] == '\0') - return change_folder_and_display_error (impl, folder_path); - else - { - GtkFilePath *subfolder_path = NULL; - GError *error = NULL; - gboolean result = FALSE; - struct UpdateFromEntryData *data; - - /* If the file part is non-empty, we need to figure out if it refers to a - * folder within folder. We could optimize the case here where the folder - * is already loaded for one of our tree models. - */ - - subfolder_path = gtk_file_system_make_path (impl->file_system, folder_path, file_part, &error); - - if (!subfolder_path) - { - char *msg; - char *uri; - - uri = gtk_file_system_path_to_uri (impl->file_system, folder_path); - msg = g_strdup_printf (_("Could not build file name from '%s' and '%s'"), - uri, file_part); - error_message (impl, msg, error->message); - - g_free (uri); - g_free (msg); - gtk_file_path_free (subfolder_path); - - return result; - } - - data = g_new0 (struct UpdateFromEntryData, 1); - data->impl = g_object_ref (impl); - data->folder_path = gtk_file_path_copy (folder_path); - data->subfolder_path = subfolder_path; - data->file_part = g_strdup (file_part); - - if (impl->update_from_entry_handle) - gtk_file_system_cancel_operation (impl->update_from_entry_handle); - - impl->update_from_entry_handle = - gtk_file_system_get_info (impl->file_system, subfolder_path, - GTK_FILE_INFO_IS_FOLDER, - update_from_entry_get_info_cb, data); - - return TRUE; - } - - g_assert_not_reached (); -} - static void location_popup_handler (GtkFileChooserDefault *impl, const gchar *path) { - GtkWidget *dialog; - GtkWindow *toplevel; - GtkWidget *hbox; - GtkWidget *label; - GtkWidget *entry; - gboolean refocus; - const char *title; - const char *accept_stock; - - /* Create dialog */ - - toplevel = get_toplevel (GTK_WIDGET (impl)); - if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) { - title = _("Open Location"); - accept_stock = GTK_STOCK_OPEN; - } - else - { - g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE - || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER); - title = _("Save in Location"); - accept_stock = GTK_STOCK_SAVE; - } + LocationMode new_mode; - dialog = gtk_dialog_new_with_buttons (title, - toplevel, - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - accept_stock, GTK_RESPONSE_ACCEPT, - NULL); - if (toplevel->group) - gtk_window_group_add_window (toplevel->group, GTK_WINDOW (dialog)); - - gtk_window_set_default_size (GTK_WINDOW (dialog), 300, -1); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); - gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2); - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); - - gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog), - GTK_RESPONSE_ACCEPT, - GTK_RESPONSE_CANCEL, - -1); - - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, FALSE, FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); - - label = gtk_label_new_with_mnemonic (_("_Location:")); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); - - entry = location_entry_create (impl, path); - - gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry); - - /* Run */ - - gtk_widget_show_all (dialog); - /* If the dialog is brought up by typing the first characters - * of a path, unselect the text in the entry, so that you can - * just type on without erasing the initial part. - */ - if (path[0]) - gtk_editable_select_region (GTK_EDITABLE (entry), -1, -1); - - refocus = TRUE; - - if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) - { - if (update_from_entry (impl, GTK_WINDOW (dialog), GTK_FILE_CHOOSER_ENTRY (entry))) + if (impl->location_mode == LOCATION_MODE_PATH_BAR) + new_mode = LOCATION_MODE_FILENAME_ENTRY; + else if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY) + new_mode = LOCATION_MODE_PATH_BAR; + else { - if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN - || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) - { - gtk_widget_grab_focus (impl->browse_files_tree_view); - } - else - { - g_assert (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE - || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER); - gtk_widget_grab_focus (impl->save_file_name_entry); - } - refocus = FALSE; + g_assert_not_reached (); + return; } + + location_mode_set (impl, new_mode, TRUE); } - - if (refocus) - { - GtkWindow *toplevel; - - toplevel = get_toplevel (GTK_WIDGET (impl)); - if (toplevel && toplevel->focus_widget) - gtk_widget_grab_focus (toplevel->focus_widget); - } - - gtk_widget_destroy (dialog); + else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE + || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER) + gtk_widget_grab_focus (impl->location_entry); + else + g_assert_not_reached (); } /* Handler for the "up-folder" keybinding signal */ diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h index 34ad17b40b..abfcddc9c6 100644 --- a/gtk/gtkfilechooserprivate.h +++ b/gtk/gtkfilechooserprivate.h @@ -142,6 +142,11 @@ typedef enum { RELOAD_WAS_UNMAPPED /* We had a folder but got unmapped; reload is needed */ } ReloadState; +typedef enum { + LOCATION_MODE_PATH_BAR, + LOCATION_MODE_FILENAME_ENTRY +} LocationMode; + struct _GtkFileChooserDefault { GtkVBox parent_instance; @@ -153,7 +158,6 @@ struct _GtkFileChooserDefault /* Save mode widgets */ GtkWidget *save_widgets; - GtkWidget *save_file_name_entry; GtkWidget *save_folder_label; GtkWidget *save_folder_combo; GtkWidget *save_expander; @@ -183,6 +187,12 @@ struct _GtkFileChooserDefault GtkWidget *extra_align; GtkWidget *extra_widget; + GtkWidget *location_button; + GtkWidget *location_entry_box; + GtkWidget *location_label; + GtkWidget *location_entry; + LocationMode location_mode; + GtkListStore *shortcuts_model; GtkTreeModel *shortcuts_filter_model; @@ -253,6 +263,7 @@ struct _GtkFileChooserDefault guint list_sort_ascending : 1; guint changing_folder : 1; guint shortcuts_current_folder_active : 1; + guint processing_pending_selections : 1; #if 0 guint shortcuts_drag_outside : 1; diff --git a/gtk/gtkfilechoosersettings.c b/gtk/gtkfilechoosersettings.c new file mode 100644 index 0000000000..861ca3f43f --- /dev/null +++ b/gtk/gtkfilechoosersettings.c @@ -0,0 +1,535 @@ +/* GTK - The GIMP Toolkit + * gtkfilechoosersettings.c: Internal settings for the GtkFileChooser widget + * Copyright (C) 2006, Novell, Inc. + * + * Authors: Federico Mena-Quintero + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* TODO: + * + * - Persist these: + * - hpaned position + * - browse_for_other_folders? + * + * - Do we want lockdown? + */ + +#include +#include +#include +#include +#include "gtkfilechoosersettings.h" + +/* Increment this every time you change the configuration format */ +#define CONFIG_VERSION 0 + +#define ELEMENT_TOPLEVEL "gtkfilechooser" +#define ELEMENT_LOCATION "location" +#define ELEMENT_SHOW_HIDDEN "show_hidden" +#define ATTRIBUTE_VERSION "version" +#define ATTRIBUTE_MODE "mode" +#define ATTRIBUTE_VALUE "value" +#define MODE_PATH_BAR "path-bar" +#define MODE_FILENAME_ENTRY "filename-entry" +#define VALUE_TRUE "true" +#define VALUE_FALSE "false" + +#define EQ(a, b) (g_ascii_strcasecmp ((a), (b)) == 0) + +static char * +get_config_dirname (void) +{ + return g_build_filename (g_get_user_config_dir (), "gtk-2.0", NULL); +} + +static char * +get_config_filename (void) +{ + return g_build_filename (g_get_user_config_dir (), "gtk-2.0", "gtkfilechooser", NULL); +} + +static void +set_defaults (GtkFileChooserSettings *settings) +{ + settings->location_mode = LOCATION_MODE_PATH_BAR; + settings->show_hidden = FALSE; +} + +typedef enum { + STATE_START, + STATE_END, + STATE_ERROR, + STATE_IN_TOPLEVEL, + STATE_IN_LOCATION, + STATE_IN_SHOW_HIDDEN +} State; + +struct parse_state { + GtkFileChooserSettings *settings; + int version; + State state; +}; + +static const char * +get_attribute_value (const char **attribute_names, + const char **attribute_values, + const char *attribute) +{ + const char **name; + const char **value; + + name = attribute_names; + value = attribute_values; + + while (*name) + { + if (EQ (*name, attribute)) + return *value; + + name++; + value++; + } + + return NULL; +} + +static void +set_missing_attribute_error (struct parse_state *state, + int line, + int col, + const char *attribute, + GError **error) +{ + state->state = STATE_ERROR; + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + _("Line %d, column %d: missing attribute \"%s\""), + line, + col, + attribute); +} + +static void +set_unexpected_element_error (struct parse_state *state, + int line, + int col, + const char *element, + GError **error) +{ + state->state = STATE_ERROR; + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ELEMENT, + _("Line %d, column %d: unexpected element \"%s\""), + line, + col, + element); +} + +static void +set_unexpected_element_end_error (struct parse_state *state, + int line, + int col, + const char *expected_element, + const char *unexpected_element, + GError **error) +{ + state->state = STATE_ERROR; + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ELEMENT, + _("Line %d, column %d: expected end of element \"%s\", but got element for \"%s\" instead"), + line, + col, + expected_element, + unexpected_element); +} + + +static void +parse_start_element_cb (GMarkupParseContext *context, + const char *element_name, + const char **attribute_names, + const char **attribute_values, + gpointer data, + GError **error) +{ + struct parse_state *state; + int line, col; + + state = data; + g_markup_parse_context_get_position (context, &line, &col); + + switch (state->state) + { + case STATE_START: + if (EQ (element_name, ELEMENT_TOPLEVEL)) + { + const char *version_str; + + state->state = STATE_IN_TOPLEVEL; + + version_str = get_attribute_value (attribute_names, attribute_values, ATTRIBUTE_VERSION); + if (!version_str) + state->version = -1; + else + if (sscanf (version_str, "%d", &state->version) != 1 || state->version < 0) + state->version = -1; + } + else + { + state->state = STATE_ERROR; + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ELEMENT, + _("Line %d, column %d: expected \"%s\" at the toplevel, but found \"%s\" instead"), + line, + col, + ELEMENT_TOPLEVEL, + element_name); + } + break; + + case STATE_END: + g_assert_not_reached (); + break; + + case STATE_ERROR: + g_assert_not_reached (); + break; + + case STATE_IN_TOPLEVEL: + if (EQ (element_name, ELEMENT_LOCATION)) + { + const char *location_mode_str; + + state->state = STATE_IN_LOCATION; + + location_mode_str = get_attribute_value (attribute_names, attribute_values, ATTRIBUTE_MODE); + if (!location_mode_str) + set_missing_attribute_error (state, line, col, ATTRIBUTE_MODE, error); + else if (EQ (location_mode_str, MODE_PATH_BAR)) + state->settings->location_mode = LOCATION_MODE_PATH_BAR; + else if (EQ (location_mode_str, MODE_FILENAME_ENTRY)) + state->settings->location_mode = LOCATION_MODE_FILENAME_ENTRY; + else + { + state->state = STATE_ERROR; + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + _("Line %d, column %d: expected \"%s\" or \"%s\", but found \"%s\" instead"), + line, + col, + MODE_PATH_BAR, + MODE_FILENAME_ENTRY, + location_mode_str); + } + } + else if (EQ (element_name, ELEMENT_SHOW_HIDDEN)) + { + const char *value_str; + + state->state = STATE_IN_SHOW_HIDDEN; + + value_str = get_attribute_value (attribute_names, attribute_values, ATTRIBUTE_VALUE); + + if (!value_str) + set_missing_attribute_error (state, line, col, ATTRIBUTE_VALUE, error); + else if (EQ (value_str, VALUE_TRUE)) + state->settings->show_hidden = TRUE; + else if (EQ (value_str, VALUE_FALSE)) + state->settings->show_hidden = FALSE; + else + { + state->state = STATE_ERROR; + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + _("Line %d, column %d: expected \"%s\" or \"%s\", but found \"%s\" instead"), + line, + col, + VALUE_FALSE, + VALUE_TRUE, + value_str); + } + } + else + set_unexpected_element_error (state, line, col, element_name, error); + + break; + + case STATE_IN_LOCATION: + case STATE_IN_SHOW_HIDDEN: + set_unexpected_element_error (state, line, col, element_name, error); + break; + + default: + g_assert_not_reached (); + } +} + +static void +parse_end_element_cb (GMarkupParseContext *context, + const char *element_name, + gpointer data, + GError **error) +{ + struct parse_state *state; + int line, col; + + state = data; + g_markup_parse_context_get_position (context, &line, &col); + + switch (state->state) + { + case STATE_START: + g_assert_not_reached (); + break; + + case STATE_END: + g_assert_not_reached (); + break; + + case STATE_ERROR: + g_assert_not_reached (); + break; + + case STATE_IN_TOPLEVEL: + if (EQ (element_name, ELEMENT_TOPLEVEL)) + state->state = STATE_END; + else + set_unexpected_element_end_error (state, line, col, ELEMENT_TOPLEVEL, element_name, error); + + break; + + case STATE_IN_LOCATION: + if (EQ (element_name, ELEMENT_LOCATION)) + state->state = STATE_IN_TOPLEVEL; + else + set_unexpected_element_end_error (state, line, col, ELEMENT_LOCATION, element_name, error); + + break; + + case STATE_IN_SHOW_HIDDEN: + if (EQ (element_name, ELEMENT_SHOW_HIDDEN)) + state->state = STATE_IN_TOPLEVEL; + else + set_unexpected_element_end_error (state, line, col, ELEMENT_SHOW_HIDDEN, element_name, error); + + break; + + default: + g_assert_not_reached (); + } +} + +static gboolean +parse_config (GtkFileChooserSettings *settings, + const char *contents, + GError **error) +{ + GMarkupParser parser = { 0, }; + GMarkupParseContext *context; + struct parse_state state; + gboolean retval; + + parser.start_element = parse_start_element_cb; + parser.end_element = parse_end_element_cb; + + state.settings = settings; + state.version = -1; + state.state = STATE_START; + + context = g_markup_parse_context_new (&parser, + 0, + &state, + NULL); + + retval = g_markup_parse_context_parse (context, contents, -1, error); + g_markup_parse_context_free (context); + + return retval; +} + +static gboolean +read_config (GtkFileChooserSettings *settings, + GError **error) +{ + char *filename; + char *contents; + gsize contents_len; + gboolean success; + + filename = get_config_filename (); + + success = g_file_get_contents (filename, &contents, &contents_len, error); + g_free (filename); + + if (!success) + { + set_defaults (settings); + return FALSE; + } + + success = parse_config (settings, contents, error); + + g_free (contents); + + return success; +} + +static void +ensure_settings_read (GtkFileChooserSettings *settings) +{ + if (settings->settings_read) + return; + + /* NULL GError */ + read_config (settings, NULL); + + settings->settings_read = TRUE; +} + +G_DEFINE_TYPE (GtkFileChooserSettings, + _gtk_file_chooser_settings, + G_TYPE_OBJECT); + +static void +_gtk_file_chooser_settings_class_init (GtkFileChooserSettingsClass *class) +{ +} + +static void +_gtk_file_chooser_settings_init (GtkFileChooserSettings *settings) +{ +} + +GtkFileChooserSettings * +_gtk_file_chooser_settings_new (void) +{ + return g_object_new (GTK_FILE_CHOOSER_SETTINGS_TYPE, NULL); +} + +LocationMode +_gtk_file_chooser_settings_get_location_mode (GtkFileChooserSettings *settings) +{ + ensure_settings_read (settings); + return settings->location_mode; +} + +void +_gtk_file_chooser_settings_set_location_mode (GtkFileChooserSettings *settings, + LocationMode location_mode) +{ + settings->location_mode = location_mode; +} + +gboolean +_gtk_file_chooser_settings_get_show_hidden (GtkFileChooserSettings *settings) +{ + ensure_settings_read (settings); + return settings->show_hidden; +} + +void +_gtk_file_chooser_settings_set_show_hidden (GtkFileChooserSettings *settings, + gboolean show_hidden) +{ + settings->show_hidden = show_hidden ? TRUE : FALSE; +} + +static char * +settings_to_markup (GtkFileChooserSettings *settings) +{ + const char *location_mode_str; + const char *show_hidden_str; + + if (settings->location_mode == LOCATION_MODE_PATH_BAR) + location_mode_str = MODE_PATH_BAR; + else if (settings->location_mode == LOCATION_MODE_FILENAME_ENTRY) + location_mode_str = MODE_FILENAME_ENTRY; + else + { + g_assert_not_reached (); + return NULL; + } + + show_hidden_str = settings->show_hidden ? VALUE_TRUE : VALUE_FALSE; + + return g_strdup_printf + ("<" ELEMENT_TOPLEVEL ">\n" /* */ + " <" ELEMENT_LOCATION " " ATTRIBUTE_MODE "=\"%s\"/>\n" /* */ + " <" ELEMENT_SHOW_HIDDEN " " ATTRIBUTE_VALUE "=\"%s\"/>\n" /* */ + "\n", /* */ + location_mode_str, + show_hidden_str); +} + +gboolean +_gtk_file_chooser_settings_save (GtkFileChooserSettings *settings, + GError **error) +{ + char *contents; + char *filename; + char *dirname; + gboolean retval; + + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + contents = settings_to_markup (settings); + + filename = get_config_filename (); + dirname = NULL; + + retval = FALSE; + + if (!g_file_set_contents (filename, contents, -1, NULL)) + { + char *dirname; + int saved_errno; + + /* Directory is not there? */ + + dirname = get_config_dirname (); + if (g_mkdir_with_parents (dirname, 0700) != 0) /* 0700 per the XDG basedir spec */ + { + saved_errno = errno; + g_set_error (error, + G_FILE_ERROR, + g_file_error_from_errno (saved_errno), + _("Could not create directory: %s"), + dirname); + goto out; + } + + if (!g_file_set_contents (filename, contents, -1, error)) + goto out; + } + + retval = TRUE; + + out: + + g_free (contents); + g_free (dirname); + g_free (filename); + + return retval; +} diff --git a/gtk/gtkfilechoosersettings.h b/gtk/gtkfilechoosersettings.h new file mode 100644 index 0000000000..47f6abba68 --- /dev/null +++ b/gtk/gtkfilechoosersettings.h @@ -0,0 +1,75 @@ +/* GTK - The GIMP Toolkit + * gtkfilechoosersettings.h: Internal settings for the GtkFileChooser widget + * Copyright (C) 2006, Novell, Inc. + * + * Authors: Federico Mena-Quintero + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_FILE_CHOOSER_SETTINGS_H__ +#define __GTK_FILE_CHOOSER_SETTINGS_H__ + +#include +#include "gtkfilechooserprivate.h" + +G_BEGIN_DECLS + +#define GTK_FILE_CHOOSER_SETTINGS_TYPE (_gtk_file_chooser_settings_get_type ()) + +typedef struct _GtkFileChooserSettings GtkFileChooserSettings; +typedef struct _GtkFileChooserSettingsClass GtkFileChooserSettingsClass; + +struct _GtkFileChooserSettings +{ + GObject object; + + LocationMode location_mode; + + guint settings_read : 1; + + guint show_hidden : 1; +}; + +struct _GtkFileChooserSettingsClass +{ + GObjectClass parent_class; +}; + +GType _gtk_file_chooser_settings_get_type (void) G_GNUC_CONST; + +GtkFileChooserSettings *_gtk_file_chooser_settings_new (void); + +LocationMode _gtk_file_chooser_settings_get_location_mode (GtkFileChooserSettings *settings); +void _gtk_file_chooser_settings_set_location_mode (GtkFileChooserSettings *settings, + LocationMode location_mode); + +gboolean _gtk_file_chooser_settings_get_show_hidden (GtkFileChooserSettings *settings); +void _gtk_file_chooser_settings_set_show_hidden (GtkFileChooserSettings *settings, + gboolean show_hidden); + +gboolean _gtk_file_chooser_settings_save (GtkFileChooserSettings *settings, + GError **error); + +/* FIXME: persist these options: + * + * - paned width + * - show_hidden + */ + +G_END_DECLS + +#endif diff --git a/gtk/gtkpathbar.c b/gtk/gtkpathbar.c index 2688c1ee36..1e2cac4179 100644 --- a/gtk/gtkpathbar.c +++ b/gtk/gtkpathbar.c @@ -143,7 +143,7 @@ gtk_path_bar_init (GtkPathBar *path_bar) path_bar->set_path_handle = NULL; - path_bar->spacing = 3; + path_bar->spacing = 0; path_bar->up_slider_button = get_slider_button (path_bar, GTK_ARROW_LEFT); path_bar->down_slider_button = get_slider_button (path_bar, GTK_ARROW_RIGHT); path_bar->icon_size = FALLBACK_ICON_SIZE; diff --git a/tests/autotestfilechooser.c b/tests/autotestfilechooser.c index d169042efd..bf654bccb5 100644 --- a/tests/autotestfilechooser.c +++ b/tests/autotestfilechooser.c @@ -147,7 +147,9 @@ test_widgets_for_current_action (GtkFileChooserDialog *dialog, if (has_action (open_actions, G_N_ELEMENTS (open_actions), impl->action)) { passed = passed && (impl->save_widgets == NULL - && impl->save_file_name_entry == NULL + && (impl->location_mode == LOCATION_MODE_PATH_BAR + ? impl->location_entry == NULL + : impl->location_entry != NULL) && impl->save_folder_label == NULL && impl->save_folder_combo == NULL && impl->save_expander == NULL @@ -157,10 +159,10 @@ test_widgets_for_current_action (GtkFileChooserDialog *dialog, { /* FIXME: we can't use GTK_IS_FILE_CHOOSER_ENTRY() because it uses * _gtk_file_chooser_entry_get_type(), which is a non-exported symbol. - * So, we just test impl->save_file_name_entry for being non-NULL + * So, we just test impl->location_entry for being non-NULL */ passed = passed && (GTK_IS_CONTAINER (impl->save_widgets) && GTK_WIDGET_DRAWABLE (impl->save_widgets) - && impl->save_file_name_entry != NULL && GTK_WIDGET_DRAWABLE (impl->save_file_name_entry) + && impl->location_entry != NULL && GTK_WIDGET_DRAWABLE (impl->location_entry) && GTK_IS_LABEL (impl->save_folder_label) && GTK_WIDGET_DRAWABLE (impl->save_folder_label) && GTK_IS_COMBO_BOX (impl->save_folder_combo) && GTK_WIDGET_DRAWABLE (impl->save_folder_combo) && GTK_IS_EXPANDER (impl->save_expander) && GTK_WIDGET_DRAWABLE (impl->save_expander)