/* PureAdmin
 * Copyright (C) 2003 Isak Savo
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
 * Dirbrowser-widget (similar to the file-selector distributet with GTK+). This is
 * in fact a stand-alone widget that easily can be used in other projects. Please give 
 * me credit for it and leave the copyright-notice is untouched. Thx!
 *
 * Simply add dirbrowser.c and .h to you project and use the functions declared in the .h-file
 * to access the widget!
 *
 * Copyright (C) 2003 Isak Savo
 */

/* FIXME: the text in the entry is the one that is used. We need a nicer handling!
 * Proposal: add a property, called 'directory' or similar a'la fileselector! */


#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include "dirbrowser.h"

/* These should not be included if used in other projects */
#include "globals.h"
#include "helper.h"

#ifndef MAXPATHLEN
# ifdef PATH_MAX
#   define MAXPATHLEN PATH_MAX
# else
#   define MAXPATHLEN 2048
# endif /* PATH:MAX */
#endif /* MAXPATHLEN */

static GtkWindowClass *parent_class = NULL;
/* Internal functions */
gboolean dirbrowser_select (Dirbrowser *dbr, const gchar *directory);
/*gboolean dirbrowser_populate (Dirbrowser *dbr, const gchar *directory);*/
void dirbrowser_populate_full_dir (Dirbrowser *dbr, const char *directory);
gint dirbrowser_populate_children (Dirbrowser *dbr, GtkTreeIter parent_iter, const char *directory);

static void dirbrowser_class_init (DirbrowserClass *klass);
static void dirbrowser_init (Dirbrowser *dbr);
static void dirbrowser_finalize      (GObject               *object);
static void dirbrowser_destroy       (GtkObject             *object);
static void dirbrowser_map           (GtkWidget             *widget);

void dirbrowser_cursor_changed (GtkTreeView *treeview, gpointer user_data);
gboolean dirbrowser_btnpress_event (GtkTreeView *treeview, GdkEventButton *event, gpointer user_data);
void dirbrowser_entry_changed (GtkEditable *entry, gpointer data);
void dirbrowser_btnhome_clicked (GtkButton *btn, gpointer data);
gchar **_dirbrowser_directory_split (const gchar *directory);
gchar *_dirbrowser_treepath_to_fspath (const GtkTreePath *c_path, GtkTreeModel *model);
GList *_dirbrowser_get_dircontents (const gchar *directory);

static void dirbrowser_get_property (GObject         *object,
				     guint            prop_id,
				     GValue          *value,
				     GParamSpec      *pspec);
static void dirbrowser_set_property (GObject         *object,
				     guint            prop_id,
				     const GValue    *value,
				     GParamSpec      *pspec);

enum {
	COL_IMAGE = 0,
	COL_NAME,
	COL_FSNAME,
	N_DIR_COLUMNS
};

enum {
	PROP_0,
	PROP_DIRECTORY
};

static gboolean grab_default (GtkWidget *widget)
{
	gtk_widget_grab_default (widget);
	return FALSE;
}

GType
dirbrowser_get_type (void)
{
	static GType dirbrowser_type = 0;
   
	if (!dirbrowser_type)
	{
		static const GTypeInfo dirbrowser_info =
			{
				sizeof (DirbrowserClass),
				NULL, /* base_init */
				NULL, /* base_finalize */
				(GClassInitFunc) dirbrowser_class_init,
				NULL, /* class_finalize */
				NULL, /* class_data */
				sizeof (Dirbrowser),
				0,    /* n_preallocs */
				(GInstanceInitFunc) dirbrowser_init,
			};
		dirbrowser_type = 
			g_type_register_static (GTK_TYPE_DIALOG, "Dirbrowser",
						&dirbrowser_info, 0);
	}
	return dirbrowser_type;
}

static void
dirbrowser_class_init (DirbrowserClass *klass)
{
	GObjectClass *gobject_class;
	GtkObjectClass *object_class;
	GtkWidgetClass *widget_class;

	gobject_class = (GObjectClass*) klass;
	object_class = (GtkObjectClass*) klass;
	widget_class = (GtkWidgetClass*) klass;
   

	parent_class = g_type_class_peek_parent (klass);
   
	gobject_class->finalize = dirbrowser_finalize; 
	object_class->destroy = dirbrowser_destroy;
	widget_class->map = dirbrowser_map;
   
	gobject_class->set_property = dirbrowser_set_property;
	gobject_class->get_property = dirbrowser_get_property;
   
	g_object_class_install_property (gobject_class,
					 PROP_DIRECTORY,
					 g_param_spec_string ("directory",
							      N_("Directory"),
							      N_("The currently selected directory"),
							      NULL,
							      G_PARAM_READABLE | G_PARAM_WRITABLE));
   
}

static void dirbrowser_set_property (GObject         *object,
				     guint            prop_id,
				     const GValue    *value,
				     GParamSpec      *pspec)
{
	Dirbrowser *db;

	db = DIRBROWSER (object);

	switch (prop_id)
	{
	case PROP_DIRECTORY:
		dirbrowser_set_directory (db, g_value_get_string (value));
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}

static void dirbrowser_get_property (GObject         *object,
				     guint            prop_id,
				     GValue          *value,
				     GParamSpec      *pspec)
{
	Dirbrowser *db;
   
	db = DIRBROWSER (object);
   
	switch (prop_id)
	{
	case PROP_DIRECTORY:
		g_value_set_string (value,
				    dirbrowser_get_directory (db));
		break;
	
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}

static void
dirbrowser_init (Dirbrowser *dbr)
{
	GtkDialog *dlg;
	GtkTreeStore *store;
	GtkTreeViewColumn *column;
	GtkTreeIter iter;
	GtkCellRenderer *renderer_img, *renderer_txt;
	GtkWidget *vbox;
   
	dlg = GTK_DIALOG (dbr);
	gtk_widget_set_size_request (GTK_WIDGET (dlg), 250, 350);
	gtk_container_set_border_width (GTK_CONTAINER (dlg), 6);
	gtk_window_set_title (GTK_WINDOW (dlg), _("Select directory"));
	gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE);
   
	vbox = GTK_DIALOG (dlg)->vbox;
	gtk_widget_show (vbox);

	dbr->main_vbox = gtk_vbox_new (FALSE, 6);
	gtk_widget_show (dbr->main_vbox);
	gtk_box_pack_start (GTK_BOX (vbox), dbr->main_vbox, TRUE, TRUE, 0);
	gtk_container_set_border_width (GTK_CONTAINER (dbr->main_vbox), 6);

	dbr->btnbox = gtk_hbutton_box_new ();
	gtk_widget_show (dbr->btnbox);
	gtk_box_pack_start (GTK_BOX (dbr->main_vbox), dbr->btnbox, FALSE, FALSE, 0);
	gtk_button_box_set_layout (GTK_BUTTON_BOX (dbr->btnbox), GTK_BUTTONBOX_START);

	dbr->btn_home = gtk_button_new_from_stock ("gtk-home");
	gtk_widget_show (dbr->btn_home);
	gtk_container_add (GTK_CONTAINER (dbr->btnbox), dbr->btn_home);
	GTK_WIDGET_SET_FLAGS (dbr->btn_home, GTK_CAN_DEFAULT);
	gtk_button_set_relief (GTK_BUTTON (dbr->btn_home), GTK_RELIEF_HALF);

	dbr->location = gtk_entry_new ();
	gtk_widget_show (dbr->location);
	gtk_box_pack_start (GTK_BOX (dbr->main_vbox), dbr->location, FALSE, FALSE, 0);

	dbr->scr_win = gtk_scrolled_window_new (NULL, NULL);
	gtk_widget_show (dbr->scr_win);
	gtk_box_pack_start (GTK_BOX (dbr->main_vbox), dbr->scr_win, TRUE, TRUE, 0);

	dbr->dir_tree = gtk_tree_view_new ();
	gtk_widget_show (dbr->dir_tree);
	gtk_container_add (GTK_CONTAINER (dbr->scr_win), dbr->dir_tree);
	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dbr->dir_tree), TRUE);

	gtk_widget_show (dlg->action_area);
	gtk_button_box_set_layout (GTK_BUTTON_BOX (dlg->action_area), GTK_BUTTONBOX_END);

	dbr->btn_cancel = gtk_button_new_from_stock ("gtk-cancel");
	gtk_widget_show (dbr->btn_cancel);
	gtk_dialog_add_action_widget (GTK_DIALOG (dlg), dbr->btn_cancel, GTK_RESPONSE_CANCEL);
	GTK_WIDGET_SET_FLAGS (dbr->btn_cancel, GTK_CAN_DEFAULT);

	dbr->btn_ok = gtk_button_new_from_stock ("gtk-ok");
	gtk_widget_show (dbr->btn_ok);
	gtk_dialog_add_action_widget (GTK_DIALOG (dlg), dbr->btn_ok, GTK_RESPONSE_OK);
	GTK_WIDGET_SET_FLAGS (dbr->btn_ok, GTK_CAN_DEFAULT);
   
	/* Initiate the treeview */
	gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (dbr->dir_tree)),
				     GTK_SELECTION_SINGLE);
   
	store = gtk_tree_store_new (N_DIR_COLUMNS, 
				    GDK_TYPE_PIXBUF,
				    G_TYPE_STRING,
				    G_TYPE_STRING);
	gtk_tree_view_set_model (GTK_TREE_VIEW (dbr->dir_tree), GTK_TREE_MODEL (store));

	g_object_unref (G_OBJECT (store));

	column = gtk_tree_view_column_new ();
	renderer_img = gtk_cell_renderer_pixbuf_new ();
	renderer_txt = gtk_cell_renderer_text_new ();

	/* Only create a view for the first two columns (icon and utf8 name), the 
	 * last column is the *real* fsname, as got from g_dir_read_name() 
	 */
   
	gtk_tree_view_column_pack_start (column, renderer_img, FALSE);
	gtk_tree_view_column_add_attribute (column, renderer_img,
					    "pixbuf", COL_IMAGE);

	gtk_tree_view_column_pack_end (column, renderer_txt, TRUE);
	gtk_tree_view_column_add_attribute (column, renderer_txt,
					    "text", COL_NAME);

	gtk_tree_view_insert_column (GTK_TREE_VIEW (dbr->dir_tree), column, -1);
   
	/* Directory-icon -- Rendered using the current theme */
	dbr->icon = gtk_widget_render_icon (GTK_WIDGET (dbr), GTK_STOCK_OPEN,
					    GTK_ICON_SIZE_MENU,
					    NULL);

	/* Add root-directory w/ children */
	gtk_tree_store_append (GTK_TREE_STORE (store), &iter, NULL);
	gtk_tree_store_set (GTK_TREE_STORE (store), &iter,
			    COL_IMAGE, dbr->icon,
			    COL_NAME, "/",
			    COL_FSNAME, "/",
			    -1);
	dirbrowser_populate_children (dbr, iter, "/");

	dbr->hid_cursor_changed =
		g_signal_connect ((gpointer) dbr->dir_tree, "cursor_changed",
				  G_CALLBACK (dirbrowser_cursor_changed),
				  (gpointer) dbr);
   
	g_signal_connect ((gpointer) dbr->dir_tree, "button_press_event",
			  G_CALLBACK (dirbrowser_btnpress_event), 
			  (gpointer) dbr);

	dbr->hid_entry_changed =
		g_signal_connect ((gpointer) dbr->location, "changed",
				  G_CALLBACK (dirbrowser_entry_changed),
				  (gpointer) dbr);
   
	g_signal_connect_swapped (dbr->location, "focus_in_event",
				  G_CALLBACK (grab_default),
				  dbr->btn_ok);
	g_signal_connect_swapped (dbr->location, "activate",
				  G_CALLBACK (gtk_button_clicked),
				  dbr->btn_ok);
	g_signal_connect ((gpointer) dbr->btn_home, "clicked",
			  G_CALLBACK (dirbrowser_btnhome_clicked),
			  (gpointer) dbr);

	gtk_widget_grab_focus (dbr->location);
}

/* FIXME: Are these needed?? */
static void dirbrowser_finalize (GObject  *object)
{
	G_OBJECT_CLASS (parent_class)->finalize (object);
}

static void dirbrowser_destroy (GtkObject *object)
{
	GTK_OBJECT_CLASS (parent_class)->destroy (object);
}

static void dirbrowser_map (GtkWidget *widget)
{
	GTK_WIDGET_CLASS (parent_class)->map (widget);
}

void dirbrowser_set_directory (Dirbrowser *dir_browser, const char *directory)
{
	gchar *directory_utf8;
   
	g_return_if_fail (IS_DIRBROWSER (dir_browser));
	g_return_if_fail (directory != NULL);
	g_return_if_fail (g_file_test (directory, G_FILE_TEST_IS_DIR));

	directory_utf8 = g_filename_to_utf8 (directory, -1, NULL, NULL, NULL);
	g_return_if_fail (directory_utf8 != NULL);
   
	if (dir_browser->location)
		gtk_entry_set_text (GTK_ENTRY (dir_browser->location), directory_utf8);
   
	g_object_notify (G_OBJECT (dir_browser), "directory");
	g_free (directory_utf8);
}

/**
 * dirbrowser_get_directory:
 * @dir_browser: a #Dirbrowser
 *
 * This functions returns the current selected directory in the current
 * on-disk encoding. (see g_filename_from_utf8() in gtk-docs). 
 * The returned string points to a statically allocated buffer and
 * should be copied if you plan to keep it around.
 *
 * If no directory is selected, the empty string, "", is returned.
 *
 * Return value: currently selected directory in the on-disk encoding.
 **/
G_CONST_RETURN gchar *dirbrowser_get_directory (Dirbrowser *dir_browser)
{
	static const gchar nothing[2] = "";
	static gchar something[MAXPATHLEN+2];
	const gchar *utf8_name;
	gchar *sys_name;

	g_return_val_if_fail (IS_DIRBROWSER (dir_browser), nothing);
   
	if (dir_browser->location)
	{
		utf8_name = gtk_entry_get_text (GTK_ENTRY (dir_browser->location));
		sys_name = g_filename_from_utf8 (utf8_name, -1, NULL, NULL, NULL);
      
		if (!sys_name)
			return nothing;
      
		strncpy (something, sys_name, sizeof (something));
		g_free (sys_name);
		return something;
	}
	return nothing;
}

GtkWidget *dirbrowser_new (const gchar *title)
{
	Dirbrowser *dbr;
   
	dbr = g_object_new (DIRBROWSER_TYPE, NULL);
	if (title)
		gtk_window_set_title (GTK_WINDOW (dbr), title);
   
	return GTK_WIDGET (dbr);
}

void dirbrowser_entry_changed (GtkEditable *entry, gpointer user_data)
{
	Dirbrowser *dbr;
	gchar *location;

	location = gtk_editable_get_chars (entry, 0, -1);
	dbr = DIRBROWSER (user_data);
	if (g_file_test (location, G_FILE_TEST_IS_DIR))
	{
		dirbrowser_populate_full_dir (dbr, location);
		dirbrowser_select (dbr, location);
	}
   
	g_free (location);
}

void dirbrowser_cursor_changed (GtkTreeView *treeview, gpointer user_data)
{
	Dirbrowser *dbr;
	GtkTreeIter iter;
	GtkTreeModel *store;
	GtkTreeSelection *sel;
	GtkTreePath *path;
	gchar *fs_path;
	gint i = 0;
   
	dbr = DIRBROWSER (user_data);
	g_return_if_fail (IS_DIRBROWSER (dbr));
	store = gtk_tree_view_get_model (treeview);
	sel = gtk_tree_view_get_selection (treeview);
	g_return_if_fail (gtk_tree_selection_get_selected (sel, &store, &iter));
   
	path = gtk_tree_model_get_path (store, &iter);
   
	fs_path = _dirbrowser_treepath_to_fspath (path, store);
   
	if (!gtk_tree_model_iter_n_children (store, &iter))
		i = dirbrowser_populate_children (dbr, iter, fs_path);
   
	//gtk_tree_view_expand_row (treeview, path, FALSE);

	g_signal_handler_block ((gpointer) dbr->location, dbr->hid_entry_changed);
	gtk_entry_set_text (GTK_ENTRY (dbr->location), fs_path);
	g_signal_handler_unblock ((gpointer) dbr->location, dbr->hid_entry_changed);

	g_free (fs_path);
}

gboolean dirbrowser_btnpress_event (GtkTreeView *treeview, GdkEventButton *event, gpointer user_data)
{
	Dirbrowser *dbr;
	GtkTreeSelection *sel;
	GtkTreeModel *model;
	GtkTreePath *path;
	GtkTreeIter iter;
   
	dbr = DIRBROWSER (user_data);
	g_return_val_if_fail (IS_DIRBROWSER (dbr), FALSE);

	model = gtk_tree_view_get_model (treeview);
	sel = gtk_tree_view_get_selection (treeview);
	g_return_val_if_fail (gtk_tree_selection_get_selected (sel, &model, &iter), FALSE);

	if (event->type == GDK_2BUTTON_PRESS)
	{
		path = gtk_tree_model_get_path (model, &iter);
      
		if (gtk_tree_view_row_expanded (treeview, path))
			gtk_tree_view_collapse_row (treeview, path);
		else
			gtk_tree_view_expand_row (treeview, path, FALSE);
      
		gtk_tree_path_free (path);
	}
	return FALSE;
}

void dirbrowser_btnhome_clicked (GtkButton *btn, gpointer data)
{
	Dirbrowser *dbr;
   
	dbr = DIRBROWSER (data);
	g_return_if_fail (IS_DIRBROWSER (dbr));

	gtk_entry_set_text (GTK_ENTRY (dbr->location), g_get_home_dir ());
}


/* This function is taken directly from the GTK+-2.6.9 sources to maintain compatibility with
 * GTK 2.0.x */
static void
pureadmin_gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
					GtkTreePath *path)
{
	gint i, depth;
	gint *indices;
	GtkTreePath *tmp;

	g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
	g_return_if_fail (path != NULL);
	
	depth = gtk_tree_path_get_depth (path);
	indices = gtk_tree_path_get_indices (path);

	tmp = gtk_tree_path_new ();
	g_return_if_fail (tmp != NULL);

	for (i = 0; i < depth; i++)
	{
		gtk_tree_path_append_index (tmp, indices[i]);
		gtk_tree_view_expand_row (tree_view, tmp, FALSE);
	}
	
	gtk_tree_path_free (tmp);
}

gboolean dirbrowser_select (Dirbrowser *dbr, const gchar *directory)
{
	GtkTreeModel *model;
	GtkTreeIter iter, child_iter;
	GtkTreePath *path;
	GtkTreeSelection *sel;
	gchar **dir_v, *tmp;
	gint i = 0;
	gboolean found = FALSE;

	g_return_val_if_fail (IS_DIRBROWSER (dbr), FALSE);
	g_return_val_if_fail (g_path_is_absolute (directory), FALSE);
   
	model = gtk_tree_view_get_model (GTK_TREE_VIEW (dbr->dir_tree));
	gtk_tree_model_get_iter_first (model, &iter);
	dir_v = _dirbrowser_directory_split (directory);
   
	while (dir_v[i]/*  && gtk_tree_store_iter_is_valid (GTK_TREE_STORE (model), &iter) */)
	{
		found = FALSE;
		gtk_tree_model_get (model, &iter,
				    COL_FSNAME, &tmp,
				    -1);
		if (strcmp (dir_v[i], tmp) == 0)
		{
			/* MATCH */
			found = TRUE;
			if (gtk_tree_model_iter_children (model, &child_iter, &iter))
			{
				if (dir_v[i+1])
					memcpy (&iter, &child_iter, sizeof (GtkTreeIter));
				i++;
			}
			else
			{
				g_free (tmp);
				break;
			}
		}
		else
			gtk_tree_model_iter_next (model, &iter);
      
		g_free (tmp);
	}
	if (found)
	{
		sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (dbr->dir_tree));
		path = gtk_tree_model_get_path (model, &iter);

		g_signal_handler_block ((gpointer) dbr->dir_tree, dbr->hid_cursor_changed);

		
		pureadmin_gtk_tree_view_expand_to_path (GTK_TREE_VIEW (dbr->dir_tree), path);
		gtk_tree_view_expand_row (GTK_TREE_VIEW (dbr->dir_tree), path, FALSE);
		gtk_tree_selection_select_path (sel, path);
		while (g_main_context_pending (NULL))
			g_main_context_iteration (NULL, FALSE);
		gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (dbr->dir_tree), path, NULL, TRUE, 0.3, 0);

		g_signal_handler_unblock ((gpointer) dbr->dir_tree, dbr->hid_cursor_changed);
      
		gtk_tree_path_free (path);
	}
	return TRUE;
}

void dirbrowser_populate_full_dir (Dirbrowser *dbr, const char *directory)
{
	GtkTreeModel *model;
	GtkTreeIter iter, child_iter;
	gchar **dir_v, *tmp;
	GString *cur_dir;
	gint i = 0, count;
   
	g_return_if_fail (IS_DIRBROWSER (dbr));
	g_return_if_fail (g_path_is_absolute (directory));
   
	model = gtk_tree_view_get_model (GTK_TREE_VIEW (dbr->dir_tree));
	gtk_tree_model_get_iter_first (model, &iter);
   
	cur_dir = g_string_new ("");
	dir_v = _dirbrowser_directory_split (directory);
	while (dir_v[i])
	{
		gtk_tree_model_get (model, &iter,
				    COL_FSNAME, &tmp,
				    -1);
		if (strcmp (dir_v[i], tmp) == 0)
		{
			cur_dir = g_string_append (cur_dir, dir_v[i]);
			if (!gtk_tree_model_iter_n_children (model, &iter))
			{
				count = dirbrowser_populate_children (dbr, iter, cur_dir->str);
				if (count < 1)
					break;
			}
			gtk_tree_model_iter_children (model, &child_iter, &iter);
			memcpy (&iter, &child_iter, sizeof (GtkTreeIter));
			if (*dir_v[i] != '/')
				cur_dir = g_string_append_c (cur_dir, '/');
			i++;
		}
		else
			gtk_tree_model_iter_next (model, &iter);
	
	}
	g_strfreev (dir_v);
	g_string_free (cur_dir, TRUE);
}

gint dirbrowser_populate_children (Dirbrowser *dbr, GtkTreeIter parent_iter, const gchar *directory)
{
	GtkTreeModel *model;
	GtkTreeIter child_iter;
	gchar *utf8_entry, *entry;
	GList *dirlist, *node;
	gint count = 0;
   
	g_return_val_if_fail (IS_DIRBROWSER (dbr), 0);
	model = gtk_tree_view_get_model (GTK_TREE_VIEW (dbr->dir_tree));
	g_return_val_if_fail (g_path_is_absolute (directory) || model != NULL , 0);

	node = dirlist = _dirbrowser_get_dircontents (directory);
	g_return_val_if_fail (dirlist != NULL, 0);
	do
	{
		entry = (gchar *) node->data;
		utf8_entry = g_filename_to_utf8 (entry, -1, NULL, NULL, NULL);
		if (utf8_entry && g_utf8_validate (utf8_entry, -1, NULL))
		{
			count++;
			gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &parent_iter);
			gtk_tree_store_set (GTK_TREE_STORE (model), &child_iter,
					    COL_IMAGE, dbr->icon,
					    COL_NAME, utf8_entry,
					    COL_FSNAME, entry,
					    -1);
		}
		else
			g_warning ("%s: Invalid entry: %s\n", __FUNCTION__, entry);
		g_free (utf8_entry);
		g_free (node->data);
	} while ((node = g_list_next(node)));

	g_list_free (dirlist);
	return count;
}

/* Returns the contents of a directory in a sorted GList */   
GList *_dirbrowser_get_dircontents (const gchar *directory)
{
	const gchar *entry;
	gchar *full_path;
	GDir *dir;
	GList *retval = NULL;

	dir = g_dir_open (directory, 0, NULL);
	g_return_val_if_fail (dir != NULL, NULL);

	while ((entry = g_dir_read_name (dir)))
	{
		full_path = g_strdup_printf ("%s/%s",directory, entry);
		/* FIXME: strcasecmp needs to be replaced here! */
      
		if (g_file_test (full_path, G_FILE_TEST_IS_DIR) && *entry != '.')
			retval = g_list_insert_sorted (retval, g_strdup (entry), (GCompareFunc) g_strcasecmp);
      
		g_free (full_path);
	}
	g_dir_close (dir);

	return g_list_first (retval);
}

gchar **_dirbrowser_directory_split (const gchar *directory)
{
	gchar **ret;
	gchar **tmp_v;
	gint i = 0, j = 0;

	tmp_v = g_strsplit (directory, "/", 0);
	if (!tmp_v)
		return g_strsplit ("", "/", 0);
   
	while (tmp_v[i++])
		; /* Check how many parts we have.. */
   
	ret = g_new0 (gchar *, i);
	/* Was: (gchar **) g_malloc0 (i * sizeof (gchar *)); */
	i = -1;
	ret[j++] = g_strdup ("/");
	while (tmp_v[++i])
	{
		if (*tmp_v[i] == '\0')
			continue;
		ret[j++] = g_strdup (tmp_v[i]);
	}
	g_strfreev (tmp_v);

	return ret;
}

gchar *_dirbrowser_treepath_to_fspath (const GtkTreePath *c_path, GtkTreeModel *model)
{
	GString *fs_path;
	GtkTreeIter iter;
	GtkTreePath *path;
	gchar *ret, *entry;

	path = gtk_tree_path_copy (c_path);
	if (gtk_tree_path_get_depth (path) == 1)
		return g_strdup ("/");

	fs_path = g_string_new ("");
	while (gtk_tree_path_get_depth (path) > 1)
	{
		gtk_tree_model_get_iter (model, &iter, path);
		gtk_tree_model_get (model, &iter,
				    COL_FSNAME, &entry,
				    -1);
		g_string_prepend (fs_path, entry);
		if (*entry != '/')
			g_string_prepend_c (fs_path, '/');
		gtk_tree_path_up (path);
	}
	ret = fs_path->str;
	g_string_free (fs_path, FALSE);
	gtk_tree_path_free (path);
	return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1