summaryrefslogblamecommitdiff
path: root/saedit/treefolderview/treefolderview.c
blob: e1b02f03110e52c375c1ee70bfade8c6784bd1ec (plain) (tree)















































































































































































































































































































































































































                                                                                                      
#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"