|
|
1.1 root 1: /*
2: Hatari - dlgFileSelect.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: A file selection dialog for the graphical user interface for Hatari.
8: */
9: char DlgFileSelect_rcsid[] = "Hatari $Id: dlgFileSelect.c,v 1.6 2004/04/28 09:04:59 thothy Exp $";
10:
11: #include <SDL.h>
12: #include <sys/stat.h>
13: #include <unistd.h>
14: #include <dirent.h>
15:
16: #include "main.h"
17: #include "screen.h"
18: #include "sdlgui.h"
19: #include "file.h"
20: #include "zip.h"
21:
22:
23: #define SGFSDLG_FILENAME 5
24: #define SGFSDLG_UPDIR 6
25: #define SGFSDLG_ROOTDIR 7
26: #define SGFSDLG_ENTRY1 10
27: #define SGFSDLG_ENTRY16 25
28: #define SGFSDLG_UP 26
29: #define SGFSDLG_DOWN 27
30: #define SGFSDLG_OKAY 28
31: #define SGFSDLG_CANCEL 29
32:
33:
34: #define DLGPATH_SIZE 62
35: static char dlgpath[DLGPATH_SIZE+1]; /* Path name in the dialog */
36:
37: #define DLGFNAME_SIZE 56
38: static char dlgfname[DLGFNAME_SIZE+1]; /* Name of the selected file in the dialog */
39:
40: #define DLGFILENAMES_SIZE 59
41: static char dlgfilenames[16][DLGFILENAMES_SIZE+1]; /* Visible file names in the dialog */
42:
43: /* The dialog data: */
44: static SGOBJ fsdlg[] =
45: {
46: { SGBOX, 0, 0, 0,0, 64,25, NULL },
47: { SGTEXT, 0, 0, 25,1, 13,1, "Choose a file" },
48: { SGTEXT, 0, 0, 1,2, 7,1, "Folder:" },
49: { SGTEXT, 0, 0, 1,3, DLGPATH_SIZE,1, dlgpath },
50: { SGTEXT, 0, 0, 1,4, 6,1, "File:" },
51: { SGTEXT, 0, 0, 7,4, DLGFNAME_SIZE,1, dlgfname },
52: { SGBUTTON, 0, 0, 55,1, 4,1, ".." },
53: { SGBUTTON, 0, 0, 60,1, 3,1, "/" },
54: { SGBOX, 0, 0, 1,6, 62,16, NULL },
55: { SGBOX, 0, 0, 62,7, 1,14, NULL },
56: { SGTEXT, SG_EXIT, 0, 2,6, DLGFILENAMES_SIZE,1, dlgfilenames[0] },
57: { SGTEXT, SG_EXIT, 0, 2,7, DLGFILENAMES_SIZE,1, dlgfilenames[1] },
58: { SGTEXT, SG_EXIT, 0, 2,8, DLGFILENAMES_SIZE,1, dlgfilenames[2] },
59: { SGTEXT, SG_EXIT, 0, 2,9, DLGFILENAMES_SIZE,1, dlgfilenames[3] },
60: { SGTEXT, SG_EXIT, 0, 2,10, DLGFILENAMES_SIZE,1, dlgfilenames[4] },
61: { SGTEXT, SG_EXIT, 0, 2,11, DLGFILENAMES_SIZE,1, dlgfilenames[5] },
62: { SGTEXT, SG_EXIT, 0, 2,12, DLGFILENAMES_SIZE,1, dlgfilenames[6] },
63: { SGTEXT, SG_EXIT, 0, 2,13, DLGFILENAMES_SIZE,1, dlgfilenames[7] },
64: { SGTEXT, SG_EXIT, 0, 2,14, DLGFILENAMES_SIZE,1, dlgfilenames[8] },
65: { SGTEXT, SG_EXIT, 0, 2,15, DLGFILENAMES_SIZE,1, dlgfilenames[9] },
66: { SGTEXT, SG_EXIT, 0, 2,16, DLGFILENAMES_SIZE,1, dlgfilenames[10] },
67: { SGTEXT, SG_EXIT, 0, 2,17, DLGFILENAMES_SIZE,1, dlgfilenames[11] },
68: { SGTEXT, SG_EXIT, 0, 2,18, DLGFILENAMES_SIZE,1, dlgfilenames[12] },
69: { SGTEXT, SG_EXIT, 0, 2,19, DLGFILENAMES_SIZE,1, dlgfilenames[13] },
70: { SGTEXT, SG_EXIT, 0, 2,20, DLGFILENAMES_SIZE,1, dlgfilenames[14] },
71: { SGTEXT, SG_EXIT, 0, 2,21, DLGFILENAMES_SIZE,1, dlgfilenames[15] },
72: { SGBUTTON, SG_TOUCHEXIT, 0, 62,6, 1,1, "\x01" }, /* Arrow up */
73: { SGBUTTON, SG_TOUCHEXIT, 0, 62,21, 1,1, "\x02" }, /* Arrow down */
74: { SGBUTTON, 0, 0, 14,23, 8,1, "Okay" },
75: { SGBUTTON, 0, 0, 34,23, 8,1, "Cancel" },
76: { -1, 0, 0, 0,0, 0,0, NULL }
77: };
78:
79:
80:
81: /*-----------------------------------------------------------------------*/
82: /*
83: Update the file name strings in the dialog.
84: Returns FALSE if it failed, TRUE on success.
85: */
86: static int DlgFileSelect_RefreshEntries(struct dirent **files, char *path,
87: BOOL browsingzip, int entries, int ypos)
88: {
89: int i;
90: char *tempstr = malloc(FILENAME_MAX);
91:
92: if (!tempstr)
93: {
94: perror("DlgFileSelect_RefreshEntries");
95: return FALSE;
96: }
97:
98: /* Copy entries to dialog: */
99: for(i=0; i<16; i++)
100: {
101: if( i+ypos < entries )
102: {
103: struct stat filestat;
104: /* Prepare entries: */
105: strcpy(tempstr, " ");
106: strcat(tempstr, files[i+ypos]->d_name);
107: File_ShrinkName(dlgfilenames[i], tempstr, DLGFILENAMES_SIZE);
108: /* Mark folders: */
109: strcpy(tempstr, path);
110: strcat(tempstr, files[i+ypos]->d_name);
111:
112: if( browsingzip )
113: {
114: if( tempstr[strlen(tempstr)-1] == '/' )
115: dlgfilenames[i][0] = SGFOLDER; /* Mark folders */
116: }
117: else
118: {
119: if( stat(tempstr, &filestat)==0 && S_ISDIR(filestat.st_mode) )
120: dlgfilenames[i][0] = SGFOLDER; /* Mark folders */
121: if (ZIP_FileNameIsZIP(tempstr) && browsingzip == FALSE)
122: dlgfilenames[i][0] = SGFOLDER; /* Mark .ZIP archives as folders */
123: }
124: }
125: else
126: dlgfilenames[i][0] = 0; /* Clear entry */
127: }
128:
129: free(tempstr);
130: return TRUE;
131: }
132:
133:
134: /*-----------------------------------------------------------------------*/
135: /*
136: Show and process a file selection dialog.
137: Returns TRUE if the use selected "okay", FALSE if "cancel".
138: input: zip_path = pointer to buffer to contain file path within a selected
139: zip file, or NULL if browsing zip files is disallowed.
140: bAllowNew: TRUE if the user is allowed to insert new file names.
141: */
142: int SDLGui_FileSelect(char *path_and_name, char *zip_path, BOOL bAllowNew)
143: {
144: int i,n;
145: int entries = 0; /* How many files are in the actual directory? */
146: int ypos = 0;
147: struct dirent **files = NULL;
148: char *pStringMem;
149: char *path, *fname; /* The actual file and path names */
150: BOOL reloaddir = TRUE; /* Do we have to reload the directory file list? */
151: BOOL refreshentries = TRUE; /* Do we have to update the file names in the dialog? */
152: int retbut;
153: int oldcursorstate;
154: int selection = -1; /* The actual selection, -1 if none selected */
155: char *zipfilename; /* Filename in zip file */
156: char *zipdir;
157: BOOL browsingzip = FALSE; /* Are we browsing an archive? */
158: zip_dir *zipfiles = NULL;
159:
160: /* Allocate memory for the file and path name strings: */
161: pStringMem = malloc(4 * FILENAME_MAX);
162: path = pStringMem;
163: fname = pStringMem + FILENAME_MAX;
164: zipfilename = pStringMem + 2 * FILENAME_MAX;
165: zipdir = pStringMem + 3 * FILENAME_MAX;
166:
167: zipfilename[0] = 0;
168:
169: SDLGui_CenterDlg(fsdlg);
170: if (bAllowNew)
171: {
172: fsdlg[SGFSDLG_FILENAME].type = SGEDITFIELD;
173: fsdlg[SGFSDLG_FILENAME].flags |= SG_EXIT;
174: }
175: else
176: {
177: fsdlg[SGFSDLG_FILENAME].type = SGTEXT;
178: fsdlg[SGFSDLG_FILENAME].flags &= ~SG_EXIT;
179: }
180:
181: /* Prepare the path and filename variables */
182: File_splitpath(path_and_name, path, fname, NULL);
183: File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
184: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE);
185:
186: /* Save old mouse cursor state and enable cursor anyway */
187: oldcursorstate = SDL_ShowCursor(SDL_QUERY);
188: if (oldcursorstate == SDL_DISABLE)
189: SDL_ShowCursor(SDL_ENABLE);
190:
191: do
192: {
193: if (reloaddir)
194: {
195: if (strlen(path) >= FILENAME_MAX)
196: {
197: fprintf(stderr, "SDLGui_FileSelect: Path name too long!\n");
198: free(pStringMem);
199: return FALSE;
200: }
201:
202: /* Free old allocated memory: */
203: if (files != NULL)
204: {
205: for(i=0; i<entries; i++)
206: {
207: free(files[i]);
208: }
209: free(files);
210: files = NULL;
211: }
212:
213: if (browsingzip)
214: {
215: files = ZIP_GetFilesDir(zipfiles, zipdir, &entries);
216: }
217: else
218: {
219: /* Load directory entries: */
220: entries = scandir(path, &files, 0, alphasort);
221: }
222:
223: if (entries < 0)
224: {
225: fprintf(stderr, "SDLGui_FileSelect: Path not found.\n");
226: free(pStringMem);
227: return FALSE;
228: }
229:
230: reloaddir = FALSE;
231: refreshentries = TRUE;
232: }/* reloaddir */
233:
234: /* Update the file name strings in the dialog? */
235: if (refreshentries)
236: {
237: if (!DlgFileSelect_RefreshEntries(files, path, browsingzip, entries, ypos))
238: {
239: free(pStringMem);
240: return FALSE;
241: }
242: refreshentries = FALSE;
243: }
244:
245: /* Show dialog: */
246: retbut = SDLGui_DoDialog(fsdlg);
247:
248: /* Has the user clicked on a file or folder? */
249: if( retbut>=SGFSDLG_ENTRY1 && retbut<=SGFSDLG_ENTRY16 && retbut-SGFSDLG_ENTRY1+ypos<entries)
250: {
251: char *tempstr;
252: struct stat filestat;
253:
254: tempstr = malloc(FILENAME_MAX);
255: if (!tempstr)
256: {
257: perror("Error while allocating temporary memory in SDLGui_FileSelect()");
258: free(pStringMem);
259: return FALSE;
260: }
261:
262: if( browsingzip == TRUE )
263: {
264: strcpy(tempstr, zipdir);
265: strcat(tempstr, files[retbut-SGFSDLG_ENTRY1+ypos]->d_name);
266: if(tempstr[strlen(tempstr)-1] == '/')
267: {
268: /* handle the ../ directory */
269: if(strcmp(files[retbut-SGFSDLG_ENTRY1+ypos]->d_name, "../") == 0)
270: {
271: /* close the zip file */
272: if( strcmp(tempstr, "../") == 0 )
273: {
274: reloaddir = refreshentries = TRUE;
275: /* free zip file entries */
276: ZIP_FreeZipDir(zipfiles);
277: zipfiles = NULL;
278: /* Copy the path name to the dialog */
279: File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
280: browsingzip = FALSE;
281: }
282: else
283: {
284: i=strlen(tempstr)-1;
285: n=0;
286: while(i > 0 && n < 3)
287: if( tempstr[i--] == '/' )
288: n++;
289: if(tempstr[i+1] == '/')
290: tempstr[i+2] = '\0';
291: else
292: tempstr[0] = '\0';
293:
294: strcpy(zipdir, tempstr);
295: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
296: }
297: }
298: else /* not the "../" directory */
299: {
300: strcpy(zipdir, tempstr);
301: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
302: }
303: reloaddir = TRUE;
304: /* Copy the path name to the dialog */
305: selection = -1; /* Remove old selection */
306: zipfilename[0] = '\0';
307: dlgfname[0] = 0;
308: ypos = 0;
309:
310: }
311: else
312: {
313: /* Select a file in the zip */
314: selection = retbut-SGFSDLG_ENTRY1+ypos;
315: strcpy(zipfilename, files[selection]->d_name);
316: File_ShrinkName(dlgfname, zipfilename, DLGFNAME_SIZE);
317: }
318:
319: } /* if browsingzip */
320: else
321: {
322: strcpy(tempstr, path);
323: strcat(tempstr, files[retbut-SGFSDLG_ENTRY1+ypos]->d_name);
324: if( stat(tempstr, &filestat)==0 && S_ISDIR(filestat.st_mode) )
325: {
326: /* Set the new directory */
327: strcpy(path, tempstr);
328: if( strlen(path)>=3 )
329: {
330: if(path[strlen(path)-2]=='/' && path[strlen(path)-1]=='.')
331: path[strlen(path)-2] = 0; /* Strip a single dot at the end of the path name */
332: if(path[strlen(path)-3]=='/' && path[strlen(path)-2]=='.' && path[strlen(path)-1]=='.')
333: {
334: /* Handle the ".." folder */
335: char *ptr;
336: if( strlen(path)==3 )
337: path[1] = 0;
338: else
339: {
340: path[strlen(path)-3] = 0;
341: ptr = strrchr(path, '/');
342: if(ptr)
343: *(ptr+1) = 0;
344: }
345: }
346: }
347: File_AddSlashToEndFileName(path);
348: reloaddir = TRUE;
349: /* Copy the path name to the dialog */
350: File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
351: selection = -1; /* Remove old selection */
352: dlgfname[0] = 0;
353: ypos = 0;
354: }
355: else if (ZIP_FileNameIsZIP(tempstr) && zip_path != NULL)
356: {
357: /* open a zip file */
358: zipfiles = ZIP_GetFiles(tempstr);
359: if( zipfiles != NULL && browsingzip == FALSE )
360: {
361: selection = retbut-SGFSDLG_ENTRY1+ypos;
362: strcpy(fname, files[selection]->d_name);
363: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE);
364: browsingzip=TRUE;
365: strcpy(zipdir, "");
366: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
367: reloaddir = refreshentries = TRUE;
368: ypos = 0;
369: }
370:
371: }
372: else
373: {
374: /* Select a file */
375: selection = retbut-SGFSDLG_ENTRY1+ypos;
376: strcpy(fname, files[selection]->d_name);
377: File_ShrinkName(dlgfname, fname, DLGFNAME_SIZE);
378: }
379:
380: } /* not browsingzip */
381:
382: free(tempstr);
383: }
384: else /* Has the user clicked on another button? */
385: {
386: switch(retbut)
387: {
388: case SGFSDLG_UPDIR: /* Change path to parent directory */
389:
390: if( browsingzip )
391: {
392: /* close the zip file */
393: if( strcmp(zipdir, "") == 0 )
394: {
395: reloaddir = refreshentries = TRUE;
396: /* free zip file entries */
397: ZIP_FreeZipDir(zipfiles);
398: zipfiles = NULL;
399: /* Copy the path name to the dialog */
400: File_ShrinkName(dlgpath, path, DLGPATH_SIZE);
401: browsingzip = FALSE;
402: reloaddir = TRUE;
403: selection = -1; /* Remove old selection */
404: fname[0] = 0;
405: dlgfname[0] = 0;
406: ypos = 0;
407: }
408: else
409: {
410: i=strlen(zipdir)-1;
411: n=0;
412: while(i > 0 && n < 2)
413: if( zipdir[i--] == '/' )
414: n++;
415: if(zipdir[i+1] == '/')
416: zipdir[i+2] = '\0';
417: else
418: zipdir[0] = '\0';
419:
420: File_ShrinkName(dlgpath, zipdir, DLGPATH_SIZE);
421: reloaddir = TRUE;
422: selection = -1; /* Remove old selection */
423: zipfilename[0] = '\0';
424: dlgfname[0] = 0;
425: ypos = 0;
426: }
427: } /* not a zip file: */
428: else if( strlen(path)>2 )
429: {
430: char *ptr;
431: File_CleanFileName(path);
432: ptr = strrchr(path, '/');
433: if(ptr)
434: *(ptr+1) = 0;
435: File_AddSlashToEndFileName(path);
436: reloaddir = TRUE;
437: File_ShrinkName(dlgpath, path, DLGPATH_SIZE); /* Copy the path name to the dialog */
438: selection = -1; /* Remove old selection */
439: fname[0] = 0;
440: dlgfname[0] = 0;
441: ypos = 0;
442: }
443: break;
444: case SGFSDLG_ROOTDIR: /* Change to root directory */
445: if( browsingzip )
446: {
447: /* free zip file entries */
448: ZIP_FreeZipDir(zipfiles);
449: zipfiles = NULL;
450: browsingzip = FALSE;
451: }
452:
453: strcpy(path, "/");
454: reloaddir = TRUE;
455: strcpy(dlgpath, path);
456: selection = -1; /* Remove old selection */
457: fname[0] = 0;
458: dlgfname[0] = 0;
459: ypos = 0;
460: break;
461: case SGFSDLG_UP: /* Scroll up */
462: if( ypos>0 )
463: {
464: --ypos;
465: refreshentries = TRUE;
466: }
467: SDL_Delay(20);
468: break;
469: case SGFSDLG_DOWN: /* Scroll down */
470: if( ypos+17<=entries )
471: {
472: ++ypos;
473: refreshentries = TRUE;
474: }
475: SDL_Delay(20);
476: break;
477: case SGFSDLG_FILENAME: /* User entered new filename */
478: strcpy(fname, dlgfname);
479: break;
480: } /* switch */
481: } /* other button code */
482:
483:
484: } /* do */
485:
486:
487: while (retbut!=SGFSDLG_OKAY && retbut!=SGFSDLG_CANCEL && !bQuitProgram);
488:
489: if (oldcursorstate == SDL_DISABLE)
490: SDL_ShowCursor(SDL_DISABLE);
491:
492: File_makepath(path_and_name, path, fname, NULL);
493:
494: /* Free old allocated memory: */
495: if (files != NULL)
496: {
497: for(i=0; i<entries; i++)
498: {
499: free(files[i]);
500: }
501: free(files);
502: files = NULL;
503: }
504:
505: if (browsingzip)
506: {
507: /* free zip file entries */
508: ZIP_FreeZipDir(zipfiles);
509: zipfiles = NULL;
510: }
511:
512: if (zip_path != NULL)
513: {
514: if( browsingzip )
515: {
516: strcpy(zip_path, zipdir);
517: strcat(zip_path, zipfilename);
518: }
519: else
520: zip_path[0] = '\0';
521: }
522:
523: free(pStringMem);
524:
525: return(retbut == SGFSDLG_OKAY);
526: }
527:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.