/* browser.c */
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include "lui.h"
/*
* Test if the given name is a directory.
*/
static int isdir( char *name )
{
struct stat stat_buff;
if (stat( name, &stat_buff )!=0) return 0;
if (stat_buff.st_mode & (unsigned) S_IFDIR)
return 1;
else
return 0;
}
/*
* Test if the given name is valid file.
*/
static int isfile( char *name )
{
struct stat stat_buff;
if (stat( name, &stat_buff )!=0) return 0;
if ( (stat_buff.st_mode & (unsigned) S_IFDIR)==0 )
return 1;
else
return 0;
}
/*
* Comparison function for qsort used in read_dir.
*/
static int compare_entries( const void *a, const void *b )
{
char *s1, *s2;
s1 = *((char **) a);
s2 = *((char **) b);
return strcmp( s1, s2 );
}
static char **read_dir( char *path, int *count )
{
DIR *dirf;
struct dirent *dentry;
char **entries;
int i;
entries = (char **) malloc( MAX_ENTRIES * sizeof(char *) );
dirf = opendir( path );
if (!dirf) {
/* bad directory path */
*count = 0;
return NULL;
}
for (i=0;i<MAX_ENTRIES;) {
char str[1000], fullname[1000];
dentry = readdir(dirf);
if (!dentry)
break;
strcpy( str, dentry->d_name );
/* don't list . or .. */
if (strcmp(str,".")!=0 && strcmp(str,"..")!=0) {
/* append a / to directory entries */
strcpy( fullname, path );
strcat( fullname, str );
if (isdir(fullname))
strcat( str, "/" );
entries[i] = strdup(str);
i++;
}
}
closedir( dirf );
qsort( entries, i, sizeof(char*), compare_entries );
*count = i;
return entries;
}
/*
* Load the list widget with the directory entries found in the dir
* named by b->current.
*/
static void load_browser_list( LUI_BROWSER *b )
{
char **entries;
int count;
/* LUI_ListUnload( b->list );*/
entries = read_dir( b->current, &count );
LUI_ListLoad( b->list, count, entries, 1 );
b->selected = -1;
}
/*
* Called when user clicks on a directory entry in the list.
*/
static int select_cb( LUI_LIST *list, int entry )
{
LUI_BROWSER *b;
char *str;
b = (LUI_BROWSER *) list->userdata;
if (b->selected>=0) {
LUI_ListSetStatus( b->list, b->selected, 0 );
}
str = b->list->strings[entry];
if (str[strlen(str)-1]=='/') {
strcat( b->current, str );
LUI_FieldSetText( b->field, b->current );
load_browser_list( b );
}
else {
if (b->selected==entry) {
b->selected = -1;
}
else {
b->selected = entry;
}
}
return 1;
}
/*
* Called when user clicks on the parent button.
*/
static int parent_cb( LUI_NEWBUTTON *button, int state )
{
LUI_BROWSER *b;
int len;
int pos;
b = (LUI_BROWSER *) button->userdata;
/* remove last segment of path name */
len = strlen( b->current );
if (len==0) return 0;
pos = len-1;
if (b->current[pos]!='/') {
pos--;
/* remove filename part of string */
while (pos>=0 && b->current[pos]!='/')
pos--;
}
/* remove last directory part of string */
pos--; /* skip '/' */
while (pos>=0 && b->current[pos]!='/')
pos--;
if (pos>=0) {
b->current[pos+1] = 0;
}
LUI_FieldSetText( b->field, b->current );
load_browser_list( b );
return 1;
}
/*
* Called when user clicks on the "Home" button.
*/
static int home_cb( LUI_NEWBUTTON *button, int state )
{
LUI_BROWSER *b;
char *pwd;
b = (LUI_BROWSER *) button->userdata;
pwd = getenv("HOME");
if (pwd) {
strcpy( b->current, pwd );
strcat( b->current, "/" );
LUI_FieldSetText( b->field, b->current );
}
load_browser_list( b );
return 1;
}
/*
* Called when user clicks on the "Root" button.
*/
static int root_cb( LUI_NEWBUTTON *button, int state )
{
LUI_BROWSER *b;
b = (LUI_BROWSER *) button->userdata;
strcpy( b->current, "/" );
LUI_FieldSetText( b->field, b->current );
load_browser_list( b );
return 1;
}
/*
* Called when user changes type-in directory field.
*/
static int typein_cb( LUI_FIELD *field, char *text )
{
LUI_BROWSER *b;
int len;
b = (LUI_BROWSER *) field->userdata;
strcpy( b->current, text );
if (isdir(text)) {
len = strlen(text);
if (len>0 && text[len-1]!='/') {
strcat( b->current, "/" );
LUI_FieldSetText( b->field, b->current );
}
load_browser_list( b );
}
else if (isfile(text)) {
XUnmapWindow( LUI_Display, b->window );
XSync( LUI_Display, False ); /* force unmap now */
if (b->callback) {
(*b->callback)( b, text );
}
}
else {
/* nothing */
}
return 1;
}
/*
* Called when user clicks on the OK button.
*/
static int ok_cb( LUI_NEWBUTTON *button, int state )
{
LUI_BROWSER *b;
b = (LUI_BROWSER *) button->userdata;
if (b->selected>=0) {
/* call user callback */
XUnmapWindow( LUI_Display, b->window );
XSync( LUI_Display, False ); /* force unmap now */
if (b->callback) {
char filepath[1000];
char *pwd = getenv( "PWD" );
if (pwd && strncmp( b->current, pwd, strlen(pwd))==0) {
/* omit prefix if it matches current directory */
strcpy( filepath, b->current+strlen(pwd)+1 );
}
else {
/* return whole path from root */
strcpy( filepath, b->current );
}
strcat( filepath, b->list->strings[b->selected] );
(*b->callback)( b, filepath );
}
}
return 1;
}
/*
* Called when user clicks on the OK button.
*/
static int okay_cb( LUI_NEWBUTTON *button, int state )
{
LUI_BROWSER *b;
b = (LUI_BROWSER *) button->userdata;
if (b->selected>=0) {
/* call user callback */
XUnmapWindow( LUI_Display, b->window );
XSync( LUI_Display, False ); /* force unmap now */
if (b->callback) {
char filepath[1000];
strcpy( filepath, b->current );
strcat( filepath, b->list->strings[b->selected] );
(*b->callback)( b, filepath );
}
}
return 1;
}
/*
* Called when user clicks on the "Cancel" button.
*/
static int cancel_cb( LUI_NEWBUTTON *button, int state )
{
LUI_BROWSER *b;
b = (LUI_BROWSER *) button->userdata;
XUnmapWindow( LUI_Display, b->window );
return 1;
}
/*
* Create a ctx browser widget.
*/
/*
* Create a file browser widget. This does *not* result in anything being
* mapped to the display. To begin a browsing "session" call the
* LUI_BrowserActivate function.
*/
LUI_BROWSER *LUI_BrowserCreate( int width, int height )
{
LUI_BROWSER *b;
int gutter = LUI_LayoutGetGutter();
char *pwd;
b = (LUI_BROWSER *) malloc( sizeof(LUI_BROWSER) );
if (!b) return NULL;
b->window = LUI_CreateWindow( LUI_RootWindow, width, height );
b->width = width;
b->height = height;
pwd = getenv( "PWD" );
if (pwd) {
strcpy( b->current, pwd );
strcat( b->current, "/" );
}
else {
strcpy( b->current, "/" );
}
/* The file list */
b->list = LUI_ListCreate( b->window, LUI_LEFT, LUI_TOP,
width - 2*gutter, height-5*gutter-30-2*24, 0 );
b->list->userdata = (void *) b;
LUI_ListCallback( b->list, select_cb );
/* Parent, Home, and Root buttons */
b->parent_button = LUI_PushButtonCreate( b->window, LUI_LEFT, LUI_NEXT_Y,
80, 24, "Parent .." );
b->parent_button->userdata = (void *) b;
LUI_ButtonCallback( b->parent_button, parent_cb );
b->home_button = LUI_PushButtonCreate( b->window, LUI_NEXT_X, LUI_SAME_Y,
80, 24, "Home ~" );
b->home_button->userdata = (void *) b;
LUI_ButtonCallback( b->home_button, home_cb );
b->root_button = LUI_PushButtonCreate( b->window, LUI_NEXT_X, LUI_SAME_Y,
80, 24, "Root /" );
b->root_button->userdata = (void *) b;
LUI_ButtonCallback( b->root_button, root_cb );
/* The current path field */
b->field = LUI_FieldCreate( b->window, LUI_LEFT, LUI_NEXT_Y,
width - 2*gutter, 30 );
b->field->userdata = (void *) b;
LUI_FieldCallback( b->field, typein_cb );
/* OK and Cancel buttons */
b->ok_button = LUI_PushButtonCreate( b->window, LUI_LEFT, LUI_NEXT_Y,
80, 24, "OK" );
b->ok_button->userdata = (void *) b;
LUI_ButtonCallback( b->ok_button, ok_cb );
b->cancel_button = LUI_PushButtonCreate( b->window, LUI_NEXT_X, LUI_SAME_Y,
80, 24, "Cancel" );
b->cancel_button->userdata = (void *) b;
LUI_ButtonCallback( b->cancel_button, cancel_cb );
b->selected = -1;
/* MJK 12.04.98 */
/* 24Nov97 Phil McDonald */
/* MJK 12.08.98 why need this?? */
/*
LUI_AddWidgetToWindow( LUI_RootWindow, b, (LUI_FNCP) LUI_BrowserDestroy );
*/
return b;
}
/*
* Register the callback function to call when the user clicks on the
* "OK" button.
* Input: browser - which browser
* callback - the function to call when user clicks on "OK". The
* function should be declared as:
* int callback( LUI_BROWSER *browser, char *filepath )
*/
void LUI_BrowserCallback( LUI_BROWSER *browser, int (*callback)() )
{
browser->callback = callback;
browser->context_index = context_index;
}
/*
* Map the given browser with the given initial path.
* Input: browser - which browser to display
* path - initial path
*/
int LUI_BrowserActivate( LUI_BROWSER *browser, char *path )
{
XMapWindow( LUI_Display, browser->window );
XRaiseWindow( LUI_Display, browser->window );
/* remove filename part from current pathname */
while (browser->current[0] && !isdir(browser->current)) {
/* find last '/' character */
char *lastslash = strrchr( browser->current, '/' );
/* truncate from last slash */
*lastslash = 0;
}
if (path != NULL) strcpy(browser->current, path); /* WLH 6-27-96 */
if (browser->current[0]==0) {
strcpy( browser->current, "." );
}
/* add a trailing slash if there isn't one already */
{
int len = strlen( browser->current );
if (len>0 && browser->current[len-1]!='/') {
strcat( browser->current, "/" );
}
}
LUI_FieldSetText( browser->field, browser->current );
load_browser_list( browser );
return 1;
}
/* MJK 12.04.98 */
/* 24Nov97 Phil McDonald */
void LUI_BrowserDestroy( LUI_BROWSER *bp )
{
delete_event(bp->window);
LUI_DestroyWindow( bp->window );
/* free memory */
LUI_ListUnload (bp->list);
free(bp);
return;
}
syntax highlighted by Code2HTML, v. 0.9.1