/* * CnvPath - file selector * Copyright (C) 1993 Petri Heinila * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * Author can be connected by email from hevi@lut.fi */ #include #include #include /********************************************************************** * declarations **********************************************************************/ static void CnvPathListInit(CnvPath p); static void CnvPathListGet(CnvPath p,String path); static void CnvPathEnter(CnvPath self); static Boolean hasActions = False; static CnvPath tmpCnvPath = NULL; /********************************************************************** * actions **********************************************************************/ static void CnvPathReturn(Widget w,XEvent *e,String *argv, Cardinal *argc); static XtActionsRec actions[] = { {"CnvPathReturn", CnvPathReturn} /* when user accept */ }; static void CnvPathReturn(Widget w,XEvent *e,String *argv, Cardinal *argc) { CnvPath self = (CnvPath)tmpCnvPath; assert(self); CnvPathEnter(self); } /********************************************************************** * widgets **********************************************************************/ static void CnvPathCancelCb(Widget w,XtPointer client,XtPointer call) { CnvPath p = (CnvPath)client; p->hold = CnvPathCancel; } static void CnvPathEnterCb(Widget w,XtPointer client,XtPointer call) { CnvPath self = (CnvPath)client; CnvPathEnter(self); } static void CnvPathSelectFileCb(Widget w,XtPointer client,XtPointer call) { CnvPath p = (CnvPath)client; XawListReturnStruct *ret = (XawListReturnStruct*)call; XtVaSetValues(p->text, XtNstring,ret->string, NULL); } static void CnvPathSelectDirCb(Widget w,XtPointer client,XtPointer call) { CnvPath p = (CnvPath)client; XawListReturnStruct *ret = (XawListReturnStruct*)call; char path[PATH_MAX+1]; if(strcmp(ret->string,"..") == 0) { char *str; pathcpy(path,p->current); str = path + strlen(path); while(*str != '/' && str > path) str--; *str = 0; } else if(strcmp(ret->string,".") == 0) { sprintf(path,"%s",p->current); } else { sprintf(path,"%s/%s",p->current,ret->string); } p->hold = CnvPathHold; CnvPathListGet(p,path); } /********************************************************************** * Layout **********************************************************************/ static void Layout(CnvPath self,String name) { Widget cont,cancel,fileView,dirView,ok; self->shell = XtVaCreatePopupShell (name,transientShellWidgetClass,cnv->shell,NULL); cont = XtVaCreateManagedWidget ("cont",formWidgetClass,self->shell, NULL); self->cwd = XtVaCreateManagedWidget ("cwd",labelWidgetClass,cont, /* XtNfromHoriz,NULL, XtNfromVert,NULL, */ NULL); self->text = XtVaCreateManagedWidget ("text",asciiTextWidgetClass,cont, XtNtype,XawAsciiString, XtNeditType,XawtextEdit, XtNfromHoriz,self->cwd, XtNfromVert,NULL, XtNaccelerators,XtParseAcceleratorTable ("#override Return: CnvPathReturn() \n"), XtNtranslations,XtParseTranslationTable ("#override Tab: CnvNop()\n" "Return: CnvPathReturn() \n"), NULL); fileView = XtVaCreateManagedWidget ("fileView",viewportWidgetClass,cont, XtNfromHoriz,NULL, XtNfromVert,self->cwd, NULL); self->fileList = XtVaCreateManagedWidget ("fileList",listWidgetClass,fileView, XtNtranslations,XtParseTranslationTable ("#override (2): Set() Notify() CnvPathReturn()\n" ": Set() Notify() \n"), NULL); XtAddCallback(self->fileList,XtNcallback,CnvPathSelectFileCb, (XtPointer)self); dirView = XtVaCreateManagedWidget ("dirView",viewportWidgetClass,cont, XtNfromHoriz,fileView, XtNfromVert,self->cwd, NULL); self->dirList = XtVaCreateManagedWidget ("dirList",listWidgetClass,dirView, NULL); XtAddCallback(self->dirList,XtNcallback,CnvPathSelectDirCb,(XtPointer)self); ok = XtVaCreateManagedWidget ("ok",commandWidgetClass,cont, XtNfromHoriz,NULL, XtNfromVert,fileView, NULL); XtAddCallback(ok,XtNcallback,CnvPathEnterCb,(XtPointer)self); cancel = XtVaCreateManagedWidget ("cancel",commandWidgetClass,cont, XtNfromHoriz,ok, XtNfromVert,fileView, NULL); XtAddCallback(cancel,XtNcallback,CnvPathCancelCb,(XtPointer)self); XtInstallAllAccelerators(cont,cont); } /********************************************************************** * **********************************************************************/ /* * function: select a filepath */ static void CnvPathEnter(CnvPath self) { String str; self->hold = CnvPathOk; XtVaGetValues(self->text, XtNstring,&str, NULL); namecpy(self->filename,str); } /* * implicit: App app */ static void CnvPathListInit(CnvPath p) { int i; for(i=0; i < EntryMax; i++) { /* debug1("i:%i\n",i); */ p->fileTable[i] = NULL; } for(i=0; i < EntryMax; i++) { /* debug1("i2:%i\n",i); */ p->dirTable[i] = NULL; } p->fileNro = 0; p->dirNro = 0; *(p->filename) = 0; } /* * compare funtion for sorting in CnvPathListGet() */ static int StrCmp (const void **s1, const void **s2) { return strcmp (*s1, *s2); } /* * read files and directories from given absolute dir * update them into Path structure. directoty is a crossfire * part of file name ie. LibDir/MapDir, althought * it is absolute name in it part, ie it have to begin with '/'. */ static void CnvPathListGet(CnvPath self,String directory) { DIR *dir; #ifdef NeXT struct direct *dirent; #else struct dirent *dirent; #endif struct stat statbuf; Cardinal i,fileOld,dirOld; char path[PATH_MAX+1],full[PATH_MAX+1]; /*** form full dir name ***/ sprintf(full,"%s%s",self->root,directory); debug1("CnvPathListGet(), rescan %s\n",full); /*** open it ***/ if(CnvPathNoAccess(self->shell, full)) return; if((dir = opendir(full)) == NULL) CnvDie(self->shell,full); XtVaSetValues(self->cwd, XtNlabel,directory, NULL); pathcpy(self->current,directory); /*** read dir & files ***/ fileOld = self->fileNro; dirOld = self->dirNro; self->fileNro = 0; self->dirNro = 0; while((dirent = readdir(dir)) != NULL) { sprintf(path,"%s/%s",full,dirent->d_name); if (stat ((char *) path, &statbuf) == -1) { perror (path); continue; } if(S_ISDIR(statbuf.st_mode)) { if(self->dirNro >= EntryMax) continue; XtFree(self->dirTable[self->dirNro]); self->dirTable[self->dirNro] = XtNewString(dirent->d_name); self->dirNro++; } else { if(self->fileNro >= EntryMax) continue; XtFree(self->fileTable[self->fileNro]); self->fileTable[self->fileNro] = XtNewString(dirent->d_name); self->fileNro++; } } closedir(dir); /*** free strings ***/ for(i = self->fileNro; i < fileOld; i++) { XtFree(self->fileTable[i]); self->fileTable[i] = NULL; } for(i = self->dirNro; i < dirOld; i++) { XtFree(self->dirTable[i]); self->dirTable[i] = NULL; } /*** sort tables ***/ qsort(self->fileTable,self->fileNro,sizeof(String),(int (*)())StrCmp); qsort(self->dirTable,self->dirNro,sizeof(String),(int (*)())StrCmp); /*** update ***/ XawListChange(self->fileList,self->fileTable,self->fileNro,0,True); XawListChange(self->dirList,self->dirTable,self->dirNro,0,True); } /********************************************************************** * public **********************************************************************/ /* * create new instance of file-selector, no show * dir is crossfire path eg "/" * name: name of this module * root: all * dir : starting directory */ CnvPath CnvPathCreate(String name,String root,String dir) { CnvPath self; debug3("CnvPathCreate() %s %s %s\n",name,root,dir); self = (CnvPath) XtMalloc (sizeof (struct CnvPath)); memset(self,0,sizeof(struct CnvPath)); pathcpy(self->root,root); /*** initialize translations if not done ***/ if(hasActions == False) { XtAppAddActions(XtWidgetToApplicationContext(cnv->shell), actions, XtNumber(actions)); hasActions = True; } Layout(self,name); CnvPathListInit(self); CnvCenterWidget(self->shell); CnvPathListGet(self,dir); return self; } /* * remove instance of file-selector */ void CnvPathDestroy(CnvPath self) { Cardinal i; debug("CnvPathDestroy()\n"); for(i=0;idirNro;i++) XtFree(self->dirTable[i]); for(i=0;ifileNro;i++) XtFree(self->fileTable[i]); XtDestroyWidget(self->shell); } /* * member: select a filepath * return: PathResponce & results are in Path-structure */ CnvPathResponce CnvPathSelect(CnvPath self) { if(tmpCnvPath) { CnvNotify("File Selector already in use", "Continue",NULL); return CnvPathCancel; } XtVaSetValues(self->text, XtNstring,self->filename, NULL); /*** round ***/ tmpCnvPath = self; self->hold = CnvPathHold; XtPopup(self->shell,XtGrabExclusive); while(self->hold == CnvPathHold) { XtAppProcessEvent(XtWidgetToApplicationContext(self->shell),XtIMXEvent); } XtPopdown(self->shell); tmpCnvPath = NULL; return self->hold; } /* * member: select a filepath * return: PathResponce & results are in Path-structure */ CnvPathResponce CnvPathSelectAbs(CnvPath self,String path) { if(tmpCnvPath) { CnvNotify("File Selector already in use", "Continue",NULL); return CnvPathCancel; } XtVaSetValues(self->text, XtNstring,self->filename, NULL); /*** round ***/ tmpCnvPath = self; self->hold = CnvPathHold; XtPopup(self->shell,XtGrabExclusive); while(self->hold == CnvPathHold) { XtAppProcessEvent(XtWidgetToApplicationContext(self->shell),XtIMXEvent); } XtPopdown(self->shell); tmpCnvPath = NULL; sprintf(path,"%s%s/%s",self->root,self->current,self->filename); return self->hold; } /********************************************************************** * utility **********************************************************************/ /* * - path is full absolute name * - return true if NO access */ Boolean CnvPathNoAccess(Widget w, String path) { char buf[BUFSIZ]; if (access (path, R_OK | X_OK) == -1) { switch (errno) { case EACCES: sprintf (buf, "Permission denied for %s", path); CnvNotify (buf,Continue,NULL); break; case ENOENT: sprintf (buf, "%s does not exist", path); CnvNotify (buf,Continue,NULL); break; case EIO: sprintf (buf, "IO error in accessing %s", path); CnvNotify (buf,Continue,NULL); break; case ENAMETOOLONG: case ENOTDIR: sprintf (buf, "Error in pathname for %s", path); CnvNotify (buf,Continue); break; default: sprintf (buf, "Error accessing to %s", path); CnvNotify (buf,Continue,NULL); break; } return True; } else { return False; } } /* * - path is full absolute name * - return true if NO access */ Boolean CnvPathNoWrite(Widget w, String path) { char buf[BUFSIZ]; if (access (path, R_OK | W_OK) == -1) { switch (errno) { case EACCES: sprintf (buf, "Permission denied for %s", path); CnvNotify (buf,Continue,NULL); break; case ENOENT: sprintf (buf, "%s does not exist", path); CnvNotify (buf,Continue,NULL); break; case EIO: sprintf (buf, "IO error in accessing %s", path); CnvNotify (buf,Continue,NULL); break; case ENAMETOOLONG: case ENOTDIR: sprintf (buf, "Error in pathname for %s", path); CnvNotify (buf,Continue); break; default: sprintf (buf, "Error accessing to %s", path); CnvNotify (buf,Continue,NULL); break; } return True; } else { return False; } } /*** end of CnvPath.c ***/