diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h index 0094beb299..a0a622c111 100644 --- a/gtk/gtkfilechooserprivate.h +++ b/gtk/gtkfilechooserprivate.h @@ -38,6 +38,7 @@ G_BEGIN_DECLS #define SETTINGS_KEY_LOCATION_MODE "location-mode" #define SETTINGS_KEY_SHOW_HIDDEN "show-hidden" #define SETTINGS_KEY_SHOW_SIZE_COLUMN "show-size-column" +#define SETTINGS_KEY_SHOW_TYPE_COLUMN "show-type-column" #define SETTINGS_KEY_SORT_COLUMN "sort-column" #define SETTINGS_KEY_SORT_ORDER "sort-order" #define SETTINGS_KEY_WINDOW_POSITION "window-position" @@ -47,6 +48,7 @@ G_BEGIN_DECLS #define SETTINGS_KEY_SORT_DIRECTORIES_FIRST "sort-directories-first" #define SETTINGS_KEY_CLOCK_FORMAT "clock-format" #define SETTINGS_KEY_DATE_FORMAT "date-format" +#define SETTINGS_KEY_TYPE_FORMAT "type-format" #define GTK_FILE_CHOOSER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GTK_TYPE_FILE_CHOOSER, GtkFileChooserIface)) diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c index ce708670c9..9eca5713e3 100644 --- a/gtk/gtkfilechooserwidget.c +++ b/gtk/gtkfilechooserwidget.c @@ -207,6 +207,12 @@ typedef enum { DATE_FORMAT_WITH_TIME } DateFormat; +typedef enum { + TYPE_FORMAT_MIME, + TYPE_FORMAT_DESCRIPTION, + TYPE_FORMAT_CATEGORY +} TypeFormat; + struct _GtkFileChooserWidgetPrivate { GtkFileChooserAction action; @@ -229,6 +235,7 @@ struct _GtkFileChooserWidgetPrivate { GtkWidget *add_shortcut_item; GtkWidget *hidden_files_item; GtkWidget *size_column_item; + GtkWidget *type_column_item; GtkWidget *copy_file_location_item; GtkWidget *visit_file_item; GtkWidget *open_folder_item; @@ -331,6 +338,8 @@ struct _GtkFileChooserWidgetPrivate { GtkCellRenderer *list_time_renderer; GtkTreeViewColumn *list_size_column; GtkCellRenderer *list_size_renderer; + GtkTreeViewColumn *list_type_column; + GtkCellRenderer *list_type_renderer; GtkTreeViewColumn *list_location_column; GtkCellRenderer *list_location_renderer; @@ -347,6 +356,8 @@ struct _GtkFileChooserWidgetPrivate { gint sort_column; GtkSortType sort_order; + TypeFormat type_format; + /* Flags */ guint local_only : 1; @@ -361,6 +372,7 @@ struct _GtkFileChooserWidgetPrivate { guint list_sort_ascending : 1; guint shortcuts_current_folder_active : 1; guint show_size_column : 1; + guint show_type_column : 1; guint create_folders : 1; guint auto_selecting_first_row : 1; }; @@ -395,9 +407,10 @@ static guint signals[LAST_SIGNAL] = { 0 }; "access::can-rename,access::can-delete,access::can-trash," \ "standard::target-uri" enum { - /* the first 3 must be these due to settings caching sort column */ + /* the first 4 must be these due to settings caching sort column */ MODEL_COL_NAME, MODEL_COL_SIZE, + MODEL_COL_TYPE, MODEL_COL_TIME, MODEL_COL_FILE, MODEL_COL_NAME_COLLATED, @@ -417,6 +430,7 @@ enum { MODEL_COL_NUM_COLUMNS, \ G_TYPE_STRING, /* MODEL_COL_NAME */ \ G_TYPE_INT64, /* MODEL_COL_SIZE */ \ + G_TYPE_STRING, /* MODEL_COL_TYPE */ \ G_TYPE_LONG, /* MODEL_COL_TIME */ \ G_TYPE_FILE, /* MODEL_COL_FILE */ \ G_TYPE_STRING, /* MODEL_COL_NAME_COLLATED */ \ @@ -1830,6 +1844,22 @@ change_show_size_state (GSimpleAction *action, priv->show_size_column); } +/* Callback used when the "Show Type Column" menu item is toggled */ +static void +change_show_type_state (GSimpleAction *action, + GVariant *state, + gpointer data) +{ + GtkFileChooserWidget *impl = data; + GtkFileChooserWidgetPrivate *priv = impl->priv; + + g_simple_action_set_state (action, state); + priv->show_type_column = g_variant_get_boolean (state); + + gtk_tree_view_column_set_visible (priv->list_type_column, + priv->show_type_column); +} + static void change_sort_directories_first_state (GSimpleAction *action, GVariant *state, @@ -2201,6 +2231,7 @@ static GActionEntry entries[] = { { "trash", trash_file_cb, NULL, NULL, NULL }, { "toggle-show-hidden", NULL, NULL, "false", change_show_hidden_state }, { "toggle-show-size", NULL, NULL, "false", change_show_size_state }, + { "toggle-show-type", NULL, NULL, "false", change_show_type_state }, { "toggle-show-time", NULL, NULL, "false", change_show_time_state }, { "toggle-sort-dirs-first", NULL, NULL, "false", change_sort_directories_first_state } }; @@ -2281,6 +2312,7 @@ file_list_build_popover (GtkFileChooserWidget *impl) priv->hidden_files_item = add_button (box, _("Show _Hidden Files"), "item.toggle-show-hidden"); priv->size_column_item = add_button (box, _("Show _Size Column"), "item.toggle-show-size"); + priv->type_column_item = add_button (box, _("Show T_ype Column"), "item.toggle-show-type"); priv->show_time_item = add_button (box, _("Show _Time"), "item.toggle-show-time"); priv->sort_directories_item = add_button (box, _("Sort _Folders before Files"), "item.toggle-sort-dirs-first"); } @@ -2318,6 +2350,9 @@ file_list_update_popover (GtkFileChooserWidget *impl) action = g_action_map_lookup_action (G_ACTION_MAP (actions), "toggle-show-size"); g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (priv->show_size_column)); + action = g_action_map_lookup_action (G_ACTION_MAP (actions), "toggle-show-type"); + g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (priv->show_type_column)); + action = g_action_map_lookup_action (G_ACTION_MAP (actions), "toggle-show-time"); g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (priv->show_time)); @@ -2433,6 +2468,7 @@ file_list_set_sort_column_ids (GtkFileChooserWidget *impl) gtk_tree_view_column_set_sort_column_id (priv->list_name_column, MODEL_COL_NAME); gtk_tree_view_column_set_sort_column_id (priv->list_time_column, MODEL_COL_TIME); gtk_tree_view_column_set_sort_column_id (priv->list_size_column, MODEL_COL_SIZE); + gtk_tree_view_column_set_sort_column_id (priv->list_type_column, MODEL_COL_TYPE); gtk_tree_view_column_set_sort_column_id (priv->list_location_column, MODEL_COL_LOCATION_TEXT); } @@ -3812,8 +3848,10 @@ settings_load (GtkFileChooserWidget *impl) GtkFileChooserWidgetPrivate *priv = impl->priv; gboolean show_hidden; gboolean show_size_column; + gboolean show_type_column; gboolean sort_directories_first; DateFormat date_format; + TypeFormat type_format; gint sort_column; GtkSortType sort_order; StartupMode startup_mode; @@ -3824,23 +3862,28 @@ settings_load (GtkFileChooserWidget *impl) show_hidden = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_HIDDEN); show_size_column = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_SIZE_COLUMN); + show_type_column = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_TYPE_COLUMN); sort_column = g_settings_get_enum (settings, SETTINGS_KEY_SORT_COLUMN); sort_order = g_settings_get_enum (settings, SETTINGS_KEY_SORT_ORDER); sidebar_width = g_settings_get_int (settings, SETTINGS_KEY_SIDEBAR_WIDTH); startup_mode = g_settings_get_enum (settings, SETTINGS_KEY_STARTUP_MODE); sort_directories_first = g_settings_get_boolean (settings, SETTINGS_KEY_SORT_DIRECTORIES_FIRST); date_format = g_settings_get_enum (settings, SETTINGS_KEY_DATE_FORMAT); + type_format = g_settings_get_enum (settings, SETTINGS_KEY_TYPE_FORMAT); if (!priv->show_hidden_set) set_show_hidden (impl, show_hidden); priv->show_size_column = show_size_column; gtk_tree_view_column_set_visible (priv->list_size_column, show_size_column); + priv->show_type_column = show_type_column; + gtk_tree_view_column_set_visible (priv->list_type_column, show_type_column); priv->sort_column = sort_column; priv->sort_order = sort_order; priv->startup_mode = startup_mode; priv->sort_directories_first = sort_directories_first; priv->show_time = date_format == DATE_FORMAT_WITH_TIME; + priv->type_format = type_format; /* We don't call set_sort_column() here as the models may not have been * created yet. The individual functions that create and set the models will @@ -3865,12 +3908,14 @@ settings_save (GtkFileChooserWidget *impl) g_settings_set_boolean (settings, SETTINGS_KEY_SHOW_HIDDEN, gtk_file_chooser_get_show_hidden (GTK_FILE_CHOOSER (impl))); g_settings_set_boolean (settings, SETTINGS_KEY_SHOW_SIZE_COLUMN, priv->show_size_column); + g_settings_set_boolean (settings, SETTINGS_KEY_SHOW_TYPE_COLUMN, priv->show_type_column); g_settings_set_boolean (settings, SETTINGS_KEY_SORT_DIRECTORIES_FIRST, priv->sort_directories_first); g_settings_set_enum (settings, SETTINGS_KEY_SORT_COLUMN, priv->sort_column); g_settings_set_enum (settings, SETTINGS_KEY_SORT_ORDER, priv->sort_order); g_settings_set_int (settings, SETTINGS_KEY_SIDEBAR_WIDTH, gtk_paned_get_position (GTK_PANED (priv->browse_widgets_hpaned))); g_settings_set_enum (settings, SETTINGS_KEY_DATE_FORMAT, priv->show_time ? DATE_FORMAT_WITH_TIME : DATE_FORMAT_REGULAR); + g_settings_set_enum (settings, SETTINGS_KEY_TYPE_FORMAT, priv->type_format); /* Now apply the settings */ g_settings_apply (settings); @@ -4122,6 +4167,20 @@ compare_size (GtkFileSystemModel *model, return size_a < size_b ? -1 : (size_a == size_b ? 0 : 1); } +static gint +compare_type (GtkFileSystemModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + GtkFileChooserWidget *impl) +{ + const char *key_a, *key_b; + + key_a = g_value_get_string (_gtk_file_system_model_get_value (model, a, MODEL_COL_TYPE)); + key_b = g_value_get_string (_gtk_file_system_model_get_value (model, b, MODEL_COL_TYPE)); + + return g_strcmp0 (key_a, key_b); +} + static gint compare_time (GtkFileSystemModel *model, GtkTreeIter *a, @@ -4188,6 +4247,25 @@ size_sort_func (GtkTreeModel *model, return result; } +/* Sort callback for the type column */ +static gint +type_sort_func (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + GtkFileSystemModel *fs_model = GTK_FILE_SYSTEM_MODEL (model); + GtkFileChooserWidget *impl = user_data; + gint result; + + result = compare_directory (fs_model, a, b, impl); + + if (result == 0) + result = compare_type (fs_model, a, b, impl); + + return result; +} + /* Sort callback for the time column */ static gint time_sort_func (GtkTreeModel *model, @@ -4862,6 +4940,92 @@ file_system_model_got_thumbnail (GObject *object, gdk_threads_leave (); } +/* Copied from src/nautilus_file.c:get_description() */ +struct { + const char *icon_name; + const char *display_name; +} mime_type_map[] = { + { "application-x-executable", N_("Program") }, + { "audio-x-generic", N_("Audio") }, + { "font-x-generic", N_("Font") }, + { "image-x-generic", N_("Image") }, + { "package-x-generic", N_("Archive") }, + { "text-html", N_("Markup") }, + { "text-x-generic", N_("Text") }, + { "text-x-generic-template", N_("Text") }, + { "text-x-script", N_("Program") }, + { "video-x-generic", N_("Video") }, + { "x-office-address-book", N_("Contacts") }, + { "x-office-calendar", N_("Calendar") }, + { "x-office-document", N_("Document") }, + { "x-office-presentation", N_("Presentation") }, + { "x-office-spreadsheet", N_("Spreadsheet") }, +}; + +static char * +get_category_from_content_type (const char *content_type) +{ + char *icon_name; + char *basic_type = NULL; + + icon_name = g_content_type_get_generic_icon_name (content_type); + if (icon_name != NULL) + { + int i; + + for (i = 0; i < G_N_ELEMENTS (mime_type_map); i++) + { + if (strcmp (mime_type_map[i].icon_name, icon_name) == 0) + { + basic_type = g_strdup (gettext (mime_type_map[i].display_name)); + break; + } + } + + g_free (icon_name); + } + + if (basic_type == NULL) + { + basic_type = g_content_type_get_description (content_type); + if (basic_type == NULL) + { + basic_type = g_strdup (_("Unknown")); + } + } + + return basic_type; +} + +static char * +get_type_information (GtkFileChooserWidget *impl, + GFileInfo *info) +{ + const char *content_type; + char *mime_type; + char *description; + + content_type = g_file_info_get_content_type (info); + switch (impl->priv->type_format) + { + case TYPE_FORMAT_MIME: + mime_type = g_content_type_get_mime_type (content_type); + return mime_type ? mime_type : g_strdup (content_type); + + case TYPE_FORMAT_DESCRIPTION: + description = g_content_type_get_description (content_type); + return description ? description : g_strdup (content_type); + + case TYPE_FORMAT_CATEGORY: + return get_category_from_content_type (content_type); + + default: + g_assert_not_reached (); + } + + return g_strdup (""); +} + static gboolean file_system_model_set (GtkFileSystemModel *model, GFile *file, @@ -4989,6 +5153,12 @@ file_system_model_set (GtkFileSystemModel *model, else g_value_take_string (value, g_format_size (g_file_info_get_size (info))); break; + case MODEL_COL_TYPE: + if (info == NULL || _gtk_file_info_consider_as_directory (info)) + g_value_set_string (value, NULL); + else + g_value_take_string (value, get_type_information (impl, info)); + break; case MODEL_COL_TIME: case MODEL_COL_DATE_TEXT: case MODEL_COL_TIME_TEXT: @@ -5101,6 +5271,7 @@ set_list_model (GtkFileChooserWidget *impl, profile_msg (" set sort function", NULL); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (priv->browse_files_model), MODEL_COL_NAME, name_sort_func, impl, NULL); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (priv->browse_files_model), MODEL_COL_SIZE, size_sort_func, impl, NULL); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (priv->browse_files_model), MODEL_COL_TYPE, type_sort_func, impl, NULL); gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (priv->browse_files_model), MODEL_COL_TIME, time_sort_func, impl, NULL); gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (priv->browse_files_model), NULL, NULL, NULL); set_sort_column (impl); @@ -7240,6 +7411,7 @@ search_setup_model (GtkFileChooserWidget *impl) gtk_tree_view_column_set_sort_column_id (priv->list_name_column, -1); gtk_tree_view_column_set_sort_column_id (priv->list_time_column, -1); gtk_tree_view_column_set_sort_column_id (priv->list_size_column, -1); + gtk_tree_view_column_set_sort_column_id (priv->list_type_column, -1); gtk_tree_view_column_set_sort_column_id (priv->list_location_column, -1); update_columns (impl, TRUE, _("Modified")); @@ -7450,6 +7622,7 @@ recent_idle_cleanup (gpointer data) gtk_tree_view_column_set_sort_column_id (priv->list_name_column, -1); gtk_tree_view_column_set_sort_column_id (priv->list_time_column, -1); gtk_tree_view_column_set_sort_column_id (priv->list_size_column, -1); + gtk_tree_view_column_set_sort_column_id (priv->list_type_column, -1); gtk_tree_view_column_set_sort_column_id (priv->list_location_column, -1); update_columns (impl, TRUE, _("Accessed")); @@ -7873,6 +8046,12 @@ update_cell_renderer_attributes (GtkFileChooserWidget *impl) "sensitive", MODEL_COL_IS_SENSITIVE, NULL); + gtk_tree_view_column_set_attributes (priv->list_type_column, + priv->list_type_renderer, + "text", MODEL_COL_TYPE, + "sensitive", MODEL_COL_IS_SENSITIVE, + NULL); + gtk_tree_view_column_set_attributes (priv->list_time_column, priv->list_date_renderer, "text", MODEL_COL_DATE_TEXT, @@ -8457,6 +8636,8 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class) gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_time_renderer); gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_size_column); gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_size_renderer); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_type_column); + gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_type_renderer); gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_location_column); gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, list_location_renderer); gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, new_folder_name_entry); @@ -8609,6 +8790,8 @@ gtk_file_chooser_widget_init (GtkFileChooserWidget *impl) priv->select_multiple = FALSE; priv->show_hidden = FALSE; priv->show_size_column = TRUE; + priv->show_type_column = TRUE; + priv->type_format = TYPE_FORMAT_MIME; priv->icon_size = FALLBACK_ICON_SIZE; priv->load_state = LOAD_EMPTY; priv->reload_state = RELOAD_EMPTY; diff --git a/gtk/org.gtk.Settings.FileChooser.gschema.xml b/gtk/org.gtk.Settings.FileChooser.gschema.xml index c3753f2f6a..dda603ab61 100644 --- a/gtk/org.gtk.Settings.FileChooser.gschema.xml +++ b/gtk/org.gtk.Settings.FileChooser.gschema.xml @@ -25,7 +25,8 @@ - + + @@ -48,6 +49,12 @@ + + + + + + "" @@ -87,6 +94,13 @@ Controls whether the file chooser shows a column with file sizes. + + true + Show file types + + Controls whether the file chooser shows a column with file types. + + 'name' Sort column @@ -148,6 +162,17 @@ The amount of detail to show in the Modified column. + + 'category' + Type format + + Different ways to show the 'Type' column information. + Example outputs for a video mp4 file: + 'mime' -> 'video/mp4' + 'description' -> 'MPEG-4 video' + 'category' -> 'Video' + + diff --git a/gtk/ui/gtkfilechooserwidget.ui b/gtk/ui/gtkfilechooserwidget.ui index ef227bdc70..c1b4b43d50 100644 --- a/gtk/ui/gtkfilechooserwidget.ui +++ b/gtk/ui/gtkfilechooserwidget.ui @@ -230,6 +230,18 @@ + + + Type + 1 + + + 0 + 6 + + + + Modified diff --git a/gtk/ui/gtkfilechooserwidget.ui.h b/gtk/ui/gtkfilechooserwidget.ui.h index b29f3faf3b..e5fe4e26b8 100644 --- a/gtk/ui/gtkfilechooserwidget.ui.h +++ b/gtk/ui/gtkfilechooserwidget.ui.h @@ -4,6 +4,7 @@ N_("All Files"); N_("Files"); N_("Name"); N_("Size"); +N_("Type"); N_("Modified"); N_("Location"); N_("Select which types of files are shown");