#include "treefolderview.h" #include "treefolderviewprivate.h" enum { STORE_COLUMN_FILE_NAME, STORE_COLUMN_IS_FOLDER, STORE_COLUMN_FILE_ICON, STORE_COLUMN_FILE_INFO, STORE_COLUMN_WAS_EXPANDED, STORE_COLUMN_COUNT }; enum { SIGNAL_FILE_ACTIVATED, SIGNAL_COUNT }; struct _TreeFolderViewPrivate { gchar *filename; GtkFileFilter *file_filter; }; static guint tfview_signals [SIGNAL_COUNT] = { 0 }; static GtkTreeStore * tree_folder_view_get_store (TreeFolderView *tfview) { GtkTreeModelFilter *model; model = GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (tfview))); return GTK_TREE_STORE (gtk_tree_model_filter_get_model (model)); } static gboolean file_filter_filter_file_info (GtkFileFilter *filter, GFileInfo *info) { gboolean result; gchar *mimetype = NULL; GtkFileFilterFlags required; GtkFileFilterInfo filter_info = { 0, }; if (filter == NULL) return TRUE; required = gtk_file_filter_get_needed (filter); filter_info.contains |= GTK_FILE_FILTER_DISPLAY_NAME; filter_info.display_name = g_file_info_get_display_name (info); if (required & GTK_FILE_FILTER_MIME_TYPE) { const gchar *ctype = g_file_info_get_content_type (info); if (ctype != NULL) { mimetype = g_content_type_get_mime_type (ctype); if (mimetype != NULL) { filter_info.contains |= GTK_FILE_FILTER_MIME_TYPE; filter_info.mime_type = mimetype; } } } if (required & GTK_FILE_FILTER_FILENAME) { filter_info.filename = g_file_info_get_name (info); filter_info.contains |= GTK_FILE_FILTER_FILENAME; } result = gtk_file_filter_filter (filter, &filter_info); g_free(mimetype); return result; } static gchar * tree_folder_view_get_file_path_from_tree_path ( TreeFolderView *tfview, GtkTreePath *path ) { GtkTreeIter iter; GtkTreeModel *model; model = GTK_TREE_MODEL (tree_folder_view_get_store (tfview)); gtk_tree_model_get_iter (model, &iter, path); return tree_folder_view_get_file_path_from_iter (tfview, &iter); } static gchar * tree_folder_view_get_file_path_from_iter ( TreeFolderView *tfview, GtkTreeIter *file_iter ) { gchar *result, *data; GPtrArray *names; GtkTreeIter iter; GtkTreeModel *model; GtkTreePath *_path; model = GTK_TREE_MODEL (tree_folder_view_get_store (tfview)); _path = gtk_tree_model_get_path (model, file_iter); names = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); while (gtk_tree_path_get_depth (_path) > 0) { gtk_tree_model_get_iter (model, &iter, _path); gtk_tree_model_get ( model, &iter, STORE_COLUMN_FILE_NAME, &data, -1 ); g_ptr_array_insert (names, 0, data); gtk_tree_path_up (_path); } g_ptr_array_insert (names, 0, g_strdup (tfview->priv->filename)); g_ptr_array_add (names, NULL); result = g_strjoinv ("/", (gchar **) names->pdata); g_ptr_array_free (names, TRUE); gtk_tree_path_free (_path); return result; } static void tree_folder_view_row_expanded ( GtkTreeView *tree_view, GtkTreeIter *filter_iter, GtkTreePath *path ) { gboolean w_exp; gchar *file_path; GtkTreeIter iter, citer; GtkTreeStore *store; gtk_tree_model_filter_convert_iter_to_child_iter ( GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (tree_view)), &iter, filter_iter ); store = tree_folder_view_get_store ( TREE_FOLDER_VIEW (tree_view) ); gtk_tree_model_get ( GTK_TREE_MODEL (store), &iter, STORE_COLUMN_WAS_EXPANDED, &w_exp, -1 ); if (w_exp) return; gtk_tree_store_set ( store, &iter, STORE_COLUMN_WAS_EXPANDED, TRUE, -1 ); if (!gtk_tree_model_iter_has_child (GTK_TREE_MODEL (store), &iter)) return; gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &citer, &iter); do { file_path = tree_folder_view_get_file_path_from_iter ( TREE_FOLDER_VIEW (tree_view), &citer ); tree_store_append_file_children ( store, &citer, file_path, FALSE ); g_free (file_path); } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &citer)); } static gboolean tree_model_filter_file_visible_func ( GtkTreeModel *model, GtkTreeIter *iter, gpointer data ) { gboolean is_folder; GFileInfo *info; GtkFileFilter *filter; TreeFolderView *tfview; tfview = TREE_FOLDER_VIEW (data); gtk_tree_model_get ( model, iter, STORE_COLUMN_FILE_INFO, &info, STORE_COLUMN_IS_FOLDER, &is_folder, -1 ); if (info == NULL) return FALSE; if (g_file_info_get_is_hidden (info)) return FALSE; if (is_folder) return TRUE; filter = tree_folder_view_get_filter (tfview); return file_filter_filter_file_info (filter, info); } static void tree_store_append_file_children ( GtkTreeStore *store, GtkTreeIter *iter, const gchar *path, gboolean expanded ) { gchar *npath; const gchar *name; GDir *dir; dir = g_dir_open (path, 0, NULL); if (dir == NULL) return; while ((name = g_dir_read_name (dir)) != NULL) { npath = g_strconcat (path, "/", name, NULL); tree_store_append_file_recursive ( store, iter, npath, name, expanded ); g_free(npath); } g_dir_close (dir); } static gint tree_store_append_file_recursive ( GtkTreeStore *store, GtkTreeIter *parent_iter, const gchar *path, const gchar *display_name, gboolean append_children ) { GFile *file; GFileInfo *info; GtkTreeIter iter; file = g_file_new_for_path (path); info = g_file_query_info (file, "*", 0, NULL, NULL); g_object_unref (file); gtk_tree_store_append (store, &iter, parent_iter); gtk_tree_store_set ( store, &iter, STORE_COLUMN_FILE_NAME, display_name, STORE_COLUMN_FILE_ICON, g_content_type_get_icon (g_file_info_get_content_type (info)), STORE_COLUMN_FILE_INFO, info, STORE_COLUMN_IS_FOLDER, FALSE, STORE_COLUMN_WAS_EXPANDED, FALSE, -1 ); if (g_file_info_get_file_type (info) != G_FILE_TYPE_DIRECTORY) return 0; gtk_tree_store_set ( store, &iter, STORE_COLUMN_IS_FOLDER, TRUE, STORE_COLUMN_FILE_ICON, g_themed_icon_new ("folder"), -1 ); if (!append_children) return 1; tree_store_append_file_children (store, &iter, path, FALSE); return 1; } static gint tree_store_iter_compare_func ( GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data ) { gboolean isf_a, isf_b; gint cmp; gchar *val_a, *val_b; gtk_tree_model_get (model, a, STORE_COLUMN_IS_FOLDER, &isf_a, -1); gtk_tree_model_get (model, b, STORE_COLUMN_IS_FOLDER, &isf_b, -1); if (isf_a != isf_b) return isf_b; gtk_tree_model_get (model, a, STORE_COLUMN_FILE_NAME, &val_a, -1); gtk_tree_model_get (model, b, STORE_COLUMN_FILE_NAME, &val_b, -1); cmp = g_strcmp0 (val_a, val_b); g_free (val_a); g_free (val_b); return cmp; } static void tree_folder_view_row_activated ( GtkTreeView *tree_view, GtkTreePath *filter_path, GtkTreeViewColumn *col ) { gboolean is_folder; GtkTreeIter iter; GtkTreePath *path; GtkTreeStore *store; path = gtk_tree_model_filter_convert_path_to_child_path ( GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (tree_view)), filter_path ); store = tree_folder_view_get_store (TREE_FOLDER_VIEW (tree_view)); gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path); gtk_tree_model_get ( GTK_TREE_MODEL (store), &iter, STORE_COLUMN_IS_FOLDER, &is_folder, -1 ); if (is_folder) return; g_signal_emit ( tree_view, tfview_signals[SIGNAL_FILE_ACTIVATED], 0, tree_folder_view_get_file_path_from_tree_path ( TREE_FOLDER_VIEW (tree_view), path ) ); gtk_tree_path_free (path); } void tree_folder_view_set_filename ( TreeFolderView *tfview, const gchar *filename ) { GtkTreeStore *store = tree_folder_view_get_store (tfview); /* TODO: values inside are not freed */ gtk_tree_store_clear (store); g_free (tfview->priv->filename); tfview->priv->filename = g_strdup (filename); if (filename != NULL) { tree_store_append_file_children ( store, NULL, filename, TRUE ); } } GtkFileFilter * tree_folder_view_get_filter (TreeFolderView *tfview) { return tfview->priv->file_filter; } void tree_folder_view_set_filter (TreeFolderView *tfview, GtkFileFilter *filter) { if (G_IS_OBJECT (tfview->priv->file_filter)) g_object_unref (tfview->priv->file_filter); tfview->priv->file_filter = filter; g_object_ref (filter); gtk_tree_model_filter_refilter ( GTK_TREE_MODEL_FILTER (gtk_tree_view_get_model (GTK_TREE_VIEW (tfview)))); } gchar * tree_folder_view_get_filename (TreeFolderView *tfview) { return g_strdup (tfview->priv->filename); } #include "type.c"