comparison Mac/scripts/EditPythonPrefs.py @ 6275:f9fbde75c536 legacy-trunk

Major overhaul: this is now little more than a user interface, the preference handling code is in modules pythonprefs and preferences. This should finally make it easier for someone (Just?) to write a decent interface to preference setting, and it'll allow setting initial sys.path and such from ConfigurePython.
author Jack Jansen <jack.jansen@cwi.nl>
date Mon, 08 Sep 1997 13:19:42 +0000
parents 77135da9f36c
children ebd099889721
comparison
equal deleted inserted replaced
6274:7a3808edc539 6275:f9fbde75c536
11 import macfs 11 import macfs
12 import MacOS 12 import MacOS
13 import os 13 import os
14 import sys 14 import sys
15 import Res # For Res.Error 15 import Res # For Res.Error
16 16 import pythonprefs
17 # Resource in the Python resource chain 17 import EasyDialogs
18 PREFNAME_NAME="PythonPreferenceFileName"
19 18
20 # resource IDs in our own resources (dialogs, etc) 19 # resource IDs in our own resources (dialogs, etc)
21 MESSAGE_ID = 256 20 MESSAGE_ID = 256
22 21
23 DIALOG_ID = 511 22 DIALOG_ID = 511
29 OPTIONS_ITEM = 7 28 OPTIONS_ITEM = 7
30 29
31 # The options dialog. There is a correspondence between 30 # The options dialog. There is a correspondence between
32 # the dialog item numbers and the option. 31 # the dialog item numbers and the option.
33 OPT_DIALOG_ID = 510 32 OPT_DIALOG_ID = 510
34 # 1 thru 9 are the options 33
34 # Map dialog item numbers to option names (and the reverse)
35 opt_dialog_map = [
36 None,
37 "inspect",
38 "verbose",
39 "optimize",
40 "unbuffered",
41 "debugging",
42 "keepopen",
43 "keeperror",
44 "nointopt",
45 "noargs",
46 "delayconsole"]
47 opt_dialog_dict = {}
48 for i in range(len(opt_dialog_map)):
49 if opt_dialog_map[i]:
50 opt_dialog_dict[opt_dialog_map[i]] = i
51 # 1 thru 10 are the options
35 # The GUSI creator/type and delay-console 52 # The GUSI creator/type and delay-console
36 OD_CREATOR_ITEM = 10 53 OD_CREATOR_ITEM = 11
37 OD_TYPE_ITEM = 11 54 OD_TYPE_ITEM = 12
38 OD_DELAYCONSOLE_ITEM = 12
39 OD_OK_ITEM = 13 55 OD_OK_ITEM = 13
40 OD_CANCEL_ITEM = 14 56 OD_CANCEL_ITEM = 14
41 57
42 # Resource IDs in the preferences file 58 def optinteract(options):
43 PATH_STRINGS_ID = 128
44 DIRECTORY_ID = 128
45 OPTIONS_ID = 128
46 GUSI_ID = 10240
47
48 # Override IDs (in the applet)
49 OVERRIDE_PATH_STRINGS_ID = 129
50 OVERRIDE_DIRECTORY_ID = 129
51 OVERRIDE_OPTIONS_ID = 129
52 OVERRIDE_GUSI_ID = 10241
53
54 # Things we know about the GUSI resource. Note the code knows these too.
55 GUSIPOS_TYPE=0
56 GUSIPOS_CREATOR=4
57 GUSIPOS_SKIP=8
58 GUSIPOS_FLAGS=9
59 GUSIPOS_VERSION=10
60 GUSIVERSION='0181'
61 GUSIFLAGS_DELAY=0x20 # Mask
62
63 READ = 1
64 WRITE = 2
65 smAllScripts = -3
66 kOnSystemDisk = 0x8000
67
68 def restolist(data):
69 """Convert STR# resource data to a list of strings"""
70 if not data:
71 return []
72 num, = struct.unpack('h', data[:2])
73 data = data[2:]
74 rv = []
75 for i in range(num):
76 strlen = ord(data[0])
77 if strlen < 0: strlen = strlen + 256
78 str = data[1:strlen+1]
79 data = data[strlen+1:]
80 rv.append(str)
81 return rv
82
83 def listtores(list):
84 """Convert a list of strings to STR# resource data"""
85 rv = struct.pack('h', len(list))
86 for str in list:
87 rv = rv + chr(len(str)) + str
88 return rv
89
90 def message(str = "Hello, world!", id = MESSAGE_ID):
91 """Show a simple alert with a text message"""
92 d = GetNewDialog(id, -1)
93 d.SetDialogDefaultItem(1)
94 tp, h, rect = d.GetDialogItem(2)
95 SetDialogItemText(h, str)
96 while 1:
97 n = ModalDialog(None)
98 if n == 1: break
99
100 def optinteract((options, creator, type, delaycons)):
101 """Let the user interact with the options dialog""" 59 """Let the user interact with the options dialog"""
102 old_options = (options[:], creator, type, delaycons)
103 d = GetNewDialog(OPT_DIALOG_ID, -1) 60 d = GetNewDialog(OPT_DIALOG_ID, -1)
104 tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM) 61 tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
105 SetDialogItemText(h, creator) 62 SetDialogItemText(h, options['creator'])
106 tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM) 63 tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
107 SetDialogItemText(h, type) 64 SetDialogItemText(h, options['type'])
108 d.SetDialogDefaultItem(OD_OK_ITEM) 65 d.SetDialogDefaultItem(OD_OK_ITEM)
109 d.SetDialogCancelItem(OD_CANCEL_ITEM) 66 d.SetDialogCancelItem(OD_CANCEL_ITEM)
67
110 while 1: 68 while 1:
111 for i in range(len(options)): 69 for name in opt_dialog_dict.keys():
112 tp, h, rect = d.GetDialogItem(i+1) 70 num = opt_dialog_dict[name]
113 h.as_Control().SetControlValue(options[i]) 71 tp, h, rect = d.GetDialogItem(num)
114 tp, h, rect = d.GetDialogItem(OD_DELAYCONSOLE_ITEM) 72 h.as_Control().SetControlValue(options[name])
115 h.as_Control().SetControlValue(delaycons)
116 n = ModalDialog(None) 73 n = ModalDialog(None)
117 if n == OD_OK_ITEM: 74 if n == OD_OK_ITEM:
118 tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM) 75 tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
119 ncreator = GetDialogItemText(h) 76 ncreator = GetDialogItemText(h)
120 tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM) 77 tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
121 ntype = GetDialogItemText(h) 78 ntype = GetDialogItemText(h)
122 if len(ncreator) == 4 and len(ntype) == 4: 79 if len(ncreator) == 4 and len(ntype) == 4:
123 return options, ncreator, ntype, delaycons 80 options['creator'] = ncreator
81 options['type'] = ntype
82 return options
124 else: 83 else:
125 sys.stderr.write('\007') 84 MacOS.SysBeep()
126 elif n == OD_CANCEL_ITEM: 85 elif n == OD_CANCEL_ITEM:
127 return old_options 86 return
128 elif n in (OD_CREATOR_ITEM, OD_TYPE_ITEM): 87 elif n in (OD_CREATOR_ITEM, OD_TYPE_ITEM):
129 pass 88 pass
130 elif n == OD_DELAYCONSOLE_ITEM: 89 elif 1 <= n <= len(opt_dialog_map):
131 delaycons = (not delaycons) 90 options[opt_dialog_map[n]] = (not options[opt_dialog_map[n]])
132 elif 1 <= n <= len(options):
133 options[n-1] = (not options[n-1])
134 91
135 92
136 def interact(list, pythondir, options, title): 93 def interact(options, title):
137 """Let the user interact with the dialog""" 94 """Let the user interact with the dialog"""
138 opythondir = pythondir
139 try: 95 try:
140 # Try to go to the "correct" dir for GetDirectory 96 # Try to go to the "correct" dir for GetDirectory
141 os.chdir(pythondir.as_pathname()) 97 os.chdir(options['dir'].as_pathname())
142 except os.error: 98 except os.error:
143 pass 99 pass
144 d = GetNewDialog(DIALOG_ID, -1) 100 d = GetNewDialog(DIALOG_ID, -1)
145 tp, h, rect = d.GetDialogItem(TITLE_ITEM) 101 tp, h, rect = d.GetDialogItem(TITLE_ITEM)
146 SetDialogItemText(h, title) 102 SetDialogItemText(h, title)
147 tp, h, rect = d.GetDialogItem(TEXT_ITEM) 103 tp, h, rect = d.GetDialogItem(TEXT_ITEM)
148 ## SetDialogItemText(h, string.joinfields(list, '\r')) 104 ## SetDialogItemText(h, string.joinfields(list, '\r'))
149 h.data = string.joinfields(list, '\r') 105 h.data = string.joinfields(options['path'], '\r')
150 d.SelectDialogItemText(TEXT_ITEM, 0, 32767) 106 d.SelectDialogItemText(TEXT_ITEM, 0, 32767)
151 d.SelectDialogItemText(TEXT_ITEM, 0, 0) 107 d.SelectDialogItemText(TEXT_ITEM, 0, 0)
152 ## d.SetDialogDefaultItem(OK_ITEM) 108 ## d.SetDialogDefaultItem(OK_ITEM)
153 d.SetDialogCancelItem(CANCEL_ITEM) 109 d.SetDialogCancelItem(CANCEL_ITEM)
154 d.GetDialogWindow().ShowWindow() 110 d.GetDialogWindow().ShowWindow()
162 ## if n == REVERT_ITEM: 118 ## if n == REVERT_ITEM:
163 ## return [], pythondir 119 ## return [], pythondir
164 if n == DIR_ITEM: 120 if n == DIR_ITEM:
165 fss, ok = macfs.GetDirectory('Select python home folder:') 121 fss, ok = macfs.GetDirectory('Select python home folder:')
166 if ok: 122 if ok:
167 pythondir = fss 123 options['dir'] = fss
168 if n == OPTIONS_ITEM: 124 if n == OPTIONS_ITEM:
169 options = optinteract(options) 125 noptions = options
126 for k in options.keys():
127 noptions[k] = options[k]
128 noptions = optinteract(noptions)
129 if noptions:
130 options = noptions
170 tmp = string.splitfields(h.data, '\r') 131 tmp = string.splitfields(h.data, '\r')
171 rv = [] 132 newpath = []
172 for i in tmp: 133 for i in tmp:
173 if i: 134 if i:
174 rv.append(i) 135 newpath.append(i)
175 return rv, pythondir, options 136 options['path'] = newpath
137 return options
176 138
177 def getprefpath(id):
178 # Load the path and directory resources
179 try:
180 sr = GetResource('STR#', id)
181 except (MacOS.Error, Res.Error):
182 return None, None
183 d = sr.data
184 l = restolist(d)
185 return l, sr
186
187 def getprefdir(id):
188 try:
189 dr = GetResource('alis', id)
190 fss, fss_changed = macfs.RawAlias(dr.data).Resolve()
191 except (MacOS.Error, Res.Error):
192 return None, None, 1
193 return fss, dr, fss_changed
194
195 def getoptions(id):
196 try:
197 opr = GetResource('Popt', id)
198 except (MacOS.Error, Res.Error):
199 return [0]*9, None
200 options = map(lambda x: ord(x), opr.data)
201 while len(options) < 9:
202 options = options + [0]
203 return options, opr
204
205 def getgusioptions(id):
206 try:
207 opr = GetResource('GU\267I', id)
208 except (MacOS.Error, Res.Error):
209 return '????', '????', 0, None
210 data = opr.data
211 type = data[GUSIPOS_TYPE:GUSIPOS_TYPE+4]
212 creator = data[GUSIPOS_CREATOR:GUSIPOS_CREATOR+4]
213 flags = ord(data[GUSIPOS_FLAGS])
214 version = data[GUSIPOS_VERSION:GUSIPOS_VERSION+4]
215 if version <> GUSIVERSION:
216 message('GU\267I resource version "%s", fixing to "%s"'%(version, GUSIVERSION))
217 flags = 0
218 delay = (not not (flags & GUSIFLAGS_DELAY))
219 return creator, type, delay, opr
220
221 def setgusioptions(opr, creator, type, delay):
222 data = opr.data
223 flags = ord(data[GUSIPOS_FLAGS])
224 version = data[GUSIPOS_VERSION:GUSIPOS_VERSION+4]
225 if version <> GUSIVERSION:
226 flags = 0x88
227 version = GUSIVERSION
228 if delay:
229 flags = flags | GUSIFLAGS_DELAY
230 else:
231 flags = flags & ~GUSIFLAGS_DELAY
232 data = type + creator + data[GUSIPOS_SKIP] + chr(flags) + GUSIVERSION + data[GUSIPOS_VERSION+4:]
233 return data
234
235 def openpreffile(rw):
236 # Find the preferences folder and our prefs file, create if needed.
237 vrefnum, dirid = macfs.FindFolder(kOnSystemDisk, 'pref', 0)
238 try:
239 pnhandle = GetNamedResource('STR ', PREFNAME_NAME)
240 except Res.Error:
241 message("No %s resource (old Python?)"%PREFNAME_NAME)
242 sys.exit(1)
243 prefname = pnhandle.data[1:]
244 preff_fss = macfs.FSSpec((vrefnum, dirid, prefname))
245 try:
246 preff_handle = FSpOpenResFile(preff_fss, rw)
247 except Res.Error:
248 # Create it
249 message('No preferences file, creating one...')
250 FSpCreateResFile(preff_fss, 'Pyth', 'pref', smAllScripts)
251 preff_handle = FSpOpenResFile(preff_fss, rw)
252 return preff_handle
253
254 def openapplet(name):
255 fss = macfs.FSSpec(name)
256 try:
257 app_handle = FSpOpenResFile(fss, WRITE)
258 except Res.Error:
259 message('File does not have a resource fork.')
260 sys.exit(0)
261 return app_handle
262
263 139
264 def edit_preferences(): 140 def edit_preferences():
265 preff_handle = openpreffile(WRITE) 141 handler = pythonprefs.PythonOptions()
266 142 result = interact(handler.load(), 'System-wide preferences')
267 l, sr = getprefpath(PATH_STRINGS_ID) 143 if result:
268 if l == None: 144 handler.save(result)
269 message('Cannot find any sys.path resource! (Old python?)')
270 sys.exit(0)
271
272 fss, dr, fss_changed = getprefdir(DIRECTORY_ID)
273 if fss == None:
274 fss = macfs.FSSpec(os.getcwd())
275 fss_changed = 1
276
277 options, opr = getoptions(OPTIONS_ID)
278 saved_options = options[:]
279
280 creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
281 saved_gusi_options = creator, type, delaycons
282
283 # Let the user play away
284 result = interact(l, fss, (options, creator, type, delaycons),
285 'System-wide preferences')
286
287 # See what we have to update, and how
288 if result == None:
289 sys.exit(0)
290
291 pathlist, nfss, (options, creator, type, delaycons) = result
292 if nfss != fss:
293 fss_changed = 1
294
295 if fss_changed:
296 alias = nfss.NewAlias()
297 if dr:
298 dr.data = alias.data
299 dr.ChangedResource()
300 else:
301 dr = Resource(alias.data)
302 dr.AddResource('alis', DIRECTORY_ID, '')
303
304 if pathlist != l:
305 if pathlist == []:
306 if sr.HomeResFile() == preff_handle:
307 sr.RemoveResource()
308 elif sr.HomeResFile() == preff_handle:
309 sr.data = listtores(pathlist)
310 sr.ChangedResource()
311 else:
312 sr = Resource(listtores(pathlist))
313 sr.AddResource('STR#', PATH_STRINGS_ID, '')
314
315 if options != saved_options:
316 newdata = reduce(lambda x, y: x+chr(y), options, '')
317 if opr and opr.HomeResFile() == preff_handle:
318 opr.data = newdata
319 opr.ChangedResource()
320 else:
321 opr = Resource(newdata)
322 opr.AddResource('Popt', OPTIONS_ID, '')
323
324 if (creator, type, delaycons) != saved_gusi_options:
325 newdata = setgusioptions(gusi_opr, creator, type, delaycons)
326 if gusi_opr.HomeResFile() == preff_handle:
327 gusi_opr.data = newdata
328 gusi_opr.ChangedResource()
329 else:
330 ngusi_opr = Resource(newdata)
331 ngusi_opr.AddResource('GU\267I', GUSI_ID, '')
332
333 CloseResFile(preff_handle)
334 145
335 def edit_applet(name): 146 def edit_applet(name):
336 pref_handle = openpreffile(READ) 147 handler = pythonprefs.AppletOptions(name)
337 app_handle = openapplet(name) 148 result = interact(handler.load(), os.path.split(name)[1])
338 149 if result:
339 notfound = '' 150 handler.save(result)
340 l, sr = getprefpath(OVERRIDE_PATH_STRINGS_ID)
341 if l == None:
342 notfound = 'path'
343
344 l, dummy = getprefpath(PATH_STRINGS_ID)
345 if l == None:
346 message('Cannot find any sys.path resource! (Old python?)')
347 sys.exit(0)
348
349 fss, dr, fss_changed = getprefdir(OVERRIDE_DIRECTORY_ID)
350 if fss == None:
351 if notfound:
352 notfound = notfound + ', directory'
353 else:
354 notfound = 'directory'
355 fss, dummy, dummy2 = getprefdir(DIRECTORY_ID)
356 if fss == None:
357 fss = macfs.FSSpec(os.getcwd())
358 fss_changed = 1
359
360 options, opr = getoptions(OVERRIDE_OPTIONS_ID)
361 if not opr:
362 if notfound:
363 notfound = notfound + ', options'
364 else:
365 notfound = 'options'
366 options, dummy = getoptions(OPTIONS_ID)
367 saved_options = options[:]
368
369 creator, type, delaycons, gusi_opr = getgusioptions(OVERRIDE_GUSI_ID)
370 if not gusi_opr:
371 if notfound:
372 notfound = notfound + ', GUSI options'
373 else:
374 notfound = 'GUSI options'
375 creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
376 saved_gusi_options = creator, type, delaycons
377
378 dummy = dummy2 = None # Discard them.
379
380 if notfound:
381 message('Warning: initial %s taken from system-wide defaults'%notfound)
382 # Let the user play away
383 result = interact(l, fss, (options, creator, type, delaycons), name)
384
385 # See what we have to update, and how
386 if result == None:
387 sys.exit(0)
388
389 pathlist, nfss, (options, creator, type, delaycons) = result
390 if nfss != fss:
391 fss_changed = 1
392
393 if fss_changed:
394 alias = nfss.NewAlias()
395 if dr:
396 dr.data = alias.data
397 dr.ChangedResource()
398 else:
399 dr = Resource(alias.data)
400 dr.AddResource('alis', OVERRIDE_DIRECTORY_ID, '')
401
402 if pathlist != l:
403 if pathlist == []:
404 if sr.HomeResFile() == app_handle:
405 sr.RemoveResource()
406 elif sr and sr.HomeResFile() == app_handle:
407 sr.data = listtores(pathlist)
408 sr.ChangedResource()
409 else:
410 sr = Resource(listtores(pathlist))
411 sr.AddResource('STR#', OVERRIDE_PATH_STRINGS_ID, '')
412
413 if options != saved_options:
414 newdata = reduce(lambda x, y: x+chr(y), options, '')
415 if opr and opr.HomeResFile() == app_handle:
416 opr.data = newdata
417 opr.ChangedResource()
418 else:
419 opr = Resource(newdata)
420 opr.AddResource('Popt', OVERRIDE_OPTIONS_ID, '')
421
422 if (creator, type, delaycons) != saved_gusi_options:
423 newdata = setgusioptions(gusi_opr, creator, type, delaycons)
424 id, type, name = gusi_opr.GetResInfo()
425 if gusi_opr.HomeResFile() == app_handle and id == OVERRIDE_GUSI_ID:
426 gusi_opr.data = newdata
427 gusi_opr.ChangedResource()
428 else:
429 ngusi_opr = Resource(newdata)
430 ngusi_opr.AddResource('GU\267I', OVERRIDE_GUSI_ID, '')
431
432 CloseResFile(app_handle)
433 151
434 def main(): 152 def main():
435 try: 153 try:
436 h = OpenResFile('EditPythonPrefs.rsrc') 154 h = OpenResFile('EditPythonPrefs.rsrc')
437 except Res.Error: 155 except Res.Error: