/*
 * $Id$
 *
 * EFiler - EDE File Manager
 * Part of Equinox Desktop Environment (EDE).
 * Copyright (c) 2000-2006 EDE Authors.
 *
 * This program is licenced under terms of the
 * GNU General Public Licence version 2 or newer.
 * See COPYING for details.
 */

#include <fltk/run.h>
#include <fltk/filename.h>
#include <fltk/Window.h>
#include <fltk/ScrollGroup.h>
#include <fltk/Button.h>
#include <fltk/ask.h>
#include <fltk/events.h>
#include <fltk/MenuBar.h>
#include <fltk/ItemGroup.h>
#include <fltk/Item.h>
#include <fltk/Divider.h>
#include <fltk/file_chooser.h>
//#include <fltk/FileBrowser.h>
#include <fltk/TiledGroup.h>
#include <fltk/ProgressBar.h>

#include "../edelib2/about_dialog.h"
#include "../edelib2/Icon.h"
#include "../edelib2/MimeType.h"
#include "../edelib2/NLS.h"
#include "../edelib2/Run.h"
#include "../edelib2/Util.h"

#include "EDE_FileBrowser.h"
#include "EDE_DirTree.h"


#define DEFAULT_ICON "misc-vedran"


using namespace fltk;
using namespace edelib;



Window *win;
TiledGroup* tile;
ScrollGroup* sgroup;
FileBrowser* fbrowser;
DirTree* dirtree;
char current_dir[PATH_MAX];
static bool semaphore=false;
bool showhidden = false;
bool showtree = false;

char **cut_copy_buffer = 0;
bool operation_is_copy = false;




/*-----------------------------------------------------------------
	Icon View implementation

NOTE: This will eventually be moved into a separate class. We know
there are ugly/unfinished stuff here, but please be patient.
-------------------------------------------------------------------*/


// Prototype (loaddir is called from button_press and vice versa
void loaddir(const char* path);

// Callback for icons in icon view
void button_press(Widget* w, void*) {
	if (event_clicks() || event_key() == ReturnKey) {
		if (!w->user_data() || (strlen((char*)w->user_data())==0)) 
			alert(_("Unknown file type"));
		else if (strncmp((char*)w->user_data(),"efiler ",7)==0) {
			// don't launch new efiler instance
			char tmp[PATH_MAX];
			strncpy(tmp,(char*)w->user_data()+7,PATH_MAX);

			// remove quotes
			if (tmp[0] == '\'' || tmp[0] == '"')
				memmove(tmp,tmp+1,strlen(tmp)-1);
			int i=strlen(tmp)-2;
			if (tmp[i] == '\'' || tmp[i] == '"')
				tmp[i] = '\0';

			loaddir(tmp);
		} else {
			fprintf(stderr, "Running: %s\n", (char*)w->user_data());
			run_program((char*)w->user_data(),false,false,true);
		}
	}
	if (event_is_click()) w->take_focus();
	fprintf (stderr, "Event: %s (%d)\n",event_name(event()), event());
}


// This function populates the icon view
// For convinience, it is now also called from other parts of code
// and also calls FileBrowser->load(path) which does the same 
// thing for listview if neccessary

void loaddir(const char *path) {
	// If user clicks too fast, it can cause problems
	if (semaphore) { 
		return;
	}
	semaphore=true;

	// Set current_dir
	if (filename_isdir(path)) {
		if (path[0] == '~') // Expand tilde
			snprintf(current_dir,PATH_MAX,"%s/%s",getenv("HOME"),path+1);
		else 
			strcpy(current_dir,path);
	} else
		strcpy(current_dir,getenv("HOME"));
	// Trailing slash should always be there
	if (current_dir[strlen(current_dir)-1] != '/') strcat(current_dir,"/");
fprintf (stderr, "loaddir(%s) = (%s)\n",path,current_dir);

	// Update directory tree
	dirtree->set_current(current_dir);

	// set window label
	win->label(tasprintf(_("%s - File manager"), current_dir));

	// Update file browser...
	if (fbrowser->visible()) { fbrowser->load(current_dir); semaphore=false; return; }

	// some constants - TODO: move to configuration
	int startx=0, starty=0;
	int sizex=90, sizey=58;
	int spacex=5, spacey=5;

	// variables used later
	Button **icon_array;
	int icon_num=0;
	dirent **files;

	// Clean up window
	sgroup->remove_all();
	sgroup->begin();

	// List all files in directory
	icon_num = fltk::filename_list(current_dir, &files, alphasort); // no sort needed because icons have coordinates
	icon_array = (Button**) malloc (sizeof(Button*) * icon_num + 1);
	// fill array with zeros, for easier detection if button exists
	for (int i=0; i<icon_num; i++) icon_array[i]=0;

	int myx=startx, myy=starty;
	for (int i=0; i<icon_num; i++) {
		char *n = files[i]->d_name; //shortcut

		// don't show ./ (current directory)
		if (strcmp(n,"./")==0) continue;

		// hide files with dot except ../ (up directory)
		if (!showhidden && (n[0] == '.') && (strcmp(n,"../")!=0)) continue;

		// hide files ending with tilde (backup) - NOTE
		if (!showhidden && (n[strlen(n)-1] == '~')) continue;

		Button* o = new Button(myx, myy, sizex, sizey);
		o->box(NO_BOX);
		//o->labeltype(SHADOW_LABEL);
		o->labelcolor(BLACK);
		o->callback((Callback*)button_press);
		o->align(ALIGN_INSIDE|ALIGN_CENTER|ALIGN_WRAP);
		//o->when(WHEN_CHANGED|WHEN_ENTER_KEY);

		o->label(n);
		o->image(Icon::get(DEFAULT_ICON,Icon::SMALL));

		myx=myx+sizex+spacex;
		// 4 - edges
		if (myx+sizex > sgroup->w()) { myx=startx; myy=myy+sizey+spacey; }

		icon_array[i] = o;
	}
	sgroup->end();
	// Give first icon the focus
	sgroup->child(0)->take_focus();

	sgroup->redraw();

	// Init mimetypes
	MimeType *m = new MimeType;

	// Detect icon mimetypes etc.
	for (int i=0; i<icon_num; i++) {
		// ignored files
		if (!icon_array[i]) continue;
		fltk::check(); // update interface

		// get mime data
		char fullpath[PATH_MAX];
		snprintf (fullpath,PATH_MAX-1,"%s%s",current_dir,files[i]->d_name);
		m->set(fullpath);

fprintf(stderr,"Adding: %s (%s), cmd: '%s'\n", fullpath, m->id(), m->command());

		// tooltip
		char *tooltip;
		if (strcmp(m->id(),"directory")==0) 
			asprintf(&tooltip, "%s - %s", files[i]->d_name, m->type_string());
		else 
			asprintf(&tooltip, "%s (%s) - %s", files[i]->d_name, nice_size(filename_size(fullpath)), m->type_string());
		icon_array[i]->tooltip(tooltip);

		// icon
		icon_array[i]->image(m->icon(Icon::SMALL));

		// get command to execute
		if (strcmp(files[i]->d_name,"../")==0) {
			// up directory - we don't want ../ poluting filename
			char exec[PATH_MAX];
			int slashes=0, j;
			for (j=strlen(current_dir); j>0; j--) {
				if (current_dir[j]=='/') slashes++;
				if (slashes==2) break;
			}
			if (slashes<2)
				sprintf(exec,"efiler /");
			else {
				sprintf(exec,"efiler ");
				strncat(exec,current_dir,j);
			}
			icon_array[i]->user_data(strdup(exec));

		} else if (m->command() && (strlen(m->command())>0))
			icon_array[i]->user_data(strdup(m->command()));
		else
			icon_array[i]->user_data(0);

		// make sure label isn't too large
		// TODO: move this to draw() method
		int lx,ly; 
		icon_array[i]->measure_label(lx,ly);
		int pos=strlen(icon_array[i]->label());
		if (pos>252) pos=252;
		char fixlabel[256];
		while (lx>sizex) {
			strncpy(fixlabel,icon_array[i]->label(),pos);
			fixlabel[pos]='\0';
			strcat(fixlabel,"...");
			icon_array[i]->label(strdup(fixlabel));
			icon_array[i]->measure_label(lx,ly);
			pos--;
		}
		icon_array[i]->redraw();
	}
	// MimeType destructor
	delete m;

	sgroup->redraw();
	semaphore=false;
}


/*-----------------------------------------------------------------
	Directory tree

	(only callback, since most of the real work is done in class)
-------------------------------------------------------------------*/

void dirtree_cb(Widget* w, void*) {
	if (!event_clicks() && event_key() != ReturnKey) return;
	char *d = (char*) dirtree->item()->user_data();
	if (d && strlen(d)>0) loaddir(d);
}


/*-----------------------------------------------------------------
	List view

	(only callback, since most of the real work is done in class)
-------------------------------------------------------------------*/

void fbrowser_cb(Widget* w, void*) {
	// Take only proper callbacks
	if (!event_clicks() && event_key() != ReturnKey) return;

	// Construct filename
	const char *c = fbrowser->system_path(fbrowser->value());
	char filename[PATH_MAX];
	if (strncmp(c+strlen(c)-3,"../",3)==0) {
		// User clicked on "..", we go up
		strcpy(filename,current_dir); // both are [PATH_MAX]
		filename[strlen(filename)-1] = '\0'; // remove trailing slash in a directory
		char *c2 = strrchr(filename,'/'); // find previous slash
		if (c2) *(c2+1) = '\0'; // cut everything after this slash
		else strcpy(filename,"/"); // if nothing is found, filename becomes "/"
	} else {
		strncpy(filename,c,PATH_MAX);
	}

	// Change directory
	if (filename_isdir(filename)) 
		loaddir(filename);

	// Let elauncher handle this file...
	else 
		run_program(tsprintf("file:%s",filename),false,false,true);
}



/*-----------------------------------------------------------------
	File moving and copying operations
-------------------------------------------------------------------*/

ProgressBar* cut_copy_progress;
bool stop_now;
bool overwrite_all, skip_all;

// Execute cut or copy operation when List View is active
void do_cut_copy_fbrowser(bool m_copy) {
	// Count selected icons, for malloc
	int num = fbrowser->children();
	int nselected = 0;
	for (int i=0; i<num; i++)
		if (fbrowser->selected(i)) nselected++;

	// Clear cut/copy buffer and optionally ungray the previously cutted icons
	if (cut_copy_buffer) {
		for (int i=0; cut_copy_buffer[i]; i++)
			free(cut_copy_buffer[i]);
		free(cut_copy_buffer);
		if (!operation_is_copy) {
			for (int i=0; i<num; i++)
				fbrowser->child(i)->textcolor(BLACK); // FIXME: use color from style
		}
	}

	// Allocate buffer
	cut_copy_buffer = (char**)malloc(sizeof(char*) * (nselected+2));

	// Add selected files to buffer and optionally grey icons (for cut effect)
	int buf=0;
	for (int i=0; i<=num; i++) {
		if (fbrowser->selected(i)) {
			cut_copy_buffer[buf] = strdup(fbrowser->system_path(i));
			if (!m_copy) fbrowser->child(i)->textcolor(GRAY50);
			buf++;
		}
	}
	cut_copy_buffer[buf] = 0;
	operation_is_copy = m_copy;

	// Deselect all
	fbrowser->deselect();
}

// Execute cut or copy operation when Icon View is active

// (this one will become obsolete when IconBrowser class gets the same API
// as FileBrowser)

void do_cut_copy_sgroup(bool m_copy) {

	// Group doesn't support type(MULTI) so only one item can be selected

	int num = fbrowser->children();

	// Clear cut/copy buffer and optionally ungray the previously cutted icon
	if (cut_copy_buffer) {
		for (int i=0; cut_copy_buffer[i]; i++)
			free(cut_copy_buffer[i]);
		free(cut_copy_buffer);
		if (!operation_is_copy) {
			for (int i=0; i<num; i++)
				sgroup->child(i)->textcolor(BLACK); // FIXME: use color from style
		}
	}

	// Allocate buffer
	cut_copy_buffer = (char**)malloc(sizeof(char*) * 3);

	// Add selected files to buffer and optionally grey icons (for cut effect)
	// FIXME: label doesn't contain filename!!
	asprintf(&cut_copy_buffer[0], "%s%s", current_dir, sgroup->child(sgroup->focus_index())->label());
	if (!m_copy) sgroup->child(sgroup->focus_index())->textcolor(GRAY50);
	cut_copy_buffer[1]=0;
	operation_is_copy=m_copy;
}


// Helper functions for paste:

// Tests if two files are on the same filesystem
bool is_on_same_fs(const char* file1, const char* file2) {
	FILE	*mtab;		// /etc/mtab or /etc/mnttab file
	static char filesystems[50][PATH_MAX];
	static int fs_number=0;

	// On first access read filesystems
	if (fs_number == 0) {
		mtab = fopen("/etc/mnttab", "r");	// Fairly standard
		if (mtab == NULL)
			mtab = fopen("/etc/mtab", "r");	// More standard
		if (mtab == NULL)
			mtab = fopen("/etc/fstab", "r");	// Otherwise fallback to full list
		if (mtab == NULL)
			mtab = fopen("/etc/vfstab", "r");	// Alternate full list file

		char	line[PATH_MAX];	// Input line
		char	device[PATH_MAX], mountpoint[PATH_MAX], fs[PATH_MAX];
		while (mtab!= NULL && fgets(line, sizeof(line), mtab) != NULL) {
			if (line[0] == '#' || line[0] == '\n')
				continue;
			if (sscanf(line, "%s%s%s", device, mountpoint, fs) != 3)
				continue;
			strcpy(filesystems[fs_number],mountpoint);
			fs_number++;
		}	
		fclose (mtab);

		if (fs_number == 0) return false; // some kind of error
	}

	// Find filesystem for file1 (largest mount point match)
	char *max;
	int maxlen = 0;
	for (int i=0; i<fs_number; i++) {
		int mylen = strlen(filesystems[i]);
		if ((strncmp(file1,filesystems[i],mylen)==0) && (mylen>maxlen)) {
			maxlen=mylen;
			max = filesystems[i];
		}
	}
	if (maxlen == 0) return false; // some kind of error

	// See if file2 matches the same filesystem
	return (strncmp(file2,max,maxlen)==0);
}


// Copy single file. Returns true if operation should continue
bool my_copy(const char* src, const char* dest) {
	FILE *fold, *fnew;
	int c;

	if (strcmp(src,dest)==0)
		// this shouldn't happen
		return true;

	if (filename_exist(dest)) {
		// if both src and dest are directories, do nothing
		if (filename_isdir(src) && filename_isdir(dest))
			return true;

		int c = -1;
		if (!overwrite_all && !skip_all) {
			c = choice_alert(tsprintf(_("File already exists: %s. What to do?"), dest), _("&Overwrite"), _("Over&write all"), _("*&Skip"), _("Skip &all"), 0); // asterisk (*) means default
		}
		if (c==1) overwrite_all=true;
		if (c==3) skip_all=true;
		if (c==2 || skip_all) {
			return true;
		}
		// At this point either c==0 (overwrite) or overwrite_all == true

		// copy directory over file
		if (filename_isdir(src))
			unlink(dest);

		// copy file over directory
		// TODO: we will just skip this case, but ideally there should be
		// another warning
		if (filename_isdir(dest))
			return true;
	}

	if (filename_isdir(src)) {
		if (mkdir (dest, umask(0))==0)
			return true; // success
		int q = choice_alert(tsprintf(_("Cannot create directory %s"),dest), _("*&Continue"), _("&Stop"), 0);
		if (q == 0) return true; else return false;
	}

	if ( ( fold = fopen( src, "rb" ) ) == NULL ) {
		int q = choice_alert(tsprintf(_("Cannot read file %s"),src), _("*&Continue"), _("&Stop"), 0);
		if (q == 0) return true; else return false;
	}

	if ( ( fnew = fopen( dest, "wb" ) ) == NULL  )
	{
		fclose ( fold );
		int q = choice_alert(tsprintf(_("Cannot create file %s"),dest), _("*&Continue"), _("&Stop"), 0);
		if (q == 0) return true; else return false;
	}
	
	while (!feof(fold)) {
		c = fgetc(fold);
		fputc(c, fnew);
	}
	// TODO: Add more error handling using ferror()
	fclose(fold);
	fclose(fnew);
	return true;
}


// Recursive function that creates a list of all files to be 
// copied, expanding directories etc. The total number of elements
// will be stored in listsize. Returns false if user decided to
// interrupt copying.
bool create_list(const char* src, char** &list, int &list_size, int &list_capacity) {
	// Grow list if neccessary
	if (list_size >= list_capacity-1) {
		list_capacity += 1000;
		list = (char**)realloc(list, sizeof(char**)*list_capacity);
	}

	// We add both files and diretories to list
	list[list_size++] = strdup(src);

	if (filename_isdir(src)) {
		char new_src[PATH_MAX];
		dirent	**files;
		// FIXME: use same sort as currently used
		// FIXME: detect errors on accessing folder
		int num_files = fltk::filename_list(src, &files, casenumericsort);
		for (int i=0; i<num_files; i++) {
			if (strcmp(files[i]->d_name,"./")==0 || strcmp(files[i]->d_name,"../")==0) continue;
			snprintf(new_src, PATH_MAX, "%s%s", src, files[i]->d_name);
			fltk::check(); // update gui
			if (stop_now || !create_list(new_src, list, list_size, list_capacity))
				return false;
		}
	}
	return true;
}


// Callback for Stop button on progress window
void stop_copying_cb(Widget*,void* v) {
	stop_now=true;
	// Let's inform user that we're stopping...
	InvisibleBox* caption = (InvisibleBox*)v;
	caption->label(_("Stopping..."));
	caption->redraw();
	caption->parent()->redraw();
}

// Execute paste operation - this will copy or move files based on last 
// operation
void do_paste() {

	if (!cut_copy_buffer || !cut_copy_buffer[0]) return;

	overwrite_all=false; skip_all=false;

	// Moving files on same filesystem is trivial
	// We don't even need a progress bar
	if (!operation_is_copy && is_on_same_fs(current_dir, cut_copy_buffer[0])) {
		for (int i=0; cut_copy_buffer[i]; i++) {
			char *newname;
			asprintf(&newname, "%s%s", current_dir, filename_name(cut_copy_buffer[i]));
			if (filename_exist(newname)) {
				int c = -1;
				if (!overwrite_all && !skip_all) {
					c = choice_alert(tsprintf(_("File already exists: %s. What to do?"), newname), _("&Overwrite"), _("Over&write all"), _("*&Skip"), _("Skip &all")); // * means default
				}
				if (c==1) overwrite_all=true;
				if (c==3) skip_all=true;
				if (c==2 || skip_all) {
					free(cut_copy_buffer[i]);
					continue; // go to next entry
				}
				// At this point c==0 (Overwrite) or overwrite_all == true
				unlink(newname);
			} 
			rename(cut_copy_buffer[i],newname);
			free(cut_copy_buffer[i]);
		}
		free(cut_copy_buffer);
		cut_copy_buffer=0;
		loaddir(current_dir); // Update display
		return;

	//
	// Real file moving / copying using recursive algorithm
	//

	} else {
		stop_now = false;

		// Create srcdir string
		char *srcdir = strdup(cut_copy_buffer[0]);
		char *p = strrchr(srcdir,'/');
		if (*(p+1) == '\0') { // slash is last - find one before
			*p = '\0';
			p = strrchr(srcdir,'/');
		}
		*(p+1) = '\0';

		if (strcmp(srcdir,current_dir)==0) {
			alert(_("You cannot copy a file onto itself!"));
			return;
		}

		// Draw progress dialog
		Window* progress_window = new Window(350,150);
		if (operation_is_copy)
			progress_window->label(_("Copying files"));
		else
			progress_window->label(_("Moving files"));
		progress_window->set_modal();
		progress_window->begin();
		InvisibleBox* caption = new InvisibleBox(20,20,310,25, _("Counting files in directories"));
		caption->align(ALIGN_LEFT|ALIGN_INSIDE);
		cut_copy_progress = new ProgressBar(20,60,310,20);
		Button* stop_button = new Button(145,100,60,40, _("&Stop"));
		stop_button->callback(stop_copying_cb,caption);
		progress_window->end();
		progress_window->show();

		// How many items do we copy?
		int copy_items=0;
		for (; cut_copy_buffer[copy_items]; copy_items++);
		// Set ProgressBar range accordingly
		cut_copy_progress->range(0,copy_items,1);
		cut_copy_progress->position(0);

		// Count files in directories
		int list_size = 0, list_capacity = 1000;
		char** files_list = (char**)malloc(sizeof(char**)*list_capacity);
		for (int i=0; i<copy_items; i++) {
			// We must ensure that cut_copy_buffer is deallocated
			// even if user clicked on Stop
			if (!stop_now) create_list(cut_copy_buffer[i], files_list, list_size, list_capacity);
			free(cut_copy_buffer[i]);
			cut_copy_progress->position(i+1);
			fltk::check(); // check to see if user pressed Stop
		}
		free (cut_copy_buffer);
		cut_copy_buffer=0;

		// Now copying those files
		if (!stop_now) {
			char label[150];
			char dest[PATH_MAX];
			cut_copy_progress->range(0, list_size, 1);
			cut_copy_progress->position(0);

			for (int i=0; i<list_size; i++) {
				// Prepare dest filename
				char *srcfile = files_list[i] + strlen(srcdir);
				snprintf (dest, PATH_MAX, "%s%s", current_dir, srcfile);

				snprintf(label, 150, _("Copying %d of %d files to %s"), i, list_size, current_dir);
				caption->label(label);
				caption->redraw();
				if (stop_now || !my_copy(files_list[i], dest))
					break;
				cut_copy_progress->position(cut_copy_progress->position()+1);
				fltk::check(); // check to see if user pressed Stop
			}
		}
		progress_window->hide();

		// Deallocate files_list[][]
		for (int i=0; i<list_size; i++) 
			free(files_list[i]);
		free(files_list);

		// Reload current dir
		loaddir(current_dir);
	}
}



/*-----------------------------------------------------------------
	Main menu callbacks
-------------------------------------------------------------------*/

// File menu callbacks

void open_cb(Widget*, void*) {
	Widget* w;
	if (sgroup->visible())
		w = sgroup->child(sgroup->focus_index());
	else
		w = fbrowser;
	event_clicks(2);
	w->do_callback();
}
void location_cb(Widget*, void*) {
	const char *dir = dir_chooser(_("Choose location"),current_dir);
	if (dir) loaddir(dir);
}
void quit_cb(Widget*, void*) {exit(0);}


// Edit menu callbacks

void cut_cb(Widget*, void*) {
	if (sgroup->visible()) 
		do_cut_copy_sgroup(false);
	else
		do_cut_copy_fbrowser(false);
}

void copy_cb(Widget*, void*) {
	if (sgroup->visible()) 
		do_cut_copy_sgroup(true);
	else
		do_cut_copy_fbrowser(true);
}

void paste_cb(Widget*, void*) {
	do_paste();
}


// View menu

void switchview() {
	if (sgroup->visible()) {
		sgroup->hide(); 
		fbrowser->show(); 
		fbrowser->take_focus();
	} else {
		sgroup->show(); 
		fbrowser->hide(); 
		sgroup->take_focus();
	}
	// We update the inactive view only when it's shown i.e. now
	loaddir(current_dir);
}

void iconsview_cb(Widget*,void*) {
	// When user presses F8 we switch view regardles of which is visible
	// However, when menu option is chosen we only switch *to* iconview
	if (fbrowser->visible() || event_key() == F8Key) switchview();
}
void listview_cb(Widget*,void*) { if (sgroup->visible()) switchview(); }

void showhidden_cb(Widget* w, void*) {
	// Presently, fbrowser has show_hidden() method while icon view
	// respects value of showhidden global variable

	Item *i = (Item*)w;
	if (showhidden) {
		showhidden=false;
		i->clear();
	} else {
		showhidden=true;
		i->set();
	}
	if (fbrowser->visible()) fbrowser->show_hidden(showhidden);
	// Reload current view
	loaddir(current_dir);
}

void showtree_cb(Widget*,void*) {
	if (!showtree) {
		tile->position(1,0,150,0);
		showtree=true;
	} else {
		tile->position(150,0,0,0);
		showtree=false;
	}
}
void refresh_cb(Widget*,void*) {
	loaddir(current_dir);
	// TODO: reload directory tree as well-
}
void case_cb(Widget*,void*) {
	fprintf(stderr,"Not implemented yet...\n");
}


// Help menu

void about_cb(Widget*, void*) { about_dialog("EFiler", "0.1", _("EDE File Manager"));}



/*-----------------------------------------------------------------
	GUI design
-------------------------------------------------------------------*/


int main (int argc, char **argv) {
	win = new fltk::Window(600, 400);
	win->color(WHITE);
	win->begin();

	// Main menu
	{MenuBar *m = new MenuBar(0, 0, 600, 25);
		m->begin();
		{ItemGroup *o = new ItemGroup(_("&File"));
			o->begin();
			{Item *o = new Item(_("&Open"));
				o->callback(open_cb);
				o->shortcut(CTRL+'o');
			}
			{Item *o = new Item(_("Open &with..."));
				//o->callback(open_cb);
				//o->shortcut(CTRL+'o');
			}
			new Divider();
			{Item *o = new Item(_("Open &location"));
				o->callback(location_cb);
				//o->shortcut(CTRL+'o');
			}
			new Divider();
			{Item *o = new Item(_("&Quit"));
				o->callback(quit_cb);
				o->shortcut(CTRL+'q');
			}
			o->end();
		}
		{ItemGroup *o = new ItemGroup(_("&Edit"));
			o->begin();
			{Item *o = new Item(_("&Cut"));
				o->callback(cut_cb);
				o->shortcut(CTRL+'x');
			}
			{Item *o = new Item(_("C&opy"));
				o->callback(copy_cb);
				o->shortcut(CTRL+'c');
			}
			{Item *o = new Item(_("&Paste"));
				o->callback(paste_cb);
				o->shortcut(CTRL+'v');
			}
			{Item *o = new Item(_("&Rename"));
				//o->callback(open_cb);
				o->shortcut(F2Key);
			}
			{Item *o = new Item(_("&Delete"));
				//o->callback(open_cb);
				o->shortcut(DeleteKey);
			}
			new Divider();
			{Item *o = new Item(_("&Preferences..."));
				o->shortcut(CTRL+'p');
			}
			o->end();
		}
		{ItemGroup *o = new ItemGroup(_("&View"));
			o->begin();
			{Item *o = new Item(_("&Icons"));
				o->type(Item::RADIO);
				o->shortcut(F8Key);
				o->set();
				o->callback(iconsview_cb);
			}
			{Item *o = new Item(_("&Detailed List"));
				o->type(Item::RADIO);
				o->callback(listview_cb);
			}
			new Divider();
			{Item *o = new Item(_("&Show hidden"));
				o->type(Item::TOGGLE);
				o->callback(showhidden_cb);
			}
			{Item *o = new Item(_("Directory &Tree"));
				o->type(Item::TOGGLE);
				o->shortcut(F9Key);
				o->callback(showtree_cb);
			}
			new Divider();
			{Item *o = new Item(_("&Refresh"));
				//o->type();
				o->callback(refresh_cb);
				o->shortcut(F5Key);
			}
			{ItemGroup *o = new ItemGroup(_("S&ort"));
				o->begin();
				{Item *o = new Item(_("&Case sensitive"));
					//o->type();
					o->callback(case_cb);
				}
				o->end();
			}
			o->end();
		}
		{ItemGroup *o = new ItemGroup(_("&Help"));
			o->begin();
			{Item *o = new Item(_("&About File Manager"));
				o->shortcut();
				o->callback(about_cb);
			}
			o->end();
		}
		m->end();
	}

	// Main tiled group
	{tile = new TiledGroup(0, 25, 600, 375);
		tile->color(WHITE);
		tile->begin();

		// Directory tree
		{dirtree = new DirTree(0, 0, 150, 375);
			dirtree->box(DOWN_BOX);
			dirtree->color(WHITE);
			dirtree->load();
			dirtree->callback(dirtree_cb);
			dirtree->when(WHEN_CHANGED|WHEN_ENTER_KEY);
		}

		// Icon view
		{sgroup = new ScrollGroup(150, 0, 450, 375);
			sgroup->box(DOWN_BOX);
			sgroup->color(WHITE);
	//		sgroup->highlight_color(WHITE);
	//		sgroup->selection_color(WHITE);
			sgroup->align(ALIGN_LEFT|ALIGN_TOP);
	//		g->label("There are no files in current directory");
		}
	
		// List view
		{fbrowser = new FileBrowser(150, 0, 450, 375);
			fbrowser->box(DOWN_BOX);
			fbrowser->color(WHITE);
			fbrowser->callback(fbrowser_cb);
	//		sgroup->align(ALIGN_LEFT|ALIGN_TOP);
	//		g->label("There are no files in current directory");
			fbrowser->when(WHEN_ENTER_KEY);
			//fbrowser->labelsize(12);
			fbrowser->type(Browser::MULTI);
			fbrowser->hide();
		}
		tile->end();
	}

	// We hide dirtree and browser expands to fill space
	tile->position(150,0,1,0);

	win->end();
	win->resizable(tile);
	win->icon(Icon::get("folder",Icon::TINY));
	win->show();

	if (argc==1) { // No params
		loaddir ("");
	} else {
		loaddir (argv[1]);
	}

	return fltk::run();
}
