Subversion Repositories filter_foundry

Rev

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

Rev Author Line No. Line
259 daniel-mar 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
}