summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFederico Mena Quintero <federico@novell.com>2006-05-03 22:30:52 +0000
committerFederico Mena Quintero <federico@src.gnome.org>2006-05-03 22:30:52 +0000
commitd955928bd56bbc333330ec1c8e7cbb14905125d0 (patch)
treef36b63f12763f445fec6a2ee60f946289a7c0bae
parent1657c842f3dc941898e41aae238747def0ac46a9 (diff)
downloadgdk-pixbuf-d955928bd56bbc333330ec1c8e7cbb14905125d0.tar.gz
Merged the federico-filename-entry branch, to fix bug #136541. CombinedAFTER_FEDERICO_FILENAME_ENTRY_MERGE
2006-05-03 Federico Mena Quintero <federico@novell.com> Merged the federico-filename-entry branch, to fix bug #136541. Combined ChangeLogs: 2006-04-17 Federico Mena Quintero <federico@novell.com> * 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 <federico@novell.com> * 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 <federico@novell.com> * 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 <federico@novell.com> * 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 <federico@novell.com> * 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 <federico@novell.com> * 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.
-rw-r--r--ChangeLog137
-rw-r--r--ChangeLog.pre-2-10137
-rw-r--r--gtk/Makefile.am2
-rw-r--r--gtk/gtkfilechooserdefault.c829
-rw-r--r--gtk/gtkfilechooserprivate.h13
-rw-r--r--gtk/gtkfilechoosersettings.c535
-rw-r--r--gtk/gtkfilechoosersettings.h75
-rw-r--r--gtk/gtkpathbar.c2
-rw-r--r--tests/autotestfilechooser.c8
9 files changed, 1388 insertions, 350 deletions
diff --git a/ChangeLog b/ChangeLog
index 034e7e2ff..1a6e2421b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,140 @@
+2006-05-03 Federico Mena Quintero <federico@novell.com>
+
+ Merged the federico-filename-entry branch, to fix bug #136541.
+ Combined ChangeLogs:
+
+ 2006-04-17 Federico Mena Quintero <federico@novell.com>
+
+ * 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 <federico@novell.com>
+
+ * 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 <federico@novell.com>
+
+ * 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 <federico@novell.com>
+
+ * 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 <federico@novell.com>
+
+ * 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 <federico@novell.com>
+
+ * 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 <mclasen@redhat.com>
* gtk/gtkprintunixdialog.c: Replace the xpm collate icons
diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10
index 034e7e2ff..1a6e2421b 100644
--- a/ChangeLog.pre-2-10
+++ b/ChangeLog.pre-2-10
@@ -1,3 +1,140 @@
+2006-05-03 Federico Mena Quintero <federico@novell.com>
+
+ Merged the federico-filename-entry branch, to fix bug #136541.
+ Combined ChangeLogs:
+
+ 2006-04-17 Federico Mena Quintero <federico@novell.com>
+
+ * 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 <federico@novell.com>
+
+ * 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 <federico@novell.com>
+
+ * 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 <federico@novell.com>
+
+ * 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 <federico@novell.com>
+
+ * 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 <federico@novell.com>
+
+ * 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 <mclasen@redhat.com>
* gtk/gtkprintunixdialog.c: Replace the xpm collate icons
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 91fa48c46..6b1439ec0 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 3d46c1cc1..a8b199fe6 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",
@@ -543,6 +550,7 @@ _gtk_file_chooser_default_class_init (GtkFileChooserDefaultClass *class)
"location-popup",
1, G_TYPE_STRING, "~");
#endif
+#endif
gtk_binding_entry_add_signal (binding_set,
GDK_Up, GDK_MOD1_MASK,
@@ -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 ("<b>_Location:</b>");
+ 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,
- &iter);
+ 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);
+ 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... */
+ 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
- change_entry = TRUE; /* ... unless we are in CREATE_FOLDER mode */
+ {
+ /* Multiple selection, so just clear the entry. */
+ file_part = "";
+ }
- 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;
- }
-
- 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);
+ LocationMode new_mode;
- /* 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;
}
- }
-
- if (refocus)
- {
- GtkWindow *toplevel;
- toplevel = get_toplevel (GTK_WIDGET (impl));
- if (toplevel && toplevel->focus_widget)
- gtk_widget_grab_focus (toplevel->focus_widget);
+ location_mode_set (impl, new_mode, TRUE);
}
-
- 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 34ad17b40..abfcddc9c 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 000000000..861ca3f43
--- /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 <federico@novell.com>
+ *
+ * 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 <config.h>
+#include <errno.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#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" /* <gtkfilechooser> */
+ " <" ELEMENT_LOCATION " " ATTRIBUTE_MODE "=\"%s\"/>\n" /* <location mode="path-bar"/> */
+ " <" ELEMENT_SHOW_HIDDEN " " ATTRIBUTE_VALUE "=\"%s\"/>\n" /* <show_hidden value="false"/> */
+ "</" ELEMENT_TOPLEVEL ">\n", /* </gtkfilechooser> */
+ 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 000000000..47f6abba6
--- /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 <federico@novell.com>
+ *
+ * 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 <glib-object.h>
+#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 2688c1ee3..1e2cac417 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 d169042ef..bf654bccb 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)