X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkfilechooserbutton.c;h=9fa5038bba5b77ef87ea72bf7846731e5569339a;hb=45ad8a06ad511ad95a74172172b9fe459bc666ad;hp=1bea89bca77683977774ba5eb82fe7a79419a382;hpb=32aa7f0582febb614c41e4130ad34ac44ef6efd2;p=~andy%2Fgtk diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c index 1bea89bca..9fa5038bb 100644 --- a/gtk/gtkfilechooserbutton.c +++ b/gtk/gtkfilechooserbutton.c @@ -154,6 +154,7 @@ typedef enum ROW_TYPE_CURRENT_FOLDER, ROW_TYPE_OTHER_SEPARATOR, ROW_TYPE_OTHER, + ROW_TYPE_EMPTY_SELECTION, ROW_TYPE_INVALID = -1 } @@ -288,8 +289,9 @@ static gint model_get_type_position (GtkFileChooserButton *button, RowType row_type); static void model_free_row_data (GtkFileChooserButton *button, GtkTreeIter *iter); -static inline void model_add_special (GtkFileChooserButton *button); -static inline void model_add_other (GtkFileChooserButton *button); +static void model_add_special (GtkFileChooserButton *button); +static void model_add_other (GtkFileChooserButton *button); +static void model_add_empty_selection (GtkFileChooserButton *button); static void model_add_volumes (GtkFileChooserButton *button, GSList *volumes); static void model_add_bookmarks (GtkFileChooserButton *button, @@ -324,6 +326,9 @@ static void fs_bookmarks_changed_cb (GtkFileSystem *fs, static void combo_box_changed_cb (GtkComboBox *combo_box, gpointer user_data); +static void combo_box_notify_popup_shown_cb (GObject *object, + GParamSpec *pspec, + gpointer user_data); static void button_clicked_cb (GtkButton *real_button, gpointer user_data); @@ -521,17 +526,20 @@ gtk_file_chooser_button_init (GtkFileChooserButton *button) /* Keep in sync with columns enum, line 88 */ priv->model = GTK_TREE_MODEL (gtk_list_store_new (NUM_COLUMNS, - GDK_TYPE_PIXBUF, /* Icon */ - G_TYPE_STRING, /* Display Name */ - G_TYPE_CHAR, /* Row Type */ - G_TYPE_POINTER /* Volume || Path */, - G_TYPE_BOOLEAN /* Is Folder? */, - G_TYPE_POINTER /* cancellable */)); + GDK_TYPE_PIXBUF, /* ICON_COLUMN */ + G_TYPE_STRING, /* DISPLAY_NAME_COLUMN */ + G_TYPE_CHAR, /* TYPE_COLUMN */ + G_TYPE_POINTER /* DATA_COLUMN (Volume || Path) */, + G_TYPE_BOOLEAN /* IS_FOLDER_COLUMN */, + G_TYPE_POINTER /* CANCELLABLE_COLUMN */)); priv->combo_box = gtk_combo_box_new (); - priv->combo_box_changed_id = - g_signal_connect (priv->combo_box, "changed", - G_CALLBACK (combo_box_changed_cb), button); + priv->combo_box_changed_id = g_signal_connect (priv->combo_box, "changed", + G_CALLBACK (combo_box_changed_cb), button); + + g_signal_connect (priv->combo_box, "notify::popup-shown", + G_CALLBACK (combo_box_notify_popup_shown_cb), button); + gtk_box_pack_start (GTK_BOX (button), priv->combo_box, TRUE, TRUE, 0); gtk_widget_set_halign (priv->combo_box, GTK_ALIGN_FILL); @@ -922,6 +930,8 @@ gtk_file_chooser_button_constructor (GType type, model_add_other (button); + model_add_empty_selection (button); + priv->filter_model = gtk_tree_model_filter_new (priv->model, NULL); gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->filter_model), filter_model_visible_func, @@ -946,6 +956,9 @@ gtk_file_chooser_button_constructor (GType type, g_signal_connect (priv->fs, "bookmarks-changed", G_CALLBACK (fs_bookmarks_changed_cb), object); + update_label_and_image (button); + update_combo_box (button); + return object; } @@ -1736,6 +1749,11 @@ model_get_type_position (GtkFileChooserButton *button, if (row_type == ROW_TYPE_OTHER) return retval; + retval++; + + if (row_type == ROW_TYPE_EMPTY_SELECTION) + return retval; + g_assert_not_reached (); return -1; } @@ -1843,7 +1861,7 @@ out: g_object_unref (model_cancellable); } -static inline void +static void model_add_special (GtkFileChooserButton *button) { const gchar *homedir; @@ -2179,7 +2197,7 @@ model_update_current_folder (GtkFileChooserButton *button, } } -static inline void +static void model_add_other (GtkFileChooserButton *button) { GtkListStore *store; @@ -2210,6 +2228,26 @@ model_add_other (GtkFileChooserButton *button) -1); } +static void +model_add_empty_selection (GtkFileChooserButton *button) +{ + GtkListStore *store; + GtkTreeIter iter; + gint pos; + + store = GTK_LIST_STORE (button->priv->model); + pos = model_get_type_position (button, ROW_TYPE_EMPTY_SELECTION); + + gtk_list_store_insert (store, &iter, pos); + gtk_list_store_set (store, &iter, + ICON_COLUMN, NULL, + DISPLAY_NAME_COLUMN, _(FALLBACK_DISPLAY_NAME), + TYPE_COLUMN, ROW_TYPE_EMPTY_SELECTION, + DATA_COLUMN, NULL, + IS_FOLDER_COLUMN, FALSE, + -1); +} + static void model_remove_rows (GtkFileChooserButton *button, gint pos, @@ -2237,7 +2275,7 @@ model_remove_rows (GtkFileChooserButton *button, } /* Filter Model */ -static inline gboolean +static gboolean test_if_file_is_visible (GtkFileSystem *fs, GFile *file, gboolean local_only, @@ -2309,6 +2347,34 @@ filter_model_visible_func (GtkTreeModel *model, } } break; + case ROW_TYPE_EMPTY_SELECTION: + { + gboolean popup_shown; + + g_object_get (priv->combo_box, + "popup-shown", &popup_shown, + NULL); + + if (popup_shown) + retval = FALSE; + else + { + GFile *selected; + + /* When the combo box is not popped up... */ + + selected = get_selected_file (button); + if (selected) + retval = FALSE; /* ... nonempty selection means the ROW_TYPE_EMPTY_SELECTION is *not* visible... */ + else + retval = TRUE; /* ... and empty selection means the ROW_TYPE_EMPTY_SELECTION *is* visible */ + + if (selected) + g_object_unref (selected); + } + + break; + } default: retval = TRUE; break; @@ -2350,7 +2416,22 @@ combo_box_row_separator_func (GtkTreeModel *model, return (type == ROW_TYPE_BOOKMARK_SEPARATOR || type == ROW_TYPE_CURRENT_FOLDER_SEPARATOR || type == ROW_TYPE_OTHER_SEPARATOR); -} +} + +static void +select_combo_box_row_no_notify (GtkFileChooserButton *button, int pos) +{ + GtkFileChooserButtonPrivate *priv = button->priv; + GtkTreeIter iter, filter_iter; + + gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, pos); + gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (priv->filter_model), + &filter_iter, &iter); + + g_signal_handler_block (priv->combo_box, priv->combo_box_changed_id); + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->combo_box), &filter_iter); + g_signal_handler_unblock (priv->combo_box, priv->combo_box_changed_id); +} static void update_combo_box (GtkFileChooserButton *button) @@ -2415,24 +2496,26 @@ update_combo_box (GtkFileChooserButton *button) } while (!row_found && gtk_tree_model_iter_next (priv->filter_model, &iter)); - /* If it hasn't been found already, update & select the current-folder row. */ - if (!row_found && file) + if (!row_found) { - GtkTreeIter filter_iter; gint pos; - - model_update_current_folder (button, file); - gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter_model)); - pos = model_get_type_position (button, ROW_TYPE_CURRENT_FOLDER); - gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, pos); + /* If it hasn't been found already, update & select the current-folder row. */ + if (file) + { + model_update_current_folder (button, file); + pos = model_get_type_position (button, ROW_TYPE_CURRENT_FOLDER); + } + else + { + /* No selection; switch to that row */ - gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (priv->filter_model), - &filter_iter, &iter); + pos = model_get_type_position (button, ROW_TYPE_EMPTY_SELECTION); + } - g_signal_handler_block (priv->combo_box, priv->combo_box_changed_id); - gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->combo_box), &filter_iter); - g_signal_handler_unblock (priv->combo_box, priv->combo_box_changed_id); + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter_model)); + + select_combo_box_row_no_notify (button, pos); } if (file) @@ -2720,21 +2803,17 @@ combo_box_changed_cb (GtkComboBox *combo_box, case ROW_TYPE_SHORTCUT: case ROW_TYPE_BOOKMARK: case ROW_TYPE_CURRENT_FOLDER: - gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->dialog)); if (data) - gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (priv->dialog), - data, NULL); + gtk_file_chooser_button_select_file (GTK_FILE_CHOOSER (button), data, NULL); break; case ROW_TYPE_VOLUME: { GFile *base_file; - gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (priv->dialog)); base_file = _gtk_file_system_volume_get_root (data); if (base_file) { - gtk_file_chooser_set_current_folder_file (GTK_FILE_CHOOSER (priv->dialog), - base_file, NULL); + gtk_file_chooser_button_select_file (GTK_FILE_CHOOSER (button), base_file, NULL); g_object_unref (base_file); } } @@ -2748,6 +2827,50 @@ combo_box_changed_cb (GtkComboBox *combo_box, } } +/* Calback for the "notify::popup-shown" signal on the combo box. + * When the combo is popped up, we don't want the ROW_TYPE_EMPTY_SELECTION to be visible + * at all; otherwise we would be showing a "(None)" item in the combo box's popup. + * + * However, when the combo box is *not* popped up, we want the empty-selection row + * to be visible depending on the selection. + * + * Since all that is done through the filter_model_visible_func(), this means + * that we need to refilter the model when the combo box pops up - hence the + * present signal handler. + */ +static void +combo_box_notify_popup_shown_cb (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + GtkFileChooserButton *button = GTK_FILE_CHOOSER_BUTTON (user_data); + GtkFileChooserButtonPrivate *priv = button->priv; + gboolean popup_shown; + + g_object_get (priv->combo_box, + "popup-shown", &popup_shown, + NULL); + + /* Indicate that the ROW_TYPE_EMPTY_SELECTION will change visibility... */ + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (priv->filter_model)); + + /* If the combo box popup got dismissed, go back to showing the ROW_TYPE_EMPTY_SELECTION if needed */ + if (!popup_shown) + { + GFile *selected = get_selected_file (button); + + if (!selected) + { + int pos; + + pos = model_get_type_position (button, ROW_TYPE_EMPTY_SELECTION); + select_combo_box_row_no_notify (button, pos); + } + else + g_object_unref (selected); + } +} + /* Button */ static void button_clicked_cb (GtkButton *real_button, @@ -2859,9 +2982,6 @@ dialog_response_cb (GtkDialog *dialog, g_signal_emit_by_name (button, "current-folder-changed"); g_signal_emit_by_name (button, "selection-changed"); - - update_label_and_image (button); - update_combo_box (button); } else { @@ -2879,6 +2999,9 @@ dialog_response_cb (GtkDialog *dialog, priv->active = FALSE; } + update_label_and_image (button); + update_combo_box (button); + gtk_widget_set_sensitive (priv->combo_box, TRUE); gtk_widget_hide (priv->dialog);