
#include "WINGsP.h"
#include "wconfig.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <limits.h>
#include <errno.h>
#include <stdint.h>

#ifndef PATH_MAX
#define PATH_MAX 1024
#endif

typedef struct W_FilePanel {
	WMWindow *win;

	WMLabel *iconLabel;
	WMLabel *titleLabel;

	WMFrame *line;

	WMLabel *nameLabel;
	WMBrowser *browser;

	WMButton *okButton;
	WMButton *cancelButton;

	WMButton *homeButton;
	WMButton *trashcanButton;
	WMButton *createDirButton;
	WMButton *disketteButton;
	WMButton *unmountButton;

	WMView *accessoryView;

	WMTextField *fileField;

	char **fileTypes;

	struct {
		unsigned int canExit:1;
		unsigned int canceled:1;	/* clicked on cancel */
		unsigned int filtered:1;
		unsigned int canChooseFiles:1;
		unsigned int canChooseDirectories:1;
		unsigned int autoCompletion:1;
		unsigned int showAllFiles:1;
		unsigned int canFreeFileTypes:1;
		unsigned int fileMustExist:1;
		unsigned int panelType:1;
	} flags;
} W_FilePanel;

/* Type of panel */
#define WP_OPEN         0
#define WP_SAVE         1

#define PWIDTH		330
#define PHEIGHT 	360

static void listDirectoryOnColumn(WMFilePanel * panel, int column, char *path);
static void browserClick();
static void browserDClick();

static void fillColumn(WMBrowserDelegate * self, WMBrowser * bPtr, int column, WMList * list);

static void deleteFile();

static void createDir();

static void goHome();

static void goFloppy();

static void goUnmount();

static void buttonClick();

static char *getCurrentFileName(WMFilePanel * panel);

static void handleEvents(XEvent * event, void *data);

static WMBrowserDelegate browserDelegate = {
	NULL,			/* data */
	fillColumn,		/* createRowsForColumn */
	NULL,			/* titleOfColumn */
	NULL,			/* didScroll */
	NULL			/* willScroll */
};

static int closestListItem(WMList * list, char *text, Bool exact)
{
	WMListItem *item;
	WMArray *items = WMGetListItems(list);
	int i, len = strlen(text);

	if (len == 0)
		return -1;

	for (i = 0; i < WMGetArrayItemCount(items); i++) {
		item = WMGetFromArray(items, i);
		if (strlen(item->text) >= len &&
		    ((exact && strcmp(item->text, text) == 0) ||
		     (!exact && strncmp(item->text, text, len) == 0))) {
			return i;
		}
	}

	return -1;
}

static void textChangedObserver(void *observerData, WMNotification * notification)
{
	W_FilePanel *panel = (W_FilePanel *) observerData;
	char *text;
	WMList *list;
	int col = WMGetBrowserNumberOfColumns(panel->browser) - 1;
	int i;
	uintptr_t textEvent;

	if (!(list = WMGetBrowserListInColumn(panel->browser, col)))
		return;

	text = WMGetTextFieldText(panel->fileField);
	textEvent = (uintptr_t)WMGetNotificationClientData(notification);

	if (panel->flags.autoCompletion && textEvent != WMDeleteTextEvent)
		i = closestListItem(list, text, False);
	else
		i = closestListItem(list, text, True);

	WMSelectListItem(list, i);
	if (i >= 0 && panel->flags.autoCompletion) {
		WMListItem *item = WMGetListItem(list, i);
		int textLen = strlen(text), itemTextLen = strlen(item->text);
		int visibleItems = WMWidgetHeight(list) / WMGetListItemHeight(list);

		WMSetListPosition(list, i - visibleItems / 2);

		if (textEvent != WMDeleteTextEvent) {
			WMRange range;

			WMInsertTextFieldText(panel->fileField, &item->text[textLen], textLen);
			range.position = textLen;
			range.count = itemTextLen - textLen;
			WMSelectTextFieldRange(panel->fileField, range);
			/*WMSetTextFieldCursorPosition(panel->fileField, itemTextLen); */
		}
	}

	wfree(text);
}

static void textEditedObserver(void *observerData, WMNotification * notification)
{
	W_FilePanel *panel = (W_FilePanel *) observerData;

	if ((uintptr_t)WMGetNotificationClientData(notification) == WMReturnTextMovement) {
		WMPerformButtonClick(panel->okButton);
	}
}

static WMFilePanel *makeFilePanel(WMScreen * scrPtr, char *name, char *title)
{
	WMFilePanel *fPtr;
	WMFont *largeFont;
	WMPixmap *icon;

	fPtr = wmalloc(sizeof(WMFilePanel));
	memset(fPtr, 0, sizeof(WMFilePanel));

	fPtr->win = WMCreateWindowWithStyle(scrPtr, name, WMTitledWindowMask | WMResizableWindowMask);
	WMResizeWidget(fPtr->win, PWIDTH, PHEIGHT);
	WMSetWindowTitle(fPtr->win, "");

	WMCreateEventHandler(WMWidgetView(fPtr->win), StructureNotifyMask, handleEvents, fPtr);
	WMSetWindowMinSize(fPtr->win, PWIDTH, PHEIGHT);

	fPtr->iconLabel = WMCreateLabel(fPtr->win);
	WMResizeWidget(fPtr->iconLabel, 64, 64);
	WMMoveWidget(fPtr->iconLabel, 0, 0);
	WMSetLabelImagePosition(fPtr->iconLabel, WIPImageOnly);
	icon = WMCreateApplicationIconBlendedPixmap(scrPtr, (RColor *) NULL);
	if (icon) {
		WMSetLabelImage(fPtr->iconLabel, icon);
		WMReleasePixmap(icon);
	} else {
		WMSetLabelImage(fPtr->iconLabel, scrPtr->applicationIconPixmap);
	}

	fPtr->titleLabel = WMCreateLabel(fPtr->win);
	WMResizeWidget(fPtr->titleLabel, PWIDTH - 64, 64);
	WMMoveWidget(fPtr->titleLabel, 64, 0);
	largeFont = WMBoldSystemFontOfSize(scrPtr, 24);
	WMSetLabelFont(fPtr->titleLabel, largeFont);
	WMReleaseFont(largeFont);
	WMSetLabelText(fPtr->titleLabel, title);

	fPtr->line = WMCreateFrame(fPtr->win);
	WMMoveWidget(fPtr->line, 0, 64);
	WMResizeWidget(fPtr->line, PWIDTH, 2);
	WMSetFrameRelief(fPtr->line, WRGroove);

	fPtr->browser = WMCreateBrowser(fPtr->win);
	WMSetBrowserAllowEmptySelection(fPtr->browser, True);
	WMSetBrowserDelegate(fPtr->browser, &browserDelegate);
	WMSetBrowserAction(fPtr->browser, browserClick, fPtr);
	WMSetBrowserDoubleAction(fPtr->browser, browserDClick, fPtr);
	WMMoveWidget(fPtr->browser, 7, 72);
	WMResizeWidget(fPtr->browser, PWIDTH - 14, 200);
	WMHangData(fPtr->browser, fPtr);

	fPtr->nameLabel = WMCreateLabel(fPtr->win);
	WMMoveWidget(fPtr->nameLabel, 7, 282);
	WMResizeWidget(fPtr->nameLabel, 55, 14);
	WMSetLabelText(fPtr->nameLabel, _("Name:"));

	fPtr->fileField = WMCreateTextField(fPtr->win);
	WMMoveWidget(fPtr->fileField, 60, 278);
	WMResizeWidget(fPtr->fileField, PWIDTH - 60 - 10, 24);
	WMAddNotificationObserver(textEditedObserver, fPtr, WMTextDidEndEditingNotification, fPtr->fileField);
	WMAddNotificationObserver(textChangedObserver, fPtr, WMTextDidChangeNotification, fPtr->fileField);

	fPtr->okButton = WMCreateCommandButton(fPtr->win);
	WMMoveWidget(fPtr->okButton, 245, 325);
	WMResizeWidget(fPtr->okButton, 75, 28);
	WMSetButtonText(fPtr->okButton, _("OK"));
	WMSetButtonImage(fPtr->okButton, scrPtr->buttonArrow);
	WMSetButtonAltImage(fPtr->okButton, scrPtr->pushedButtonArrow);
	WMSetButtonImagePosition(fPtr->okButton, WIPRight);
	WMSetButtonAction(fPtr->okButton, buttonClick, fPtr);

	fPtr->cancelButton = WMCreateCommandButton(fPtr->win);
	WMMoveWidget(fPtr->cancelButton, 165, 325);
	WMResizeWidget(fPtr->cancelButton, 75, 28);
	WMSetButtonText(fPtr->cancelButton, _("Cancel"));
	WMSetButtonAction(fPtr->cancelButton, buttonClick, fPtr);

	fPtr->trashcanButton = WMCreateCommandButton(fPtr->win);
	WMMoveWidget(fPtr->trashcanButton, 7, 325);
	WMResizeWidget(fPtr->trashcanButton, 28, 28);
	WMSetButtonImagePosition(fPtr->trashcanButton, WIPImageOnly);
	WMSetButtonImage(fPtr->trashcanButton, scrPtr->trashcanIcon);
	WMSetButtonAltImage(fPtr->trashcanButton, scrPtr->altTrashcanIcon);
	WMSetButtonAction(fPtr->trashcanButton, deleteFile, fPtr);

	fPtr->createDirButton = WMCreateCommandButton(fPtr->win);
	WMMoveWidget(fPtr->createDirButton, 37, 325);
	WMResizeWidget(fPtr->createDirButton, 28, 28);
	WMSetButtonImagePosition(fPtr->createDirButton, WIPImageOnly);
	WMSetButtonImage(fPtr->createDirButton, scrPtr->createDirIcon);
	WMSetButtonAltImage(fPtr->createDirButton, scrPtr->altCreateDirIcon);
	WMSetButtonAction(fPtr->createDirButton, createDir, fPtr);

	fPtr->homeButton = WMCreateCommandButton(fPtr->win);
	WMMoveWidget(fPtr->homeButton, 67, 325);
	WMResizeWidget(fPtr->homeButton, 28, 28);
	WMSetButtonImagePosition(fPtr->homeButton, WIPImageOnly);
	WMSetButtonImage(fPtr->homeButton, scrPtr->homeIcon);
	WMSetButtonAltImage(fPtr->homeButton, scrPtr->altHomeIcon);
	WMSetButtonAction(fPtr->homeButton, goHome, fPtr);

	fPtr->disketteButton = WMCreateCommandButton(fPtr->win);
	WMMoveWidget(fPtr->disketteButton, 97, 325);
	WMResizeWidget(fPtr->disketteButton, 28, 28);
	WMSetButtonImagePosition(fPtr->disketteButton, WIPImageOnly);
	WMSetButtonImage(fPtr->disketteButton, scrPtr->disketteIcon);
	WMSetButtonAltImage(fPtr->disketteButton, scrPtr->altDisketteIcon);
	WMSetButtonAction(fPtr->disketteButton, goFloppy, fPtr);

	fPtr->unmountButton = WMCreateCommandButton(fPtr->win);
	WMMoveWidget(fPtr->unmountButton, 127, 325);
	WMResizeWidget(fPtr->unmountButton, 28, 28);
	WMSetButtonImagePosition(fPtr->unmountButton, WIPImageOnly);
	WMSetButtonImage(fPtr->unmountButton, scrPtr->unmountIcon);
	WMSetButtonAltImage(fPtr->unmountButton, scrPtr->altUnmountIcon);
	WMSetButtonAction(fPtr->unmountButton, goUnmount, fPtr);
	WMSetButtonEnabled(fPtr->unmountButton, False);

	WMRealizeWidget(fPtr->win);
	WMMapSubwidgets(fPtr->win);

	WMSetFocusToWidget(fPtr->fileField);
	WMSetTextFieldCursorPosition(fPtr->fileField, 0);

	WMLoadBrowserColumnZero(fPtr->browser);

	WMSetWindowInitialPosition(fPtr->win,
				   (scrPtr->rootView->size.width - WMWidgetWidth(fPtr->win)) / 2,
				   (scrPtr->rootView->size.height - WMWidgetHeight(fPtr->win)) / 2);

	fPtr->flags.canChooseFiles = 1;
	fPtr->flags.canChooseDirectories = 1;
	fPtr->flags.autoCompletion = 1;

	return fPtr;
}

WMOpenPanel *WMGetOpenPanel(WMScreen * scrPtr)
{
	WMFilePanel *panel;

	if (scrPtr->sharedOpenPanel)
		return scrPtr->sharedOpenPanel;

	panel = makeFilePanel(scrPtr, "openFilePanel", _("Open"));
	panel->flags.fileMustExist = 1;
	panel->flags.panelType = WP_OPEN;

	scrPtr->sharedOpenPanel = panel;

	return panel;
}

WMSavePanel *WMGetSavePanel(WMScreen * scrPtr)
{
	WMFilePanel *panel;

	if (scrPtr->sharedSavePanel)
		return scrPtr->sharedSavePanel;

	panel = makeFilePanel(scrPtr, "saveFilePanel", _("Save"));
	panel->flags.fileMustExist = 0;
	panel->flags.panelType = WP_SAVE;

	scrPtr->sharedSavePanel = panel;

	return panel;
}

void WMFreeFilePanel(WMFilePanel * panel)
{
	if (panel == WMWidgetScreen(panel->win)->sharedSavePanel) {
		WMWidgetScreen(panel->win)->sharedSavePanel = NULL;
	}
	if (panel == WMWidgetScreen(panel->win)->sharedOpenPanel) {
		WMWidgetScreen(panel->win)->sharedOpenPanel = NULL;
	}
	WMRemoveNotificationObserver(panel);
	WMUnmapWidget(panel->win);
	WMDestroyWidget(panel->win);
	wfree(panel);
}

int
WMRunModalFilePanelForDirectory(WMFilePanel * panel, WMWindow * owner, char *path, char *name, char **fileTypes)
{
	WMScreen *scr = WMWidgetScreen(panel->win);

	if (name && !owner) {
		WMSetWindowTitle(panel->win, name);
	}

	WMChangePanelOwner(panel->win, owner);

	WMSetFilePanelDirectory(panel, path);

	switch (panel->flags.panelType) {
	case WP_OPEN:
		if (fileTypes)
			panel->flags.filtered = 1;
		panel->fileTypes = fileTypes;
		if (name == NULL)
			name = _("Open");
		break;
	case WP_SAVE:
		panel->fileTypes = NULL;
		panel->flags.filtered = 0;
		if (name == NULL)
			name = _("Save");
		break;
	default:
		break;
	}

	WMSetLabelText(panel->titleLabel, name);

	WMMapWidget(panel->win);

	WMRunModalLoop(scr, W_VIEW(panel->win));

	/* Must withdraw window because the next time we map
	 * it, it might have a different transient owner.
	 */
	WMCloseWindow(panel->win);

	return (panel->flags.canceled ? False : True);
}

void WMSetFilePanelDirectory(WMFilePanel * panel, char *path)
{
	WMList *list;
	WMListItem *item;
	int col;
	char *rest;

	rest = WMSetBrowserPath(panel->browser, path);
	if (strcmp(path, "/") == 0)
		rest = NULL;

	col = WMGetBrowserSelectedColumn(panel->browser);
	list = WMGetBrowserListInColumn(panel->browser, col);
	if (list && (item = WMGetListSelectedItem(list))) {
		if (item->isBranch) {
			WMSetTextFieldText(panel->fileField, rest);
		} else {
			WMSetTextFieldText(panel->fileField, item->text);
		}
	} else {
		WMSetTextFieldText(panel->fileField, rest);
	}
}

void WMSetFilePanelCanChooseDirectories(WMFilePanel * panel, Bool flag)
{
	panel->flags.canChooseDirectories = ((flag == 0) ? 0 : 1);
}

void WMSetFilePanelCanChooseFiles(WMFilePanel * panel, Bool flag)
{
	panel->flags.canChooseFiles = ((flag == 0) ? 0 : 1);
}

void WMSetFilePanelAutoCompletion(WMFilePanel * panel, Bool flag)
{
	panel->flags.autoCompletion = ((flag == 0) ? 0 : 1);
}

char *WMGetFilePanelFileName(WMFilePanel * panel)
{
	return getCurrentFileName(panel);
}

void WMSetFilePanelAccessoryView(WMFilePanel * panel, WMView * view)
{
	WMView *v;

	panel->accessoryView = view;

	v = WMWidgetView(panel->win);

	W_ReparentView(view, v, 0, 0);

	W_MoveView(view, (v->size.width - v->size.width) / 2, 300);
}

WMView *WMGetFilePanelAccessoryView(WMFilePanel * panel)
{
	return panel->accessoryView;
}

static char *get_name_from_path(char *path)
{
	int size;

	assert(path != NULL);

	size = strlen(path);

	/* remove trailing / */
	while (size > 0 && path[size - 1] == '/')
		size--;
	/* directory was root */
	if (size == 0)
		return wstrdup("/");

	while (size > 0 && path[size - 1] != '/')
		size--;

	return wstrdup(&(path[size]));
}

static int filterFileName(WMFilePanel * panel, char *file, Bool isDirectory)
{
	return True;
}

#define CAST(item) (*((WMListItem**)item))
static int comparer(const void *a, const void *b)
{
	if (CAST(a)->isBranch == CAST(b)->isBranch)
		return (strcmp(CAST(a)->text, CAST(b)->text));
	if (CAST(a)->isBranch)
		return (-1);
	return (1);
}

#undef CAST

static void listDirectoryOnColumn(WMFilePanel * panel, int column, char *path)
{
	WMBrowser *bPtr = panel->browser;
	struct dirent *dentry;
	DIR *dir;
	struct stat stat_buf;
	char pbuf[PATH_MAX + 16];
	char *name;

	assert(column >= 0);
	assert(path != NULL);

	/* put directory name in the title */
	name = get_name_from_path(path);
	WMSetBrowserColumnTitle(bPtr, column, name);
	wfree(name);

	dir = opendir(path);

	if (!dir) {
#ifdef VERBOSE
		printf(_("WINGs: could not open directory %s\n"), path);
#endif
		return;
	}

	/* list contents in the column */
	while ((dentry = readdir(dir))) {
		if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
			continue;

		strcpy(pbuf, path);
		if (strcmp(path, "/") != 0)
			strcat(pbuf, "/");
		strcat(pbuf, dentry->d_name);

		if (stat(pbuf, &stat_buf) != 0) {
#ifdef VERBOSE
			printf(_("WINGs: could not stat %s\n"), pbuf);
#endif
			continue;
		} else {
			int isDirectory;

			isDirectory = S_ISDIR(stat_buf.st_mode);

			if (filterFileName(panel, dentry->d_name, isDirectory))
				WMInsertBrowserItem(bPtr, column, -1, dentry->d_name, isDirectory);
		}
	}
	WMSortBrowserColumnWithComparer(bPtr, column, comparer);

	closedir(dir);
}

static void fillColumn(WMBrowserDelegate * self, WMBrowser * bPtr, int column, WMList * list)
{
	char *path;
	WMFilePanel *panel;

	if (column > 0) {
		path = WMGetBrowserPathToColumn(bPtr, column - 1);
	} else {
		path = wstrdup("/");
	}

	panel = WMGetHangedData(bPtr);
	listDirectoryOnColumn(panel, column, path);
	wfree(path);
}

static void browserDClick(WMBrowser * bPtr, WMFilePanel * panel)
{
	WMPerformButtonClick(panel->okButton);
}

static void browserClick(WMBrowser * bPtr, WMFilePanel * panel)
{
	int col = WMGetBrowserSelectedColumn(bPtr);
	WMListItem *item = WMGetBrowserSelectedItemInColumn(bPtr, col);

	if (!item || item->isBranch)
		WMSetTextFieldText(panel->fileField, NULL);
	else {
		WMSetTextFieldText(panel->fileField, item->text);
	}
}

static void showError(WMScreen * scr, WMWindow * owner, char *s, char *file)
{
	char *errStr;

	if (file) {
		errStr = wmalloc(strlen(file) + strlen(s));
		sprintf(errStr, s, file);
	} else {
		errStr = wstrdup(s);
	}
	WMRunAlertPanel(scr, owner, _("Error"), errStr, _("OK"), NULL, NULL);
	wfree(errStr);
}

static void createDir(WMButton * bPre, WMFilePanel * panel)
{
	char *dirName, *directory, *file, *s;
	WMScreen *scr = WMWidgetScreen(panel->win);

	dirName = WMRunInputPanel(scr, panel->win, _("Create Directory"),
				  _("Enter directory name"), "", _("OK"), _("Cancel"));
	if (!dirName)
		return;

	directory = getCurrentFileName(panel);
	s = strrchr(directory, '/');
	if (s)
		s[1] = 0;

	if (dirName[0] == '/') {
		directory[0] = 0;
	} else {
		while ((s = strstr(directory, "//"))) {
			int i;
			for (i = 2; s[i] == '/'; i++) ;
			strcpy(s, &s[i - 1]);
		}
		if ((s = strrchr(directory, '/')) && !s[1])
			s[0] = 0;
	}
	while ((s = strstr(dirName, "//"))) {
		int i;
		for (i = 2; s[i] == '/'; i++) ;
		strcpy(s, &s[i - 1]);
	}
	if ((s = strrchr(dirName, '/')) && !s[1])
		s[0] = 0;

	file = wmalloc(strlen(dirName) + strlen(directory) + 4);
	sprintf(file, "%s/%s", directory, dirName);
	while ((s = strstr(file, "//"))) {
		int i;
		for (i = 2; s[i] == '/'; i++) ;
		strcpy(s, &s[i - 1]);
	}

	if (mkdir(file, 0xfff) != 0) {
		switch (errno) {
		case EACCES:
			showError(scr, panel->win, _("Permission denied."), NULL);
			break;
		case EEXIST:
			showError(scr, panel->win, _("'%s' already exists."), file);
			break;
		case ENOENT:
			showError(scr, panel->win, _("Path does not exist."), NULL);
		}
	} else
		WMSetFilePanelDirectory(panel, file);

	wfree(dirName);
	wfree(directory);
	wfree(file);
}

static void deleteFile(WMButton * bPre, WMFilePanel * panel)
{
	char *file;
	char *buffer, *s;
	struct stat filestat;
	WMScreen *scr = WMWidgetScreen(panel->win);

	file = getCurrentFileName(panel);

	while ((s = strstr(file, "//"))) {
		int i;
		for (i = 2; s[i] == '/'; i++) ;
		strcpy(s, &s[i - 1]);
	}
	if (strlen(file) > 1 && (s = strrchr(file, '/')) && !s[1])
		s[0] = 0;

	if (stat(file, &filestat)) {
		switch (errno) {
		case ENOENT:
			showError(scr, panel->win, _("'%s' does not exist."), file);
			break;
		case EACCES:
			showError(scr, panel->win, _("Permission denied."), NULL);
			break;
		case ENOMEM:
			showError(scr, panel->win, _("Insufficient memory available."), NULL);
			break;
		case EROFS:
			showError(scr, panel->win, _("'%s' is on a read-only filesystem."), file);
			break;
		default:
			showError(scr, panel->win, _("Can not delete '%s'."), file);
		}
		wfree(file);
		return;
	} else if (S_ISDIR(filestat.st_mode)) {
		int len = strlen(file) + 20;
		buffer = wmalloc(len);
		snprintf(buffer, len, _("Delete directory %s ?"), file);
	} else {
		int len = strlen(file) + 15;
		buffer = wmalloc(len);
		snprintf(buffer, len, _("Delete file %s ?"), file);
	}

	if (!WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
			     _("Warning"), buffer, _("OK"), _("Cancel"), NULL)) {
		if (S_ISDIR(filestat.st_mode)) {
			if (rmdir(file) != 0) {
				switch (errno) {
				case EACCES:
					showError(scr, panel->win, _("Permission denied."), NULL);
					break;
				case ENOENT:
					showError(scr, panel->win, _("Directory '%s' does not exist."), file);
					break;
				case ENOTEMPTY:
					showError(scr, panel->win, _("Directory '%s' is not empty."), file);
					break;
				case EBUSY:
					showError(scr, panel->win, _("Directory '%s' is busy."), file);
					break;
				default:
					showError(scr, panel->win, _("Can not delete '%s'."), file);
				}
			} else {
				char *s = strrchr(file, '/');
				if (s)
					s[0] = 0;
				WMSetFilePanelDirectory(panel, file);
			}
		} else if (remove(file) != 0) {
			switch (errno) {
			case EISDIR:
				showError(scr, panel->win, _("'%s' is a directory."), file);
				break;
			case ENOENT:
				showError(scr, panel->win, _("'%s' does not exist."), file);
				break;
			case EACCES:
				showError(scr, panel->win, _("Permission denied."), NULL);
				break;
			case ENOMEM:
				showError(scr, panel->win, _("Insufficient memory available."), NULL);
				break;
			case EROFS:
				showError(scr, panel->win, _("'%s' is on a read-only filesystem."), file);
				break;
			default:
				showError(scr, panel->win, _("Can not delete '%s'."), file);
			}
		} else {
			char *s = strrchr(file, '/');
			if (s)
				s[1] = 0;
			WMSetFilePanelDirectory(panel, file);
		}
	}
	wfree(buffer);
	wfree(file);
}

static void goUnmount(WMButton * bPtr, WMFilePanel * panel)
{
}

static void goFloppy(WMButton * bPtr, WMFilePanel * panel)
{
	struct stat filestat;
	WMScreen *scr = WMWidgetScreen(panel->win);

	if (stat(WINGsConfiguration.floppyPath, &filestat)) {
		showError(scr, panel->win, _("An error occured browsing '%s'."), WINGsConfiguration.floppyPath);
		return;
	} else if (!S_ISDIR(filestat.st_mode)) {
		showError(scr, panel->win, _("'%s' is not a directory."), WINGsConfiguration.floppyPath);
		return;
	}

	WMSetFilePanelDirectory(panel, WINGsConfiguration.floppyPath);
}

static void goHome(WMButton * bPtr, WMFilePanel * panel)
{
	char *home;

	/* home is statically allocated. Don't free it! */
	home = wgethomedir();
	if (!home)
		return;

	WMSetFilePanelDirectory(panel, home);
}

static void handleEvents(XEvent * event, void *data)
{
	W_FilePanel *pPtr = (W_FilePanel *) data;
	W_View *view = WMWidgetView(pPtr->win);

	if (event->type == ConfigureNotify) {
		if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
			unsigned int newWidth = event->xconfigure.width;
			unsigned int newHeight = event->xconfigure.height;
			int newColumnCount;

			W_ResizeView(view, newWidth, newHeight);
			WMResizeWidget(pPtr->line, newWidth, 2);
			WMResizeWidget(pPtr->browser, newWidth - 14, newHeight - (PHEIGHT - 200));
			WMResizeWidget(pPtr->fileField, newWidth - 60 - 10, 24);
			WMMoveWidget(pPtr->nameLabel, 7, newHeight - (PHEIGHT - 282));
			WMMoveWidget(pPtr->fileField, 60, newHeight - (PHEIGHT - 278));
			WMMoveWidget(pPtr->okButton, newWidth - (PWIDTH - 245), newHeight - (PHEIGHT - 325));
			WMMoveWidget(pPtr->cancelButton, newWidth - (PWIDTH - 165), newHeight - (PHEIGHT - 325));

			WMMoveWidget(pPtr->trashcanButton, 7, newHeight - (PHEIGHT - 325));
			WMMoveWidget(pPtr->createDirButton, 37, newHeight - (PHEIGHT - 325));
			WMMoveWidget(pPtr->homeButton, 67, newHeight - (PHEIGHT - 325));
			WMMoveWidget(pPtr->disketteButton, 97, newHeight - (PHEIGHT - 325));
			WMMoveWidget(pPtr->unmountButton, 127, newHeight - (PHEIGHT - 325));

			newColumnCount = (newWidth - 14) / 140;
			WMSetBrowserMaxVisibleColumns(pPtr->browser, newColumnCount);
		}
	}
}

static char *getCurrentFileName(WMFilePanel * panel)
{
	char *path;
	char *file;
	char *tmp;
	int len;

	path = WMGetBrowserPath(panel->browser);

	len = strlen(path);
	if (path[len - 1] == '/') {
		file = WMGetTextFieldText(panel->fileField);
		tmp = wmalloc(strlen(path) + strlen(file) + 8);
		if (file[0] != '/') {
			strcpy(tmp, path);
			strcat(tmp, file);
		} else
			strcpy(tmp, file);

		wfree(file);
		wfree(path);
		return tmp;
	} else {
		return path;
	}
}

static Bool validOpenFile(WMFilePanel * panel)
{
	WMListItem *item;
	int col, haveFile = 0;
	char *file = WMGetTextFieldText(panel->fileField);

	if (file[0] != '\0')
		haveFile = 1;
	wfree(file);

	col = WMGetBrowserSelectedColumn(panel->browser);
	item = WMGetBrowserSelectedItemInColumn(panel->browser, col);
	if (item) {
		if (item->isBranch && !panel->flags.canChooseDirectories && !haveFile)
			return False;
		else if (!item->isBranch && !panel->flags.canChooseFiles)
			return False;
		else
			return True;
	} else {
		/* we compute for / here */
		if (!panel->flags.canChooseDirectories && !haveFile)
			return False;
		else
			return True;
	}
	return True;
}

static void buttonClick(WMButton * bPtr, WMFilePanel * panel)
{
	WMRange range;

	if (bPtr == panel->okButton) {
		if (!validOpenFile(panel))
			return;
		if (panel->flags.fileMustExist) {
			char *file;

			file = getCurrentFileName(panel);
			if (access(file, F_OK) != 0) {
				WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
						_("Error"), _("File does not exist."), _("OK"), NULL, NULL);
				wfree(file);
				return;
			}
			wfree(file);
		}
		panel->flags.canceled = 0;
	} else
		panel->flags.canceled = 1;

	range.count = range.position = 0;
	WMSelectTextFieldRange(panel->fileField, range);
	WMBreakModalLoop(WMWidgetScreen(bPtr));
}
