Subversion Repositories filter_foundry

Rev

Rev 199 | Rev 268 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.         This file is part of a common library
  3.     Copyright (C) 2002-6 Toby Thain, toby@telegraphics.com.au
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 2 of the License, or
  8.     (at your option) any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18. */
  19.  
  20. /* Choose file dialog using Navigation Services
  21.    (C) 2002-6 Toby Thain <toby@telegraphics.com.au> */
  22.  
  23. #include <memory.h>
  24. #include <script.h>
  25. #include <plstringfuncs.h>
  26. #include <stringcompare.h>
  27. #include <aedatamodel.h>
  28.  
  29. #include <string.h>
  30. #include <ctype.h>
  31. #include <stdio.h>
  32.  
  33. #include "choosefile.h"
  34. #include "dbg.h"
  35. #include "str.h"
  36.  
  37. #if ! OPAQUE_TOOLBOX_STRUCTS
  38.         #define AEGetDescData BlockMove
  39. #endif
  40.  
  41. struct exts_types{
  42.         char *filter;
  43.         int numtypes;
  44.         OSType *typelist;
  45. };
  46.  
  47. Boolean matchext(StringPtr name,char *ext);
  48. Boolean matchextfilter(StringPtr name,struct exts_types *ud);
  49. Boolean matchtypelist(NavFileOrFolderInfo* info,struct exts_types *ud);
  50. pascal Boolean myFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode);
  51.  
  52. int strincmp(char *s1, char *s2, int n) {
  53.         /* case insensitive comparison */
  54.         int d;
  55.         while (--n >= 0) {
  56.                 d = tolower(*s1) - tolower(*s2);
  57.                 if (d != 0 || *s1 == '\0' || *s2 == '\0') return d;
  58.                 ++s1;
  59.                 ++s2;
  60.         }
  61.         return 0;
  62. }
  63.  
  64. Boolean matchext(StringPtr name,char *ext){
  65.         Ptr pos = PLstrrchr(name,'.');
  66.         int len = strlen(ext);
  67.         return pos && (name[0] - (pos-(Ptr)name) == len) && !strincmp(pos+1,ext,len);
  68. }
  69.  
  70. /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/CommonDialogBoxLibrary/CommonDialogBoxReference/CommonDialogBoxStructures/OPENFILENAME.asp
  71. lpstrFilter
  72. Pointer to a buffer containing pairs of null-terminated filter strings.
  73. The last string in the buffer must be terminated by two NULL characters.
  74. The first string in each pair is a display string that describes the filter
  75. (for example, "Text Files"), and the second string specifies the filter pattern
  76. (for example, "*.TXT"). To specify multiple filter patterns for a single display string,
  77. use a semicolon to separate the patterns (for example, "*.TXT;*.DOC;*.BAK").
  78. A pattern string can be a combination of valid file name characters
  79. and the asterisk (*) wildcard character. Do not include spaces in the pattern string.
  80. */
  81. // example:
  82. // "All supported files (.AFS, .8BF, .TXT)\0*.AFS;*.8BF;*.TXT\0All files (*.*)\0*.*\0\0"
  83.  
  84. Boolean matchextfilter(StringPtr name,struct exts_types *ud){
  85.         Ptr pos = PLstrrchr(name,'.');
  86.         char *p = ud->filter,*q;
  87.         int len;
  88.  
  89.         if(p){
  90.                 // process only the FIRST string pair (in Windows GetFile box,
  91.                 // the user gets to choose which filter string to apply)
  92.  
  93.                 // skip over display string
  94.                 while(*p++)
  95.                         ;
  96.  
  97.                 // keep going until second string ends
  98.                 while(*p){
  99.  
  100.                         if(p[0] == '*' && p[1] == '.'){ // only match entries of '*.XXX' form
  101.  
  102.                                 if(p[2] == '*')
  103.                                         return true; // looks like it's "*.*"
  104.  
  105.                                 p += 2;
  106.  
  107.                                 if(pos){ // file name does have an extension
  108.                                         q = pos+1; // point to first char of extension
  109.                                         len = name[0] - (pos-(Ptr)name);
  110.  
  111.                                         // match characters until filename ends, pattern ends (NUL or ';') or mismatch
  112.                                         while( len && *p && *p != ';' && toupper(*q++) == toupper(*p++) )
  113.                                                 --len;
  114.  
  115.                                         // check if whole pattern matched
  116.                                         if( len == 0 && (!*p || *p == ';') )
  117.                                                 return true;
  118.                                 }
  119.                         }
  120.  
  121.                         // skip to next item (after ';')
  122.                         while( *p && *p != ';' )
  123.                                 ++p;
  124.                         if(*p) ++p; // skip over semicolon
  125.  
  126.                 }
  127.  
  128.         }
  129.         return false;
  130. }
  131.  
  132. Boolean matchtypelist(NavFileOrFolderInfo* info,struct exts_types *ud){
  133.         int i;
  134.  
  135.         if(ud->typelist)
  136.                 for(i=0;i<ud->numtypes;++i)
  137.                         if(info->fileAndFolder.fileInfo.finderInfo.fdType == ud->typelist[i])
  138.                                 return true;
  139.         return false;
  140. }
  141.  
  142. pascal Boolean myFilterProc(AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode)
  143. {
  144.         NavFileOrFolderInfo *theInfo = (NavFileOrFolderInfo*)info;
  145.         OSStatus e = noErr;
  146.         AEDesc theDesc;
  147.         FSSpec fss;
  148.  
  149.         if( !(e = AECoerceDesc(theItem,typeFSS,&theDesc)) ){
  150.                 AEGetDescData(&theDesc,&fss,sizeof(FSSpec));
  151.                 AEDisposeDesc(&theDesc);
  152.                 return e || theItem->descriptorType != typeFSS || theInfo->isFolder
  153.                         || matchextfilter(fss.name,(struct exts_types*)callBackUD)
  154.                         || matchtypelist(theInfo,(struct exts_types*)callBackUD);
  155.   }
  156.   return true;
  157. }
  158.  
  159. Boolean choosefiletypes(StringPtr prompt,StandardFileReply *sfr,NavReplyRecord *reply,
  160.                                                 OSType types[],int ntypes,const char *lpstrFilter)
  161. {
  162.         //NavTypeListHandle tl = (NavTypeListHandle)NewHandle(sizeof(NavTypeList) + ntypes*sizeof(OSType));
  163.         OSErr e;
  164.         long count;
  165.         AEKeyword theKeyword;
  166.         DescType actualType;
  167.         Size actualSize;
  168.         NavDialogOptions dopts;
  169.         NavObjectFilterUPP filter_upp = NewNavObjectFilterUPP(myFilterProc);
  170.         struct exts_types ud;
  171.  
  172.         sfr->sfGood = false;
  173.  
  174.         if(!(e = NavGetDefaultDialogOptions(&dopts))){
  175.                 PLstrcpy(dopts.message,prompt);
  176.                 ud.filter = lpstrFilter;
  177.                 ud.numtypes = ntypes;
  178.                 ud.typelist = types;
  179.                 e = NavChooseFile(NULL,reply,&dopts,NULL,NULL,filter_upp,NULL/*tl*/,&ud);
  180.         }
  181.  
  182.         if(!e && reply->validRecord ){
  183.                 if ( !(e = AECountItems(&reply->selection, &count))
  184.                          && count==1
  185.                          && !(e = AEGetNthPtr(&reply->selection,1,typeFSS,&theKeyword,&actualType,
  186.                                                                   &sfr->sfFile,sizeof(FSSpec),&actualSize)) ){
  187.                         sfr->sfScript = reply->keyScript;
  188.                         sfr->sfGood = true;
  189.                 }
  190. //        NavDisposeReply(&reply); // caller must dispose
  191.         }
  192.  
  193.         DisposeNavObjectFilterUPP(filter_upp);
  194.         return sfr->sfGood;
  195. }
  196.  
  197. Boolean choosefile(StringPtr prompt,StandardFileReply *sfr,
  198.                                    NavReplyRecord *reply,OSType type,const char *lpstrFilter)
  199. {
  200.         return choosefiletypes(prompt,sfr,reply,&type,1,lpstrFilter);
  201. }
  202.  
  203. Boolean putfile(StringPtr prompt,StringPtr fname,OSType fileType,OSType fileCreator,
  204.                 NavReplyRecord *reply,StandardFileReply *sfr,
  205.                 char *lpstrDefExt,const char *lpstrFilter,int nFilterIndex){
  206. //      NavReplyRecord reply;
  207.         NavDialogOptions dopts;
  208. //      AEDesc defaultLocation;
  209.         AEKeyword theKeyword;
  210.         DescType actualType;
  211.         Size actualSize;
  212.         OSErr e;
  213.  
  214.         sfr->sfGood = false;
  215.  
  216.         NavGetDefaultDialogOptions(&dopts);
  217.         dopts.dialogOptionFlags |= kNavNoTypePopup;
  218.         dopts.dialogOptionFlags &= ~kNavAllowStationery;
  219.         PLstrcpy(dopts.savedFileName,fname);          /* default name for text box in NavPutFile (or null string for default) */
  220. /* in two minds whether to append default extension or not, on Mac; skip for now.
  221.         if(lpstrDefExt && fname[0]){
  222.                 dopts.savedFileName[++*dopts.savedFileName] = '.';
  223.                 memcpy(dopts.savedFileName+1+*dopts.savedFileName,lpstrDefExt,strlen(lpstrDefExt));
  224.                 *dopts.savedFileName += strlen(lpstrDefExt);
  225.         }
  226. */
  227.         PLstrcpy(dopts.message,prompt);                /* custom message prompt (or null string for default) */
  228.  
  229.         if( !(e = NavPutFile(NULL,reply,&dopts,NULL,fileType,fileCreator,NULL)) && reply->validRecord ){
  230.                 if( !(e = AEGetNthPtr(&(reply->selection), 1, typeFSS,
  231.                                                           &theKeyword, &actualType, &sfr->sfFile, sizeof(FSSpec), &actualSize)) ){
  232.                         sfr->sfScript = reply->keyScript;
  233.                         sfr->sfGood = true;
  234.                 }
  235.         }
  236.  
  237.         return sfr->sfGood;
  238. }
  239.  
  240. OSErr completesave(NavReplyRecord *reply){
  241.         OSErr e = NavCompleteSave(reply,kNavTranslateInPlace);
  242.         NavDisposeReply(reply);
  243.         return e;
  244. }
  245.