diff --git a/gtk/gtkfilechooser.c b/gtk/gtkfilechooser.c
index f7676ff5af..edad536877 100644
--- a/gtk/gtkfilechooser.c
+++ b/gtk/gtkfilechooser.c
@@ -1070,31 +1070,26 @@ gtk_file_chooser_get_filename (GtkFileChooser *chooser)
* @chooser: a #GtkFileChooser
* @filename: (type filename): the filename to set as current
*
- * Sets @filename as the current filename for the file chooser, by changing
- * to the file's parent folder and actually selecting the file in list. If
- * the @chooser is in %GTK_FILE_CHOOSER_ACTION_SAVE mode, the file's base name
- * will also appear in the dialog's file name entry.
- *
- * If the file name isn't in the current folder of @chooser, then the current
- * folder of @chooser will be changed to the folder containing @filename. This
- * is equivalent to a sequence of gtk_file_chooser_unselect_all() followed by
- * gtk_file_chooser_select_filename().
+ * Sets @filename as the current filename for the file chooser, by changing to
+ * the file's parent folder and actually selecting the file in list; all other
+ * files will be unselected. If the @chooser is in
+ * %GTK_FILE_CHOOSER_ACTION_SAVE mode, the file's base name will also appear in
+ * the dialog's file name entry.
*
* Note that the file must exist, or nothing will be done except
* for the directory change.
*
- * If you are implementing a File/Save As... dialog,
- * you should use this function if you already have a file name to which the
- * user may save; for example, when the user opens an existing file and then
- * does File/Save As... on it. If you don't have
- * a file name already — for example, if the user just created a new
- * file and is saving it for the first time, do not call this function.
- * Instead, use something similar to this:
+ * You should use this function only when implementing a File/Save
+ * As... dialog for which you already have a file name to which
+ * the user may save. For example, when the user opens an existing file and
+ * then does File/Save As... on it to save a copy or
+ * a modified version. If you don't have a file name already — for
+ * example, if the user just created a new file and is saving it for the first
+ * time, do not call this function. Instead, use something similar to this:
* |[
* if (document_is_new)
* {
* /* the user just created a new document */
- * gtk_file_chooser_set_current_folder (chooser, default_folder_for_saving);
* gtk_file_chooser_set_current_name (chooser, "Untitled document");
* }
* else
@@ -1103,9 +1098,12 @@ gtk_file_chooser_get_filename (GtkFileChooser *chooser)
* gtk_file_chooser_set_filename (chooser, existing_filename);
* }
* ]|
+ *
+ * In the first case, the file chooser will present the user with useful suggestions
+ * as to where to save his new file. In the second case, the file's existing location
+ * is already known, so the file chooser will use it.
*
- * Return value: %TRUE if both the folder could be changed and the file was
- * selected successfully, %FALSE otherwise.
+ * Return value: Not useful.
*
* Since: 2.4
**/
@@ -1128,8 +1126,9 @@ gtk_file_chooser_set_filename (GtkFileChooser *chooser,
* folder of @chooser, then the current folder of @chooser will
* be changed to the folder containing @filename.
*
- * Return value: %TRUE if both the folder could be changed and the file was
- * selected successfully, %FALSE otherwise.
+ * Return value: Not useful.
+ *
+ * See also: gtk_file_chooser_set_filename()
*
* Since: 2.4
**/
@@ -1240,8 +1239,11 @@ gtk_file_chooser_get_filenames (GtkFileChooser *chooser)
* The user will be shown the full contents of the current folder,
* plus user interface elements for navigating to other folders.
*
- * Return value: %TRUE if the folder could be changed successfully, %FALSE
- * otherwise.
+ * In general, you should not use this function. See the section on setting up a file
+ * chooser dialog for the rationale behind this.
+ *
+ * Return value: Not useful.
*
* Since: 2.4
**/
@@ -1312,7 +1314,8 @@ gtk_file_chooser_get_current_folder (GtkFileChooser *chooser)
* Sets the current name in the file selector, as if entered
* by the user. Note that the name passed in here is a UTF-8
* string rather than a filename. This function is meant for
- * such uses as a suggested name in a "Save As..." dialog.
+ * such uses as a suggested name in a "Save As..." dialog. You can
+ * pass "Untitled.doc" or a similarly suitable suggestion for the @name.
*
* If you want to preselect a particular existing file, you should use
* gtk_file_chooser_set_filename() or gtk_file_chooser_set_uri() instead.
@@ -1375,25 +1378,20 @@ gtk_file_chooser_get_uri (GtkFileChooser *chooser)
* list. If the @chooser is %GTK_FILE_CHOOSER_ACTION_SAVE mode, the URI's base
* name will also appear in the dialog's file name entry.
*
- * If the URI isn't in the current folder of @chooser, then the current folder
- * of @chooser will be changed to the folder containing @uri. This is equivalent
- * to a sequence of gtk_file_chooser_unselect_all() followed by
- * gtk_file_chooser_select_uri().
- *
* Note that the URI must exist, or nothing will be done except for the
* directory change.
- * If you are implementing a File/Save As... dialog,
- * you should use this function if you already have a file name to which the
- * user may save; for example, when the user opens an existing file and then
- * does File/Save As... on it. If you don't have
- * a file name already — for example, if the user just created a new
- * file and is saving it for the first time, do not call this function.
- * Instead, use something similar to this:
+ *
+ * You should use this function only when implementing a File/Save
+ * As... dialog for which you already have a file name to which
+ * the user may save. For example, whenthe user opens an existing file and then
+ * does File/Save As... on it to save a copy or a
+ * modified version. If you don't have a file name already — for example,
+ * if the user just created a new file and is saving it for the first time, do
+ * not call this function. Instead, use something similar to this:
* |[
* if (document_is_new)
* {
* /* the user just created a new document */
- * gtk_file_chooser_set_current_folder_uri (chooser, default_folder_for_saving);
* gtk_file_chooser_set_current_name (chooser, "Untitled document");
* }
* else
@@ -1403,8 +1401,12 @@ gtk_file_chooser_get_uri (GtkFileChooser *chooser)
* }
* ]|
*
- * Return value: %TRUE if both the folder could be changed and the URI was
- * selected successfully, %FALSE otherwise.
+ *
+ * In the first case, the file chooser will present the user with useful suggestions
+ * as to where to save his new file. In the second case, the file's existing location
+ * is already known, so the file chooser will use it.
+ *
+ * Return value: Not useful.
*
* Since: 2.4
**/
@@ -1427,8 +1429,7 @@ gtk_file_chooser_set_uri (GtkFileChooser *chooser,
* file in the current folder of @chooser, then the current folder of
* @chooser will be changed to the folder containing @filename.
*
- * Return value: %TRUE if both the folder could be changed and the URI was
- * selected successfully, %FALSE otherwise.
+ * Return value: Not useful.
*
* Since: 2.4
**/
@@ -1545,6 +1546,10 @@ gtk_file_chooser_get_uris (GtkFileChooser *chooser)
* The user will be shown the full contents of the current folder,
* plus user interface elements for navigating to other folders.
*
+ * In general, you should not use this function. See the section on setting up a file
+ * chooser dialog for the rationale behind this.
+ *
* Return value: %TRUE if the folder could be changed successfully, %FALSE
* otherwise.
*
@@ -1661,8 +1666,7 @@ gtk_file_chooser_get_current_folder_file (GtkFileChooser *chooser)
* Selects the file referred to by @file. An internal function. See
* _gtk_file_chooser_select_uri().
*
- * Return value: %TRUE if both the folder could be changed and the path was
- * selected successfully, %FALSE otherwise.
+ * Return value: Not useful.
*
* Since: 2.14
**/
@@ -1760,8 +1764,7 @@ gtk_file_chooser_get_files (GtkFileChooser *chooser)
* }
* ]|
*
- * Return value: %TRUE if both the folder could be changed and the file was
- * selected successfully, %FALSE otherwise.
+ * Return value: Not useful.
*
* Since: 2.14
**/
diff --git a/gtk/gtkfilechooserdefault.c b/gtk/gtkfilechooserdefault.c
index 3d3fc4985a..aab4b04b04 100644
--- a/gtk/gtkfilechooserdefault.c
+++ b/gtk/gtkfilechooserdefault.c
@@ -46,6 +46,7 @@
#include "gtkicontheme.h"
#include "gtkimage.h"
#include "gtkimagemenuitem.h"
+#include "gtkinfobar.h"
#include "gtklabel.h"
#include "gtkmarshalers.h"
#include "gtkmessagedialog.h"
@@ -252,7 +253,6 @@ typedef enum {
#define SETTINGS_KEY_LAST_FOLDER_URI "last-folder-uri"
#define SETTINGS_KEY_LOCATION_MODE "location-mode"
#define SETTINGS_KEY_SHOW_HIDDEN "show-hidden"
-#define SETTINGS_KEY_EXPAND_FOLDERS "expand-folders"
#define SETTINGS_KEY_SHOW_SIZE_COLUMN "show-size-column"
#define SETTINGS_KEY_SORT_COLUMN "sort-column"
#define SETTINGS_KEY_SORT_ORDER "sort-order"
@@ -392,8 +392,6 @@ static void add_bookmark_button_clicked_cb (GtkButton *button,
GtkFileChooserDefault *impl);
static void remove_bookmark_button_clicked_cb (GtkButton *button,
GtkFileChooserDefault *impl);
-static void save_folder_combo_changed_cb (GtkComboBox *combo,
- GtkFileChooserDefault *impl);
static void update_cell_renderer_attributes (GtkFileChooserDefault *impl);
@@ -838,9 +836,6 @@ gtk_file_chooser_default_finalize (GObject *object)
if (impl->shortcuts_pane_filter_model)
g_object_unref (impl->shortcuts_pane_filter_model);
- if (impl->shortcuts_combo_filter_model)
- g_object_unref (impl->shortcuts_combo_filter_model);
-
shortcuts_free (impl);
g_free (impl->browse_files_last_selected_name);
@@ -1529,32 +1524,6 @@ get_file_info_finished (GCancellable *cancellable,
if (request->impl->shortcuts_pane_filter_model)
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_pane_filter_model));
- if (request->impl->shortcuts_combo_filter_model)
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_combo_filter_model));
-
- if (request->type == SHORTCUTS_CURRENT_FOLDER &&
- request->impl->save_folder_combo != NULL)
- {
- /* The current folder is updated via _activate_iter(), don't
- * have save_folder_combo_changed_cb() call _activate_iter()
- * again.
- */
- g_signal_handlers_block_by_func (request->impl->save_folder_combo,
- G_CALLBACK (save_folder_combo_changed_cb),
- request->impl);
-
- if (request->impl->has_search)
- pos -= 1;
-
- if (request->impl->has_recent)
- pos -= 2;
-
- gtk_combo_box_set_active (GTK_COMBO_BOX (request->impl->save_folder_combo), pos);
- g_signal_handlers_unblock_by_func (request->impl->save_folder_combo,
- G_CALLBACK (save_folder_combo_changed_cb),
- request->impl);
- }
-
if (pixbuf)
g_object_unref (pixbuf);
@@ -1740,33 +1709,6 @@ shortcuts_insert_file (GtkFileChooserDefault *impl,
if (impl->shortcuts_pane_filter_model)
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
- if (impl->shortcuts_combo_filter_model)
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
-
- if (type == SHORTCUTS_CURRENT_FOLDER && impl->save_folder_combo != NULL)
- {
- /* The current folder is updated via _activate_iter(), don't
- * have save_folder_combo_changed_cb() call _activate_iter()
- * again.
- */
- gint combo_pos = shortcuts_get_index (impl, SHORTCUTS_CURRENT_FOLDER);
-
- if (impl->has_search)
- combo_pos -= 1;
-
- if (impl->has_recent)
- combo_pos -= 2;
-
- g_signal_handlers_block_by_func (impl->save_folder_combo,
- G_CALLBACK (save_folder_combo_changed_cb),
- impl);
-
- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), combo_pos);
- g_signal_handlers_unblock_by_func (impl->save_folder_combo,
- G_CALLBACK (save_folder_combo_changed_cb),
- impl);
- }
-
g_free (label_copy);
if (pixbuf)
@@ -1819,8 +1761,6 @@ shortcuts_append_recent (GtkFileChooserDefault *impl)
if (pixbuf)
g_object_unref (pixbuf);
-
- impl->has_recent = TRUE;
}
/* Appends an item for the user's home directory to the shortcuts model */
@@ -1936,12 +1876,12 @@ shortcuts_get_index (GtkFileChooserDefault *impl,
if (where == SHORTCUTS_RECENT)
goto out;
- n += impl->has_recent ? 1 : 0;
+ n += 1; /* we always have the recently-used item */
if (where == SHORTCUTS_RECENT_SEPARATOR)
goto out;
- n += impl->has_recent ? 1 : 0;
+ n += 1; /* we always have the separator after the recently-used item */
if (where == SHORTCUTS_HOME)
goto out;
@@ -2053,9 +1993,6 @@ shortcuts_add_volumes (GtkFileChooserDefault *impl)
if (impl->shortcuts_pane_filter_model)
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
- if (impl->shortcuts_combo_filter_model)
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
-
impl->changing_folder = old_changing_folders;
profile_end ("end", NULL);
@@ -2091,7 +2028,6 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
gboolean old_changing_folders;
GtkTreeIter iter;
GFile *list_selected = NULL;
- GFile *combo_selected = NULL;
ShortcutType shortcut_type;
gpointer col_data;
@@ -2112,25 +2048,6 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
list_selected = g_object_ref (col_data);
}
- if (impl->save_folder_combo &&
- gtk_combo_box_get_active_iter (GTK_COMBO_BOX (impl->save_folder_combo),
- &iter))
- {
- GtkTreeIter child_iter;
-
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
- &child_iter,
- &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model),
- &child_iter,
- SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_TYPE, &shortcut_type,
- -1);
-
- if (col_data && shortcut_type == SHORTCUT_TYPE_FILE)
- combo_selected = g_object_ref (col_data);
- }
-
if (impl->num_bookmarks > 0)
shortcuts_remove_rows (impl,
shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR),
@@ -2150,34 +2067,12 @@ shortcuts_add_bookmarks (GtkFileChooserDefault *impl)
if (impl->shortcuts_pane_filter_model)
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
- if (impl->shortcuts_combo_filter_model)
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
-
if (list_selected)
{
shortcuts_find_folder (impl, list_selected);
g_object_unref (list_selected);
}
- if (combo_selected)
- {
- gint pos;
-
- pos = shortcut_find_position (impl, combo_selected);
- if (pos != -1)
- {
- if (impl->has_search)
- pos -= 1;
-
- if (impl->has_recent)
- pos -= 2;
-
- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
- }
-
- g_object_unref (combo_selected);
- }
-
impl->changing_folder = old_changing_folders;
profile_end ("end", NULL);
@@ -2219,16 +2114,6 @@ shortcuts_add_current_folder (GtkFileChooserDefault *impl)
if (base_file)
g_object_unref (base_file);
}
- else if (impl->save_folder_combo != NULL)
- {
- if (impl->has_search)
- pos -= 1;
-
- if (impl->has_recent)
- pos -= 2; /* + separator */
-
- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
- }
}
/* Updates the current folder row in the shortcuts model */
@@ -4460,17 +4345,6 @@ create_file_list (GtkFileChooserDefault *impl)
return swin;
}
-static GtkWidget *
-create_path_bar (GtkFileChooserDefault *impl)
-{
- GtkWidget *path_bar;
-
- path_bar = g_object_new (GTK_TYPE_PATH_BAR, NULL);
- _gtk_path_bar_set_file_system (GTK_PATH_BAR (path_bar), impl->file_system);
-
- return path_bar;
-}
-
/* Creates the widgets for the files/folders pane */
static GtkWidget *
file_pane_create (GtkFileChooserDefault *impl,
@@ -4515,173 +4389,11 @@ file_pane_create (GtkFileChooserDefault *impl,
return vbox;
}
-/* Callback used when the "Browse for more folders" expander is toggled */
-static void
-expander_changed_cb (GtkExpander *expander,
- GParamSpec *pspec,
- GtkFileChooserDefault *impl)
-{
- impl->expand_folders = gtk_expander_get_expanded(GTK_EXPANDER (impl->save_expander));
- update_appearance (impl);
-}
-
-/* Callback used when the selection changes in the save folder combo box */
-static void
-save_folder_combo_changed_cb (GtkComboBox *combo,
- GtkFileChooserDefault *impl)
-{
- GtkTreeIter iter;
-
- if (impl->changing_folder)
- return;
-
- if (gtk_combo_box_get_active_iter (combo, &iter))
- {
- GtkTreeIter child_iter;
-
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
- &child_iter,
- &iter);
- shortcuts_activate_iter (impl, &child_iter);
- }
-}
-
-static void
-save_folder_update_tooltip (GtkComboBox *combo,
- GtkFileChooserDefault *impl)
-{
- GtkTreeIter iter;
- gchar *tooltip;
-
- tooltip = NULL;
-
- if (gtk_combo_box_get_active_iter (combo, &iter))
- {
- GtkTreeIter child_iter;
- gpointer col_data;
- ShortcutType shortcut_type;
-
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
- &child_iter,
- &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &child_iter,
- SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_TYPE, &shortcut_type,
- -1);
-
- if (shortcut_type == SHORTCUT_TYPE_FILE)
- tooltip = g_file_get_parse_name (G_FILE (col_data));
- }
-
- gtk_widget_set_tooltip_text (GTK_WIDGET (combo), tooltip);
- gtk_widget_set_has_tooltip (GTK_WIDGET (combo),
- gtk_widget_get_sensitive (GTK_WIDGET (combo)));
- g_free (tooltip);
-}
-
-/* Filter function used to filter out the Search item and its separator.
- * Used for the "Save in folder" combo box, so that these items do not appear in it.
- */
-static gboolean
-shortcuts_combo_filter_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- GtkFileChooserDefault *impl;
- GtkTreePath *tree_path;
- gint *indices;
- int idx;
- gboolean retval;
-
- impl = GTK_FILE_CHOOSER_DEFAULT (data);
-
- g_assert (model == GTK_TREE_MODEL (impl->shortcuts_model));
-
- tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), iter);
- g_assert (tree_path != NULL);
-
- indices = gtk_tree_path_get_indices (tree_path);
-
- retval = TRUE;
-
- if (impl->has_search)
- {
- idx = shortcuts_get_index (impl, SHORTCUTS_SEARCH);
- if (idx == indices[0])
- retval = FALSE;
- }
-
- if (impl->has_recent)
- {
- idx = shortcuts_get_index (impl, SHORTCUTS_RECENT);
- if (idx == indices[0])
- retval = FALSE;
- else
- {
- idx = shortcuts_get_index (impl, SHORTCUTS_RECENT_SEPARATOR);
- if (idx == indices[0])
- retval = FALSE;
- }
- }
-
- gtk_tree_path_free (tree_path);
-
- return retval;
- }
-
-/* Creates the combo box with the save folders */
-static GtkWidget *
-save_folder_combo_create (GtkFileChooserDefault *impl)
-{
- GtkWidget *combo;
- GtkCellRenderer *cell;
-
- impl->shortcuts_combo_filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->shortcuts_model), NULL);
- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
- shortcuts_combo_filter_func,
- impl,
- NULL);
-
- combo = g_object_new (GTK_TYPE_COMBO_BOX,
- "model", impl->shortcuts_combo_filter_model,
- "focus-on-click", FALSE,
- NULL);
- gtk_widget_show (combo);
-
- cell = gtk_cell_renderer_pixbuf_new ();
- gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, FALSE);
- gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
- "pixbuf", SHORTCUTS_COL_PIXBUF,
- "visible", SHORTCUTS_COL_PIXBUF_VISIBLE,
- "sensitive", SHORTCUTS_COL_PIXBUF_VISIBLE,
- NULL);
-
- cell = gtk_cell_renderer_text_new ();
- g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
- gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
- gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
- "text", SHORTCUTS_COL_NAME,
- "sensitive", SHORTCUTS_COL_PIXBUF_VISIBLE,
- NULL);
-
- gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
- shortcuts_row_separator_func,
- NULL, NULL);
-
- g_signal_connect (combo, "changed",
- G_CALLBACK (save_folder_combo_changed_cb), impl);
- g_signal_connect (combo, "changed",
- G_CALLBACK (save_folder_update_tooltip), impl);
-
- return combo;
-}
-
/* Creates the widgets specific to Save mode */
static void
save_widgets_create (GtkFileChooserDefault *impl)
{
GtkWidget *vbox;
- GtkWidget *table;
GtkWidget *widget;
if (impl->save_widgets != NULL)
@@ -4691,18 +4403,18 @@ save_widgets_create (GtkFileChooserDefault *impl)
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- table = gtk_table_new (2, 2, FALSE);
- gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
- gtk_widget_show (table);
- gtk_table_set_row_spacings (GTK_TABLE (table), 12);
- gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+ impl->save_widgets_table = gtk_table_new (2, 2, FALSE);
+ gtk_box_pack_start (GTK_BOX (vbox), impl->save_widgets_table, FALSE, FALSE, 0);
+ gtk_widget_show (impl->save_widgets_table);
+ gtk_table_set_row_spacings (GTK_TABLE (impl->save_widgets_table), 12);
+ gtk_table_set_col_spacings (GTK_TABLE (impl->save_widgets_table), 12);
/* Label */
widget = gtk_label_new_with_mnemonic (_("_Name:"));
gtk_widget_set_halign (widget, GTK_ALIGN_START);
gtk_widget_set_valign (widget, GTK_ALIGN_CENTER);
- gtk_table_attach (GTK_TABLE (table), widget,
+ gtk_table_attach (GTK_TABLE (impl->save_widgets_table), widget,
0, 1, 0, 1,
GTK_FILL, GTK_FILL,
0, 0);
@@ -4716,7 +4428,7 @@ save_widgets_create (GtkFileChooserDefault *impl)
_gtk_file_chooser_entry_set_local_only (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->local_only);
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,
+ gtk_table_attach (GTK_TABLE (impl->save_widgets_table), impl->location_entry,
1, 2, 0, 1,
GTK_EXPAND | GTK_FILL, 0,
0, 0);
@@ -4727,30 +4439,12 @@ save_widgets_create (GtkFileChooserDefault *impl)
impl->save_folder_label = gtk_label_new (NULL);
gtk_widget_set_halign (impl->save_folder_label, GTK_ALIGN_START);
gtk_widget_set_valign (impl->save_folder_label, GTK_ALIGN_CENTER);
- gtk_table_attach (GTK_TABLE (table), impl->save_folder_label,
+ gtk_table_attach (GTK_TABLE (impl->save_widgets_table), impl->save_folder_label,
0, 1, 1, 2,
GTK_FILL, GTK_FILL,
0, 0);
gtk_widget_show (impl->save_folder_label);
- impl->save_folder_combo = save_folder_combo_create (impl);
- gtk_table_attach (GTK_TABLE (table), impl->save_folder_combo,
- 1, 2, 1, 2,
- GTK_EXPAND | GTK_FILL, GTK_FILL,
- 0, 0);
- gtk_label_set_mnemonic_widget (GTK_LABEL (impl->save_folder_label), impl->save_folder_combo);
-
- /* Expander */
-
- impl->save_expander = gtk_expander_new_with_mnemonic (_("_Browse for other folders"));
- gtk_widget_set_halign (impl->save_expander, GTK_ALIGN_START);
- gtk_widget_set_valign (impl->save_expander, GTK_ALIGN_CENTER);
- gtk_box_pack_start (GTK_BOX (vbox), impl->save_expander, FALSE, FALSE, 0);
- g_signal_connect (impl->save_expander, "notify::expanded",
- G_CALLBACK (expander_changed_cb),
- impl);
- gtk_widget_show (impl->save_expander);
-
impl->save_widgets = vbox;
gtk_box_pack_start (GTK_BOX (impl), impl->save_widgets, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (impl), impl->save_widgets, 0);
@@ -4766,10 +4460,9 @@ save_widgets_destroy (GtkFileChooserDefault *impl)
gtk_widget_destroy (impl->save_widgets);
impl->save_widgets = NULL;
+ impl->save_widgets_table = 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
@@ -5021,22 +4714,96 @@ location_button_create (GtkFileChooserDefault *impl)
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)
+typedef enum {
+ PATH_BAR_FOLDER_PATH,
+ PATH_BAR_SELECT_A_FOLDER,
+ PATH_BAR_ERROR_NO_FILENAME,
+ PATH_BAR_ERROR_NO_FOLDER,
+ PATH_BAR_RECENTLY_USED,
+ PATH_BAR_SEARCH
+} PathBarMode;
+
+/* Creates the info bar for informational messages or warnings, with its icon and label */
+static void
+info_bar_create (GtkFileChooserDefault *impl)
{
- GtkWidget *vbox;
- GtkWidget *hpaned;
- GtkWidget *widget;
- GtkSizeGroup *size_group;
+ GtkWidget *content_area;
- /* size group is used by the scrolled windows of the panes */
- size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
- vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ impl->browse_select_a_folder_info_bar = gtk_info_bar_new ();
+ impl->browse_select_a_folder_icon = gtk_image_new_from_stock (GTK_STOCK_DIRECTORY, GTK_ICON_SIZE_MENU);
+ impl->browse_select_a_folder_label = gtk_label_new (NULL);
- /* Location widgets */
+ content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (impl->browse_select_a_folder_info_bar));
+
+ gtk_box_pack_start (GTK_BOX (content_area), impl->browse_select_a_folder_icon, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (content_area), impl->browse_select_a_folder_label, FALSE, FALSE, 0);
+
+ gtk_widget_show (impl->browse_select_a_folder_icon);
+ gtk_widget_show (impl->browse_select_a_folder_label);
+}
+
+/* Sets the info bar to show the appropriate informational or warning message */
+static void
+info_bar_set (GtkFileChooserDefault *impl, PathBarMode mode)
+{
+ char *str;
+ gboolean free_str;
+ GtkMessageType message_type;
+
+ free_str = FALSE;
+
+ switch (mode)
+ {
+ case PATH_BAR_SELECT_A_FOLDER:
+ str = g_strconcat ("", _("Please select a folder below"), "", NULL);
+ free_str = TRUE;
+ message_type = GTK_MESSAGE_OTHER;
+ break;
+
+ case PATH_BAR_ERROR_NO_FILENAME:
+ str = _("Please type a file name");
+ message_type = GTK_MESSAGE_WARNING;
+ break;
+
+ case PATH_BAR_ERROR_NO_FOLDER:
+ str = _("Please select a folder below");
+ message_type = GTK_MESSAGE_WARNING;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ return;
+ }
+
+ gtk_info_bar_set_message_type (GTK_INFO_BAR (impl->browse_select_a_folder_info_bar), message_type);
+ gtk_image_set_from_stock (GTK_IMAGE (impl->browse_select_a_folder_icon),
+ (message_type == GTK_MESSAGE_WARNING) ? GTK_STOCK_DIALOG_WARNING : GTK_STOCK_DIRECTORY,
+ GTK_ICON_SIZE_MENU);
+ gtk_label_set_markup (GTK_LABEL (impl->browse_select_a_folder_label), str);
+
+ if (free_str)
+ g_free (str);
+}
+
+/* Creates the icon and label used to show that the file chooser is in Search or Recently-used mode */
+static void
+special_mode_widgets_create (GtkFileChooserDefault *impl)
+{
+ impl->browse_special_mode_icon = gtk_image_new ();
+ gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->browse_special_mode_icon);
+ gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->browse_special_mode_icon, FALSE, FALSE, 0);
+
+ impl->browse_special_mode_label = gtk_label_new (NULL);
+ gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->browse_special_mode_label);
+ gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->browse_special_mode_label, FALSE, FALSE, 0);
+}
+
+/* Creates the path bar's container and eveyrthing that goes in it: location button, pathbar, info bar, and Create Folder button */
+static void
+path_bar_widgets_create (GtkFileChooserDefault *impl)
+{
+ /* Location widgets - note browse_path_bar_hbox is packed in the right place until switch_path_bar() */
impl->browse_path_bar_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
- gtk_box_pack_start (GTK_BOX (vbox), impl->browse_path_bar_hbox, FALSE, FALSE, 0);
gtk_widget_show (impl->browse_path_bar_hbox);
/* Size group that allows the path bar to be the same size between modes */
@@ -5044,29 +4811,121 @@ browse_widgets_create (GtkFileChooserDefault *impl)
gtk_size_group_set_ignore_hidden (impl->browse_path_bar_size_group, FALSE);
/* Location button */
-
location_button_create (impl);
- gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->location_button, FALSE, FALSE, 0);
gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->location_button);
+ gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->location_button, FALSE, FALSE, 0);
/* Path bar */
-
- impl->browse_path_bar = create_path_bar (impl);
+ impl->browse_path_bar = g_object_new (GTK_TYPE_PATH_BAR, NULL);
+ _gtk_path_bar_set_file_system (GTK_PATH_BAR (impl->browse_path_bar), impl->file_system);
g_signal_connect (impl->browse_path_bar, "path-clicked", G_CALLBACK (path_bar_clicked), impl);
- gtk_widget_show_all (impl->browse_path_bar);
- gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->browse_path_bar, TRUE, TRUE, 0);
+
gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->browse_path_bar);
+ gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->browse_path_bar, TRUE, TRUE, 0);
+
+ /* Info bar */
+ info_bar_create (impl);
+ gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->browse_select_a_folder_info_bar);
+ gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->browse_select_a_folder_info_bar, TRUE, TRUE, 0);
+
+ /* Widgets for special modes (recently-used in Open mode, Search mode) */
+ special_mode_widgets_create (impl);
/* Create Folder */
impl->browse_new_folder_button = gtk_button_new_with_mnemonic (_("Create Fo_lder"));
g_signal_connect (impl->browse_new_folder_button, "clicked",
G_CALLBACK (new_folder_button_clicked), impl);
+ gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->browse_new_folder_button);
gtk_box_pack_end (GTK_BOX (impl->browse_path_bar_hbox), impl->browse_new_folder_button, FALSE, FALSE, 0);
+}
+
+/* Sets the path bar's mode to show a label, the actual folder path, or a
+ * warning message. You may call this function with PATH_BAR_ERROR_* directly
+ * if the pathbar is already showing the widgets you expect; otherwise, call
+ * path_bar_update() instead to set the appropriate widgets automatically.
+ */
+static void
+path_bar_set_mode (GtkFileChooserDefault *impl, PathBarMode mode)
+{
+ gboolean path_bar_visible = FALSE;
+ gboolean special_mode_widgets_visible = FALSE;
+ gboolean info_bar_visible = FALSE;
+ gboolean create_folder_visible = FALSE;
+
+ char *tmp;
+
+ switch (mode)
+ {
+ case PATH_BAR_FOLDER_PATH:
+ path_bar_visible = TRUE;
+ break;
+
+ case PATH_BAR_SELECT_A_FOLDER:
+ case PATH_BAR_ERROR_NO_FILENAME:
+ case PATH_BAR_ERROR_NO_FOLDER:
+ info_bar_set (impl, mode);
+ info_bar_visible = TRUE;
+ break;
+
+ case PATH_BAR_RECENTLY_USED:
+ gtk_image_set_from_icon_name (GTK_IMAGE (impl->browse_special_mode_icon), "document-open-recent", GTK_ICON_SIZE_BUTTON);
+
+ tmp = g_strdup_printf ("%s", _("Recently Used"));
+ gtk_label_set_markup (GTK_LABEL (impl->browse_special_mode_label), tmp);
+ g_free (tmp);
+
+ special_mode_widgets_visible = TRUE;
+ break;
+
+ case PATH_BAR_SEARCH:
+ gtk_image_set_from_stock (GTK_IMAGE (impl->browse_special_mode_icon), GTK_STOCK_FIND, GTK_ICON_SIZE_BUTTON);
+
+ tmp = g_strdup_printf ("%s", _("Search:"));
+ gtk_label_set_markup (GTK_LABEL (impl->browse_special_mode_label), tmp);
+ g_free (tmp);
+
+ special_mode_widgets_visible = TRUE;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ gtk_widget_set_visible (impl->browse_path_bar, path_bar_visible);
+ gtk_widget_set_visible (impl->browse_special_mode_icon, special_mode_widgets_visible);
+ gtk_widget_set_visible (impl->browse_special_mode_label, special_mode_widgets_visible);
+ gtk_widget_set_visible (impl->browse_select_a_folder_info_bar, info_bar_visible);
+
+ if (path_bar_visible)
+ {
+ if (impl->create_folders
+ && impl->action != GTK_FILE_CHOOSER_ACTION_OPEN
+ && impl->operation_mode != OPERATION_MODE_RECENT)
+ create_folder_visible = TRUE;
+ }
+
+ gtk_widget_set_visible (impl->browse_new_folder_button, create_folder_visible);
+}
+
+/* Creates the main hpaned with the widgets shared by Open and Save mode */
+static void
+browse_widgets_create (GtkFileChooserDefault *impl)
+{
+ GtkWidget *hpaned;
+ GtkWidget *widget;
+ GtkSizeGroup *size_group;
+
+ /* size group is used by the scrolled windows of the panes */
+ size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
+ impl->browse_widgets_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+
+ /* Path bar, info bar, and their respective machinery - the browse_path_bar_hbox will get packed elsewhere */
+ path_bar_widgets_create (impl);
/* Box for the location label and entry */
impl->location_entry_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
- gtk_box_pack_start (GTK_BOX (vbox), impl->location_entry_box, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (impl->browse_widgets_box), impl->location_entry_box, FALSE, FALSE, 0);
impl->location_label = gtk_label_new_with_mnemonic (_("_Location:"));
gtk_widget_show (impl->location_label);
@@ -5076,7 +4935,7 @@ browse_widgets_create (GtkFileChooserDefault *impl)
hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
gtk_widget_show (hpaned);
- gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (impl->browse_widgets_box), hpaned, TRUE, TRUE, 0);
widget = shortcuts_pane_create (impl, size_group);
gtk_paned_pack1 (GTK_PANED (hpaned), widget, FALSE, FALSE);
@@ -5084,8 +4943,6 @@ browse_widgets_create (GtkFileChooserDefault *impl)
gtk_paned_pack2 (GTK_PANED (hpaned), widget, TRUE, FALSE);
gtk_paned_set_position (GTK_PANED (hpaned), 148);
g_object_unref (size_group);
-
- return vbox;
}
static GObject*
@@ -5111,8 +4968,8 @@ gtk_file_chooser_default_constructor (GType type,
shortcuts_model_create (impl);
/* The browse widgets */
- impl->browse_widgets = browse_widgets_create (impl);
- gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets, TRUE, TRUE, 0);
+ browse_widgets_create (impl);
+ gtk_box_pack_start (GTK_BOX (impl), impl->browse_widgets_box, TRUE, TRUE, 0);
/* Alignment to hold extra widget */
impl->extra_align = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
@@ -5258,6 +5115,116 @@ unset_file_system_backend (GtkFileChooserDefault *impl)
impl->file_system = NULL;
}
+/* Saves the widgets around the pathbar so they can be reparented later
+ * in the correct place. This function must be called paired with
+ * restore_path_bar().
+ */
+static void
+save_path_bar (GtkFileChooserDefault *impl)
+{
+ GtkWidget *parent;
+
+ g_object_ref (impl->browse_path_bar_hbox);
+
+ parent = gtk_widget_get_parent (impl->browse_path_bar_hbox);
+ if (parent)
+ gtk_container_remove (GTK_CONTAINER (parent), impl->browse_path_bar_hbox);
+}
+
+/* Reparents the path bar and the "Create folder" button to the right place:
+ * Above the file list in Open mode, or to the right of the "Save in folder:"
+ * label in Save mode. The save_path_bar() function must be called before this
+ * one.
+ */
+static void
+restore_path_bar (GtkFileChooserDefault *impl)
+{
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ {
+ gtk_box_pack_start (GTK_BOX (impl->browse_widgets_box), impl->browse_path_bar_hbox, FALSE, FALSE, 0);
+ gtk_box_reorder_child (GTK_BOX (impl->browse_widgets_box), impl->browse_path_bar_hbox, 0);
+ }
+ else if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ {
+ gtk_table_attach (GTK_TABLE (impl->save_widgets_table), impl->browse_path_bar_hbox,
+ 1, 2, 1, 2,
+ GTK_EXPAND | GTK_FILL, GTK_FILL,
+ 0, 0);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (impl->save_folder_label), impl->browse_path_bar);
+ }
+ else
+ g_assert_not_reached ();
+
+ g_object_unref (impl->browse_path_bar_hbox);
+}
+
+/* Takes the folder stored in a row in the recent_model, and puts it in the pathbar */
+static void
+put_recent_folder_in_pathbar (GtkFileChooserDefault *impl, GtkTreeIter *iter)
+{
+ GFile *file;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), iter,
+ MODEL_COL_FILE, &file,
+ -1);
+ _gtk_path_bar_set_file (GTK_PATH_BAR (impl->browse_path_bar), file, FALSE, NULL); /* NULL-GError */
+ g_object_unref (file);
+}
+
+/* Sets the pathbar in the appropriate mode according to the current operation mode and action. This is the central function for
+ * dealing with the pathbar's widgets; as long as impl->action and impl->operation_mode are set correctly, then calling this
+ * function will update all the pathbar's widgets.
+ */
+static void
+path_bar_update (GtkFileChooserDefault *impl)
+{
+ PathBarMode mode;
+
+ switch (impl->operation_mode)
+ {
+ case OPERATION_MODE_BROWSE:
+ mode = PATH_BAR_FOLDER_PATH;
+ break;
+
+ case OPERATION_MODE_RECENT:
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ {
+ GtkTreeSelection *selection;
+ gboolean have_selected;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+
+ /* Save mode means single-selection mode, so the following is valid */
+ have_selected = gtk_tree_selection_get_selected (selection, NULL, &iter);
+
+ if (have_selected)
+ {
+ mode = PATH_BAR_FOLDER_PATH;
+ put_recent_folder_in_pathbar (impl, &iter);
+ }
+ else
+ mode = PATH_BAR_SELECT_A_FOLDER;
+ }
+ else
+ mode = PATH_BAR_RECENTLY_USED;
+
+ break;
+
+ case OPERATION_MODE_SEARCH:
+ mode = PATH_BAR_SEARCH;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ return;
+ }
+
+ path_bar_set_mode (impl, mode);
+}
+
/* This function is basically a do_all function.
*
* It sets the visibility on all the widgets based on the current state, and
@@ -5266,6 +5233,8 @@ unset_file_system_backend (GtkFileChooserDefault *impl)
static void
update_appearance (GtkFileChooserDefault *impl)
{
+ save_path_bar (impl);
+
if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE ||
impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
{
@@ -5281,21 +5250,6 @@ update_appearance (GtkFileChooserDefault *impl)
gtk_label_set_text_with_mnemonic (GTK_LABEL (impl->save_folder_label), text);
- if (gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
- {
- gtk_widget_set_sensitive (impl->save_folder_label, FALSE);
- gtk_widget_set_sensitive (impl->save_folder_combo, FALSE);
- gtk_widget_set_has_tooltip (impl->save_folder_combo, FALSE);
- gtk_widget_show (impl->browse_widgets);
- }
- else
- {
- gtk_widget_set_sensitive (impl->save_folder_label, TRUE);
- gtk_widget_set_sensitive (impl->save_folder_combo, TRUE);
- gtk_widget_set_has_tooltip (impl->save_folder_combo, TRUE);
- gtk_widget_hide (impl->browse_widgets);
- }
-
if (impl->select_multiple)
{
g_warning ("Save mode cannot be set in conjunction with multiple selection mode. "
@@ -5308,17 +5262,15 @@ update_appearance (GtkFileChooserDefault *impl)
{
gtk_widget_show (impl->location_button);
save_widgets_destroy (impl);
- gtk_widget_show (impl->browse_widgets);
+ gtk_widget_show (impl->browse_widgets_box);
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 || !impl->create_folders)
- gtk_widget_hide (impl->browse_new_folder_button);
- else
- gtk_widget_show (impl->browse_new_folder_button);
+ restore_path_bar (impl);
+ path_bar_update (impl);
/* This *is* needed; we need to redraw the file list because the "sensitivity"
* of files may change depending whether we are in a file or folder-only mode.
@@ -5501,33 +5453,11 @@ gtk_file_chooser_default_get_property (GObject *object,
}
}
-/* Removes the settings signal handler. It's safe to call multiple times */
+/* This cancels everything that may be going on in the background. */
static void
-remove_settings_signal (GtkFileChooserDefault *impl,
- GdkScreen *screen)
-{
- if (impl->settings_signal_id)
- {
- GtkSettings *settings;
-
- settings = gtk_settings_get_for_screen (screen);
- g_signal_handler_disconnect (settings,
- impl->settings_signal_id);
- impl->settings_signal_id = 0;
- }
-}
-
-static void
-gtk_file_chooser_default_dispose (GObject *object)
+cancel_all_operations (GtkFileChooserDefault *impl)
{
GSList *l;
- GtkFileChooserDefault *impl = (GtkFileChooserDefault *) object;
-
- if (impl->extra_widget)
- {
- g_object_unref (impl->extra_widget);
- impl->extra_widget = NULL;
- }
pending_select_files_free (impl);
@@ -5597,6 +5527,36 @@ gtk_file_chooser_default_dispose (GObject *object)
search_stop_searching (impl, TRUE);
recent_stop_loading (impl);
+}
+
+/* Removes the settings signal handler. It's safe to call multiple times */
+static void
+remove_settings_signal (GtkFileChooserDefault *impl,
+ GdkScreen *screen)
+{
+ if (impl->settings_signal_id)
+ {
+ GtkSettings *settings;
+
+ settings = gtk_settings_get_for_screen (screen);
+ g_signal_handler_disconnect (settings,
+ impl->settings_signal_id);
+ impl->settings_signal_id = 0;
+ }
+}
+
+static void
+gtk_file_chooser_default_dispose (GObject *object)
+{
+ GtkFileChooserDefault *impl = (GtkFileChooserDefault *) object;
+
+ cancel_all_operations (impl);
+
+ if (impl->extra_widget)
+ {
+ g_object_unref (impl->extra_widget);
+ impl->extra_widget = NULL;
+ }
remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
@@ -5820,14 +5780,12 @@ settings_load (GtkFileChooserDefault *impl)
{
LocationMode location_mode;
gboolean show_hidden;
- gboolean expand_folders;
gboolean show_size_column;
gint sort_column;
GtkSortType sort_order;
settings_ensure (impl);
- expand_folders = g_settings_get_boolean (impl->settings, SETTINGS_KEY_EXPAND_FOLDERS);
location_mode = g_settings_get_enum (impl->settings, SETTINGS_KEY_LOCATION_MODE);
show_hidden = g_settings_get_boolean (impl->settings, SETTINGS_KEY_SHOW_HIDDEN);
show_size_column = g_settings_get_boolean (impl->settings, SETTINGS_KEY_SHOW_SIZE_COLUMN);
@@ -5838,10 +5796,6 @@ settings_load (GtkFileChooserDefault *impl)
gtk_file_chooser_set_show_hidden (GTK_FILE_CHOOSER (impl), show_hidden);
- impl->expand_folders = expand_folders;
- if (impl->save_expander)
- gtk_expander_set_expanded (GTK_EXPANDER (impl->save_expander), expand_folders);
-
impl->show_size_column = show_size_column;
gtk_tree_view_column_set_visible (impl->list_size_column, show_size_column);
@@ -5859,14 +5813,6 @@ save_dialog_geometry (GtkFileChooserDefault *impl)
GtkWindow *toplevel;
int x, y, width, height;
- /* We don't save the geometry in non-expanded "save" mode, so that the "little
- * dialog" won't make future Open dialogs too small.
- */
- if (!(impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
- || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
- || impl->expand_folders))
- return;
-
toplevel = get_toplevel (GTK_WIDGET (impl));
if (!(toplevel && GTK_IS_FILE_CHOOSER_DIALOG (toplevel)))
@@ -5901,7 +5847,6 @@ settings_save (GtkFileChooserDefault *impl)
/* All the other state */
g_settings_set_enum (impl->settings, SETTINGS_KEY_LOCATION_MODE, impl->location_mode);
- g_settings_set_boolean (impl->settings, SETTINGS_KEY_EXPAND_FOLDERS, impl->expand_folders);
g_settings_set_boolean (impl->settings, SETTINGS_KEY_SHOW_HIDDEN,
gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl)));
g_settings_set_boolean (impl->settings, SETTINGS_KEY_SHOW_SIZE_COLUMN, impl->show_size_column);
@@ -5967,17 +5912,10 @@ gtk_file_chooser_default_map (GtkWidget *widget)
if (impl->operation_mode == OPERATION_MODE_BROWSE)
{
- GFile *folder;
-
switch (impl->reload_state)
{
case RELOAD_EMPTY:
- /* The user didn't explicitly give us a folder to display, so we'll
- * use the saved one from the last invocation of the file chooser
- */
- folder = get_file_for_last_folder_opened (impl);
- gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (impl), folder, NULL);
- g_object_unref (folder);
+ recent_shortcut_handler (impl);
break;
case RELOAD_HAS_FOLDER:
@@ -6008,6 +5946,9 @@ gtk_file_chooser_default_unmap (GtkWidget *widget)
settings_save (impl);
+ cancel_all_operations (impl);
+ impl->reload_state = RELOAD_EMPTY;
+
GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->unmap (widget);
}
@@ -6822,7 +6763,6 @@ update_chooser_entry (GtkFileChooserDefault *impl)
/* no need to update the file chooser's entry if there's no entry */
if (impl->operation_mode == OPERATION_MODE_SEARCH ||
- impl->operation_mode == OPERATION_MODE_RECENT ||
!impl->location_entry)
return;
@@ -6841,7 +6781,10 @@ update_chooser_entry (GtkFileChooserDefault *impl)
if (closure.num_selected == 0)
{
- goto maybe_clear_entry;
+ if (impl->operation_mode == OPERATION_MODE_RECENT)
+ _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), NULL);
+ else
+ goto maybe_clear_entry;
}
else if (closure.num_selected == 1)
{
@@ -6882,6 +6825,20 @@ update_chooser_entry (GtkFileChooserDefault *impl)
return;
}
+ else if (impl->operation_mode == OPERATION_MODE_RECENT
+ && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ {
+ GFile *folder;
+
+ /* Set the base folder on the name entry, so it will do completion relative to the correct recent-folder */
+
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->recent_model), &closure.first_selected_iter,
+ MODEL_COL_FILE, &folder,
+ -1);
+ _gtk_file_chooser_entry_set_base_folder (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), folder);
+ g_object_unref (folder);
+ return;
+ }
}
else
{
@@ -7505,15 +7462,23 @@ gtk_file_chooser_default_get_files (GtkFileChooser *chooser)
GtkWidget *current_focus;
gboolean file_list_seen;
+ info.impl = impl;
+ info.result = NULL;
+ info.file_from_entry = NULL;
+
if (impl->operation_mode == OPERATION_MODE_SEARCH)
return search_get_selected_files (impl);
if (impl->operation_mode == OPERATION_MODE_RECENT)
- return recent_get_selected_files (impl);
-
- info.impl = impl;
- info.result = NULL;
- info.file_from_entry = NULL;
+ {
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ {
+ file_list_seen = TRUE;
+ goto file_entry;
+ }
+ else
+ return recent_get_selected_files (impl);
+ }
toplevel = get_toplevel (GTK_WIDGET (impl));
if (toplevel)
@@ -7975,51 +7940,39 @@ gtk_file_chooser_default_get_default_size (GtkFileChooserEmbed *chooser_embed,
{
GtkFileChooserDefault *impl;
GtkRequisition req;
+ int x, y, width, height;
impl = GTK_FILE_CHOOSER_DEFAULT (chooser_embed);
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
- || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
- || impl->expand_folders)
+ settings_ensure (impl);
+
+ g_settings_get (impl->settings, SETTINGS_KEY_WINDOW_POSITION, "(ii)", &x, &y);
+ g_settings_get (impl->settings, SETTINGS_KEY_WINDOW_SIZE, "(ii)", &width, &height);
+
+ if (x >= 0 && y >= 0 && width > 0 && height > 0)
{
- int x, y, width, height;
-
- settings_ensure (impl);
-
- g_settings_get (impl->settings, SETTINGS_KEY_WINDOW_POSITION, "(ii)", &x, &y);
- g_settings_get (impl->settings, SETTINGS_KEY_WINDOW_SIZE, "(ii)", &width, &height);
-
- if (x >= 0 && y >= 0 && width > 0 && height > 0)
- {
- *default_width = width;
- *default_height = height;
- return;
- }
-
- find_good_size_from_style (GTK_WIDGET (chooser_embed), default_width, default_height);
-
- if (impl->preview_widget_active &&
- impl->preview_widget &&
- gtk_widget_get_visible (impl->preview_widget))
- {
- gtk_widget_get_preferred_size (impl->preview_box,
- &req, NULL);
- *default_width += PREVIEW_HBOX_SPACING + req.width;
- }
-
- if (impl->extra_widget &&
- gtk_widget_get_visible (impl->extra_widget))
- {
- gtk_widget_get_preferred_size (impl->extra_align, &req, NULL);
- *default_height += gtk_box_get_spacing (GTK_BOX (chooser_embed)) + req.height;
- }
+ *default_width = width;
+ *default_height = height;
+ return;
}
- else
+
+ find_good_size_from_style (GTK_WIDGET (chooser_embed), default_width, default_height);
+
+ if (impl->preview_widget_active &&
+ impl->preview_widget &&
+ gtk_widget_get_visible (impl->preview_widget))
{
- gtk_widget_get_preferred_size (GTK_WIDGET (impl),
- &req, NULL);
- *default_width = req.width;
- *default_height = req.height;
+ gtk_widget_get_preferred_size (impl->preview_box,
+ &req, NULL);
+ *default_width += PREVIEW_HBOX_SPACING + req.width;
+ }
+
+ if (impl->extra_widget &&
+ gtk_widget_get_visible (impl->extra_widget))
+ {
+ gtk_widget_get_preferred_size (impl->extra_align,
+ &req, NULL);
+ *default_height += gtk_box_get_spacing (GTK_BOX (chooser_embed)) + req.height;
}
}
@@ -8514,7 +8467,6 @@ location_popup_on_paste_handler (GtkFileChooserDefault *impl)
impl);
}
-
/* Implementation for GtkFileChooserEmbed::should_respond() */
static gboolean
gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
@@ -8565,7 +8517,12 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
return search_should_respond (impl);
if (impl->operation_mode == OPERATION_MODE_RECENT)
- return recent_should_respond (impl);
+ {
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ goto save_entry;
+ else
+ return recent_should_respond (impl);
+ }
selection_check (impl, &num_selected, &all_files, &all_folders);
@@ -8633,13 +8590,35 @@ gtk_file_chooser_default_should_respond (GtkFileChooserEmbed *chooser_embed)
check_save_entry (impl, &file, &is_well_formed, &is_empty, &is_file_part_empty, &is_folder);
if (!is_well_formed)
- return FALSE;
+ {
+ if (!is_empty
+ && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ && impl->operation_mode == OPERATION_MODE_RECENT)
+ {
+ path_bar_set_mode (impl, PATH_BAR_ERROR_NO_FOLDER);
+#if 0
+ /* We'll #ifdef this out, as the fucking treeview selects its first row,
+ * thus changing our assumption that no selection is present - setting
+ * a selection causes the error message from path_bar_set_mode() to go away,
+ * but we want the user to see that message!
+ */
+ gtk_widget_grab_focus (impl->browse_files_tree_view);
+#endif
+ }
+ /* FIXME: else show an "invalid filename" error as the pathbar mode? */
+
+ return FALSE;
+ }
if (is_empty)
{
if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
|| impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- return FALSE;
+ {
+ path_bar_set_mode (impl, PATH_BAR_ERROR_NO_FILENAME);
+ gtk_widget_grab_focus (impl->location_entry);
+ return FALSE;
+ }
goto file_list;
}
@@ -8946,12 +8925,8 @@ search_switch_to_browse_mode (GtkFileChooserDefault *impl)
impl->search_hbox = NULL;
impl->search_entry = NULL;
- gtk_widget_show (impl->browse_path_bar);
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || !impl->create_folders)
- gtk_widget_hide (impl->browse_new_folder_button);
- else
- gtk_widget_show (impl->browse_new_folder_button);
-
+ impl->operation_mode = OPERATION_MODE_BROWSE;
+ path_bar_update (impl);
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
@@ -8962,8 +8937,6 @@ search_switch_to_browse_mode (GtkFileChooserDefault *impl)
gtk_widget_show (impl->location_entry_box);
}
- impl->operation_mode = OPERATION_MODE_BROWSE;
-
file_list_set_sort_column_ids (impl);
}
@@ -9098,29 +9071,11 @@ focus_search_entry_in_idle (GtkFileChooserDefault *impl)
static void
search_setup_widgets (GtkFileChooserDefault *impl)
{
- GtkWidget *label;
- GtkWidget *image;
- gchar *tmp;
-
impl->search_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
- /* Image */
-
- image = gtk_image_new_from_stock (GTK_STOCK_FIND, GTK_ICON_SIZE_BUTTON);
- gtk_box_pack_start (GTK_BOX (impl->search_hbox), image, FALSE, FALSE, 5);
-
- /* Label */
-
- label = gtk_label_new (NULL);
- tmp = g_strdup_printf ("%s", _("Search:"));
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), tmp);
- gtk_box_pack_start (GTK_BOX (impl->search_hbox), label, FALSE, FALSE, 0);
- g_free (tmp);
-
- /* Entry */
+ path_bar_update (impl);
impl->search_entry = gtk_entry_new ();
- gtk_label_set_mnemonic_widget (GTK_LABEL (label), impl->search_entry);
g_signal_connect (impl->search_entry, "activate",
G_CALLBACK (search_entry_activate_cb),
impl);
@@ -9145,9 +9100,6 @@ search_setup_widgets (GtkFileChooserDefault *impl)
}
}
- gtk_widget_hide (impl->browse_path_bar);
- gtk_widget_hide (impl->browse_new_folder_button);
-
/* Box for search widgets */
gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->search_hbox, TRUE, TRUE, 0);
gtk_widget_show_all (impl->search_hbox);
@@ -9189,13 +9141,28 @@ stop_operation (GtkFileChooserDefault *impl, OperationMode mode)
case OPERATION_MODE_RECENT:
recent_stop_loading (impl);
recent_clear_model (impl, TRUE);
-
- gtk_widget_destroy (impl->recent_hbox);
- impl->recent_hbox = NULL;
break;
}
}
+/* Sometimes we need to frob the selection in the shortcuts list manually */
+static void
+shortcuts_select_item_without_activating (GtkFileChooserDefault *impl, int pos)
+{
+ GtkTreeSelection *selection;
+ GtkTreePath *path;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view));
+
+ g_signal_handlers_block_by_func (selection, G_CALLBACK (shortcuts_selection_changed_cb), impl);
+
+ path = gtk_tree_path_new_from_indices (pos, -1);
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_path_free (path);
+
+ g_signal_handlers_unblock_by_func (selection, G_CALLBACK (shortcuts_selection_changed_cb), impl);
+}
+
/* Main entry point to the searching functions; this gets called when the user
* activates the Search shortcut.
*/
@@ -9213,6 +9180,8 @@ search_activate (GtkFileChooserDefault *impl)
previous_mode = impl->operation_mode;
impl->operation_mode = OPERATION_MODE_SEARCH;
+ shortcuts_select_item_without_activating (impl, shortcuts_get_index (impl, SHORTCUTS_SEARCH));
+
stop_operation (impl, previous_mode);
g_assert (impl->search_hbox == NULL);
@@ -9266,14 +9235,8 @@ recent_switch_to_browse_mode (GtkFileChooserDefault *impl)
recent_stop_loading (impl);
recent_clear_model (impl, TRUE);
- gtk_widget_destroy (impl->recent_hbox);
- impl->recent_hbox = NULL;
-
- gtk_widget_show (impl->browse_path_bar);
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN || !impl->create_folders)
- gtk_widget_hide (impl->browse_new_folder_button);
- else
- gtk_widget_show (impl->browse_new_folder_button);
+ impl->operation_mode = OPERATION_MODE_BROWSE;
+ path_bar_update (impl);
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
@@ -9286,8 +9249,6 @@ recent_switch_to_browse_mode (GtkFileChooserDefault *impl)
gtk_tree_view_column_set_visible (impl->list_size_column, impl->show_size_column);
- impl->operation_mode = OPERATION_MODE_BROWSE;
-
file_list_set_sort_column_ids (impl);
}
@@ -9321,8 +9282,6 @@ typedef struct
{
GtkFileChooserDefault *impl;
GList *items;
- gint n_items;
- gint n_loaded_items;
guint needs_sorting : 1;
} RecentLoadData;
@@ -9339,12 +9298,6 @@ recent_idle_cleanup (gpointer data)
impl->load_recent_id = 0;
- if (load_data->items)
- {
- g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
- g_list_free (load_data->items);
- }
-
g_free (load_data);
}
@@ -9374,13 +9327,61 @@ get_recent_files_limit (GtkWidget *widget)
return limit;
}
+/* Populates the file system model with the GtkRecentInfo* items in the provided list; frees the items */
+static void
+populate_model_with_recent_items (GtkFileChooserDefault *impl, GList *items)
+{
+ gint limit;
+ GList *l;
+ int n;
+
+ limit = get_recent_files_limit (GTK_WIDGET (impl));
+
+ n = 0;
+
+ for (l = items; l; l = l->next)
+ {
+ GtkRecentInfo *info = l->data;
+ GFile *file;
+
+ file = g_file_new_for_uri (gtk_recent_info_get_uri (info));
+ _gtk_file_system_model_add_and_query_file (impl->recent_model,
+ file,
+ MODEL_ATTRIBUTES);
+ g_object_unref (file);
+
+ n++;
+ if (limit != -1 && n >= limit)
+ break;
+ }
+}
+
+static void
+populate_model_with_folders (GtkFileChooserDefault *impl, GList *items)
+{
+ GList *folders;
+ GList *l;
+
+ folders = _gtk_file_chooser_extract_recent_folders (items);
+
+ for (l = folders; l; l = l->next)
+ {
+ GFile *folder = l->data;
+
+ _gtk_file_system_model_add_and_query_file (impl->recent_model,
+ folder,
+ MODEL_ATTRIBUTES);
+ }
+
+ g_list_foreach (folders, (GFunc) g_object_unref, NULL);
+ g_list_free (folders);
+}
+
static gboolean
recent_idle_load (gpointer data)
{
RecentLoadData *load_data = data;
GtkFileChooserDefault *impl = load_data->impl;
- GList *walk;
- GFile *file;
if (!impl->recent_manager)
return FALSE;
@@ -9397,55 +9398,21 @@ recent_idle_load (gpointer data)
return TRUE;
}
- /* second iteration: preliminary MRU sorting and clamping */
+ /* second iteration: MRU sorting and clamping, and populating the model */
if (load_data->needs_sorting)
{
- gint limit;
-
load_data->items = g_list_sort (load_data->items, recent_sort_mru);
- load_data->n_items = g_list_length (load_data->items);
- limit = get_recent_files_limit (GTK_WIDGET (impl));
-
- if (limit != -1 && (load_data->n_items > limit))
- {
- GList *clamp, *l;
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
+ populate_model_with_recent_items (impl, load_data->items);
+ else
+ populate_model_with_folders (impl, load_data->items);
- clamp = g_list_nth (load_data->items, limit - 1);
- if (G_LIKELY (clamp))
- {
- l = clamp->next;
- clamp->next = NULL;
-
- g_list_foreach (l, (GFunc) gtk_recent_info_unref, NULL);
- g_list_free (l);
-
- load_data->n_items = limit;
- }
- }
-
- load_data->n_loaded_items = 0;
- load_data->needs_sorting = FALSE;
-
- return TRUE;
+ g_list_foreach (load_data->items, (GFunc) gtk_recent_info_unref, NULL);
+ g_list_free (load_data->items);
+ load_data->items = NULL;
}
- /* finished loading items */
- for (walk = load_data->items; walk; walk = walk->next)
- {
- GtkRecentInfo *info = walk->data;
- file = g_file_new_for_uri (gtk_recent_info_get_uri (info));
-
- _gtk_file_system_model_add_and_query_file (impl->recent_model,
- file,
- MODEL_ATTRIBUTES);
- gtk_recent_info_unref (walk->data);
- g_object_unref (file);
- }
-
- g_list_free (load_data->items);
- load_data->items = NULL;
-
return FALSE;
}
@@ -9464,8 +9431,6 @@ recent_start_loading (GtkFileChooserDefault *impl)
load_data = g_new (RecentLoadData, 1);
load_data->impl = impl;
load_data->items = NULL;
- load_data->n_items = 0;
- load_data->n_loaded_items = 0;
load_data->needs_sorting = TRUE;
/* begin lazy loading the recent files into the model */
@@ -9524,30 +9489,7 @@ recent_should_respond (GtkFileChooserDefault *impl)
static void
recent_hide_entry (GtkFileChooserDefault *impl)
{
- GtkWidget *label;
- GtkWidget *image;
- gchar *tmp;
-
- impl->recent_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
-
- /* Image */
- image = gtk_image_new_from_icon_name ("document-open-recent", GTK_ICON_SIZE_BUTTON);
- gtk_box_pack_start (GTK_BOX (impl->recent_hbox), image, FALSE, FALSE, 5);
-
- /* Label */
- label = gtk_label_new (NULL);
- tmp = g_strdup_printf ("%s", _("Recently Used"));
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), tmp);
- gtk_box_pack_start (GTK_BOX (impl->recent_hbox), label, FALSE, FALSE, 0);
- g_free (tmp);
-
- gtk_widget_hide (impl->browse_path_bar);
- gtk_widget_hide (impl->browse_new_folder_button);
-
- /* Box for recent widgets */
- gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->recent_hbox, TRUE, TRUE, 0);
- gtk_size_group_add_widget (impl->browse_path_bar_size_group, impl->recent_hbox);
- gtk_widget_show_all (impl->recent_hbox);
+ path_bar_update (impl);
/* Hide the location widgets temporarily */
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN ||
@@ -9572,6 +9514,8 @@ recent_activate (GtkFileChooserDefault *impl)
previous_mode = impl->operation_mode;
impl->operation_mode = OPERATION_MODE_RECENT;
+ shortcuts_select_item_without_activating (impl, shortcuts_get_index (impl, SHORTCUTS_RECENT));
+
stop_operation (impl, previous_mode);
recent_hide_entry (impl);
@@ -10045,6 +9989,8 @@ list_selection_changed (GtkTreeSelection *selection,
if (impl->location_entry)
update_chooser_entry (impl);
+ path_bar_update (impl);
+
check_preview_change (impl);
bookmarks_check_add_sensitivity (impl);
@@ -10331,8 +10277,7 @@ search_shortcut_handler (GtkFileChooserDefault *impl)
static void
recent_shortcut_handler (GtkFileChooserDefault *impl)
{
- if (impl->has_recent)
- switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_RECENT));
+ switch_to_shortcut (impl, shortcuts_get_index (impl, SHORTCUTS_RECENT));
}
static void
diff --git a/gtk/gtkfilechooserdialog.c b/gtk/gtkfilechooserdialog.c
index ea19777c7b..08dfc62d3e 100644
--- a/gtk/gtkfilechooserdialog.c
+++ b/gtk/gtkfilechooserdialog.c
@@ -93,10 +93,7 @@
* gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
*
* if (user_edited_a_new_document)
- * {
- * gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), default_folder_for_saving);
- * gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "Untitled document");
- * }
+ * gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), "Untitled document");
* else
* gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), filename_for_existing_document);
*
@@ -113,6 +110,59 @@
*
*
*
+ *
+ * Setting up a file chooser dialog
+ * There are various cases in which you may need to use a #GtkFileChooserDialog:
+ *
+ *
+ *
+ * To select a file for opening, as for a
+ * File/Open command. Use
+ * #GTK_FILE_CHOOSER_ACTION_OPEN.
+ *
+ *
+ *
+ *
+ *
+ * To save a file for the first time, as for a
+ * File/Save command. Use
+ * #GTK_FILE_CHOOSER_ACTION_SAVE, and suggest a name such as
+ * "Untitled" with gtk_file_chooser_set_current_name().
+ *
+ *
+ *
+ *
+ *
+ * To save a file under a different name, as for a
+ * File/Save As command. Use
+ * #GTK_FILE_CHOOSER_ACTION_SAVE, and set the existing filename
+ * with gtk_file_chooser_set_filename().
+ *
+ *
+ *
+ *
+ *
+ * To choose a folder instead of a file. Use
+ * #GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER.
+ *
+ *
+ *
+ *
+ *
+ * Old versions of the file chooser's documentation suggested
+ * using gtk_file_chooser_set_current_folder() in various
+ * situations, with the intention of letting the application
+ * suggest a reasonable default folder. This is no longer
+ * considered to be a good policy, as now the file chooser is
+ * able to make good suggestions on its own. In general, you
+ * should only cause the file chooser to show a specific folder
+ * when it is appropriate to use gtk_file_chooser_set_filename()
+ * - i.e. when you are doing a File/Save
+ * As command and you already
+ * have a file saved somewhere.
+ *
+ *
+ *
*
* Response Codes
* #GtkFileChooserDialog inherits from #GtkDialog, so buttons that
diff --git a/gtk/gtkfilechooserentry.c b/gtk/gtkfilechooserentry.c
index 55303ed0fb..e102652132 100644
--- a/gtk/gtkfilechooserentry.c
+++ b/gtk/gtkfilechooserentry.c
@@ -1563,7 +1563,6 @@ refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry,
error = NULL;
if (!chooser_entry->file_system ||
- !chooser_entry->base_folder ||
!_gtk_file_system_parse (chooser_entry->file_system,
chooser_entry->base_folder, text,
&folder_file, &file_part, &error))
@@ -1831,7 +1830,6 @@ _gtk_file_chooser_entry_set_base_folder (GtkFileChooserEntry *chooser_entry,
g_object_ref (chooser_entry->base_folder);
clear_completions (chooser_entry);
- _gtk_file_chooser_entry_select_filename (chooser_entry);
}
/**
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
index 117900fa32..2e2109f7af 100644
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@ -162,13 +162,12 @@ struct _GtkFileChooserDefault
/* Save mode widgets */
GtkWidget *save_widgets;
+ GtkWidget *save_widgets_table;
GtkWidget *save_folder_label;
- GtkWidget *save_folder_combo;
- GtkWidget *save_expander;
/* The file browsing widgets */
- GtkWidget *browse_widgets;
+ GtkWidget *browse_widgets_box;
GtkWidget *browse_shortcuts_tree_view;
GtkWidget *browse_shortcuts_add_button;
GtkWidget *browse_shortcuts_remove_button;
@@ -184,6 +183,11 @@ struct _GtkFileChooserDefault
GtkWidget *browse_path_bar_hbox;
GtkSizeGroup *browse_path_bar_size_group;
GtkWidget *browse_path_bar;
+ GtkWidget *browse_special_mode_icon;
+ GtkWidget *browse_special_mode_label;
+ GtkWidget *browse_select_a_folder_info_bar;
+ GtkWidget *browse_select_a_folder_label;
+ GtkWidget *browse_select_a_folder_icon;
GtkFileSystemModel *browse_files_model;
char *browse_files_last_selected_name;
@@ -196,7 +200,6 @@ struct _GtkFileChooserDefault
GtkFileSystemModel *search_model;
/* OPERATION_MODE_RECENT */
- GtkWidget *recent_hbox;
GtkRecentManager *recent_manager;
GtkFileSystemModel *recent_model;
guint load_recent_id;
@@ -222,11 +225,6 @@ struct _GtkFileChooserDefault
*/
GtkTreeModel *shortcuts_pane_filter_model;
- /* Filter for the "Save in folder" combo. We filter out the Search row and
- * its separator.
- */
- GtkTreeModel *shortcuts_combo_filter_model;
-
/* Handles */
GSList *loading_shortcuts;
GSList *reload_icon_cancellables;
@@ -298,11 +296,9 @@ struct _GtkFileChooserDefault
guint list_sort_ascending : 1;
guint changing_folder : 1;
guint shortcuts_current_folder_active : 1;
- guint expand_folders : 1;
guint has_home : 1;
guint has_desktop : 1;
guint has_search : 1;
- guint has_recent : 1;
guint show_size_column : 1;
guint create_folders : 1;
diff --git a/gtk/gtkfilechooserutils.c b/gtk/gtkfilechooserutils.c
index e0fefcfe03..9458abdaba 100644
--- a/gtk/gtkfilechooserutils.c
+++ b/gtk/gtkfilechooserutils.c
@@ -360,3 +360,59 @@ delegate_confirm_overwrite (GtkFileChooser *chooser,
g_signal_emit_by_name (data, "confirm-overwrite", &conf);
return conf;
}
+
+static GFile *
+get_parent_for_uri (const char *uri)
+{
+ GFile *file;
+ GFile *parent;
+
+ file = g_file_new_for_uri (uri);
+ parent = g_file_get_parent (file);
+
+ g_object_unref (file);
+ return parent;
+
+}
+
+/* Extracts the parent folders out of the supplied list of GtkRecentInfo* items, and returns
+ * a list of GFile* for those unique parents.
+ */
+GList *
+_gtk_file_chooser_extract_recent_folders (GList *infos)
+{
+ GList *l;
+ GList *result;
+ GHashTable *folders;
+
+ result = NULL;
+
+ folders = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
+
+ for (l = infos; l; l = l->next)
+ {
+ GtkRecentInfo *info = l->data;
+ const char *uri;
+ GFile *parent;
+
+ uri = gtk_recent_info_get_uri (info);
+ parent = get_parent_for_uri (uri);
+
+ if (parent)
+ {
+ if (!g_hash_table_lookup (folders, parent))
+ {
+ g_hash_table_insert (folders, parent, (gpointer) 1);
+ result = g_list_prepend (result, g_object_ref (parent));
+ }
+
+ g_object_unref (parent);
+ }
+ }
+
+ result = g_list_reverse (result);
+
+ g_hash_table_destroy (folders);
+
+ return result;
+}
diff --git a/gtk/gtkfilechooserutils.h b/gtk/gtkfilechooserutils.h
index 8b80ab66f9..ba58d71bdc 100644
--- a/gtk/gtkfilechooserutils.h
+++ b/gtk/gtkfilechooserutils.h
@@ -52,6 +52,8 @@ void _gtk_file_chooser_set_delegate (GtkFileChooser *receiver,
GQuark _gtk_file_chooser_delegate_get_quark (void) G_GNUC_CONST;
+GList *_gtk_file_chooser_extract_recent_folders (GList *infos);
+
G_END_DECLS
#endif /* __GTK_FILE_CHOOSER_UTILS_H__ */
diff --git a/gtk/gtkfilesystem.c b/gtk/gtkfilesystem.c
index 30ff484444..f3d8e823a0 100644
--- a/gtk/gtkfilesystem.c
+++ b/gtk/gtkfilesystem.c
@@ -708,9 +708,22 @@ _gtk_file_system_parse (GtkFileSystem *file_system,
if (str[0] == '~' || g_path_is_absolute (str) || is_uri)
file = g_file_parse_name (str);
else
- file = g_file_resolve_relative_path (base_file, str);
+ {
+ if (base_file)
+ file = g_file_resolve_relative_path (base_file, str);
+ else
+ {
+ *folder = NULL;
+ *file_part = NULL;
+ g_set_error (error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_BAD_FILENAME,
+ _("Invalid path"));
+ return FALSE;
+ }
+ }
- if (g_file_equal (base_file, file))
+ if (base_file && g_file_equal (base_file, file))
{
/* this is when user types '.', could be the
* beginning of a hidden file, ./ or ../
diff --git a/gtk/org.gtk.Settings.FileChooser.gschema.xml b/gtk/org.gtk.Settings.FileChooser.gschema.xml
index 7bef20d17d..075a1ab638 100644
--- a/gtk/org.gtk.Settings.FileChooser.gschema.xml
+++ b/gtk/org.gtk.Settings.FileChooser.gschema.xml
@@ -44,9 +44,6 @@
false
-
- false
-
true