blob: 48ed19cc37b8d70eda275b69208f1be98bfda663 [file] [log] [blame]
Jack Jansen7571f301995-07-29 13:48:41 +00001"""Edit the Python Preferences file."""
Jack Jansen822a30b1996-04-10 14:52:18 +00002#
3# This program is getting more and more clunky. It should really
4# be rewritten in a modeless way some time soon.
Jack Jansen7571f301995-07-29 13:48:41 +00005
6from Dlg import *
7from Events import *
8from Res import *
9import string
10import struct
11import macfs
12import MacOS
13import os
14import sys
15import Res # For Res.Error
16
17# resource IDs in our own resources (dialogs, etc)
18MESSAGE_ID = 256
19
Jack Jansen9062fa21995-08-14 12:21:12 +000020DIALOG_ID = 512
Jack Jansen7571f301995-07-29 13:48:41 +000021TEXT_ITEM = 1
22OK_ITEM = 2
23CANCEL_ITEM = 3
Jack Jansendb0bace1996-04-04 15:38:44 +000024DIR_ITEM = 4
25TITLE_ITEM = 5
Jack Jansen822a30b1996-04-10 14:52:18 +000026OPTIONS_ITEM = 7
27
28# The options dialog. There is a correspondence between
29# the dialog item numbers and the option.
30OPT_DIALOG_ID = 513
Jack Jansen6c4e9871996-09-06 22:25:34 +000031# 1 thru 9 are the options
32# The GUSI creator/type and delay-console
33OD_CREATOR_ITEM = 10
34OD_TYPE_ITEM = 11
35OD_DELAYCONSOLE_ITEM = 12
36OD_OK_ITEM = 13
37OD_CANCEL_ITEM = 14
Jack Jansen7571f301995-07-29 13:48:41 +000038
39# Resource IDs in the preferences file
40PATH_STRINGS_ID = 128
41DIRECTORY_ID = 128
Jack Jansendb0bace1996-04-04 15:38:44 +000042OPTIONS_ID = 128
Jack Jansen6c4e9871996-09-06 22:25:34 +000043GUSI_ID = 10240
Jack Jansen7571f301995-07-29 13:48:41 +000044
Jack Jansendb0bace1996-04-04 15:38:44 +000045# Override IDs (in the applet)
46OVERRIDE_PATH_STRINGS_ID = 129
47OVERRIDE_DIRECTORY_ID = 129
48OVERRIDE_OPTIONS_ID = 129
Jack Jansen6c4e9871996-09-06 22:25:34 +000049OVERRIDE_GUSI_ID = 10240
50
51# Things we know about the GUSI resource. Note the code knows these too.
52GUSIPOS_TYPE=0
53GUSIPOS_CREATOR=4
54GUSIPOS_SKIP=8
55GUSIPOS_FLAGS=9
56GUSIFLAGS_DELAY=0x04 # Mask
Jack Jansendb0bace1996-04-04 15:38:44 +000057
58READ = 1
Jack Jansen7571f301995-07-29 13:48:41 +000059WRITE = 2
60smAllScripts = -3
61kOnSystemDisk = 0x8000
62
63def restolist(data):
64 """Convert STR# resource data to a list of strings"""
65 if not data:
66 return []
67 num, = struct.unpack('h', data[:2])
68 data = data[2:]
69 rv = []
70 for i in range(num):
71 strlen = ord(data[0])
72 if strlen < 0: strlen = strlen + 256
73 str = data[1:strlen+1]
74 data = data[strlen+1:]
75 rv.append(str)
76 return rv
77
78def listtores(list):
79 """Convert a list of strings to STR# resource data"""
80 rv = struct.pack('h', len(list))
81 for str in list:
82 rv = rv + chr(len(str)) + str
83 return rv
84
85def message(str = "Hello, world!", id = MESSAGE_ID):
86 """Show a simple alert with a text message"""
87 d = GetNewDialog(id, -1)
Jack Jansen822a30b1996-04-10 14:52:18 +000088 d.SetDialogDefaultItem(1)
Jack Jansen7571f301995-07-29 13:48:41 +000089 print 'd=', d
90 tp, h, rect = d.GetDialogItem(2)
91 SetDialogItemText(h, str)
92 while 1:
93 n = ModalDialog(None)
94 if n == 1: break
95
Jack Jansen6c4e9871996-09-06 22:25:34 +000096def optinteract((options, creator, type, delaycons)):
Jack Jansen822a30b1996-04-10 14:52:18 +000097 """Let the user interact with the options dialog"""
Jack Jansen6c4e9871996-09-06 22:25:34 +000098 old_options = (options[:], creator, type, delaycons)
Jack Jansen822a30b1996-04-10 14:52:18 +000099 d = GetNewDialog(OPT_DIALOG_ID, -1)
Jack Jansen6c4e9871996-09-06 22:25:34 +0000100 tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
101 SetDialogItemText(h, creator)
102 tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
103 SetDialogItemText(h, type)
Jack Jansen822a30b1996-04-10 14:52:18 +0000104 d.SetDialogDefaultItem(OD_OK_ITEM)
105 d.SetDialogCancelItem(OD_CANCEL_ITEM)
106 while 1:
107 for i in range(len(options)):
108 tp, h, rect = d.GetDialogItem(i+1)
109 h.as_Control().SetControlValue(options[i])
Jack Jansen6c4e9871996-09-06 22:25:34 +0000110 tp, h, rect = d.GetDialogItem(OD_DELAYCONSOLE_ITEM)
111 h.as_Control().SetControlValue(delaycons)
Jack Jansen822a30b1996-04-10 14:52:18 +0000112 n = ModalDialog(None)
113 if n == OD_OK_ITEM:
Jack Jansen6c4e9871996-09-06 22:25:34 +0000114 tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
115 ncreator = GetDialogItemText(h)
116 tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
117 ntype = GetDialogItemText(h)
118 if len(ncreator) == 4 and len(ntype) == 4:
119 return options, ncreator, ntype, delaycons
120 else:
121 sys.stderr.write('\007')
Jack Jansen822a30b1996-04-10 14:52:18 +0000122 elif n == OD_CANCEL_ITEM:
123 return old_options
Jack Jansen6c4e9871996-09-06 22:25:34 +0000124 elif n in (OD_CREATOR_ITEM, OD_TYPE_ITEM):
125 pass
126 elif n == OD_DELAYCONSOLE_ITEM:
127 delaycons = (not delaycons)
Jack Jansen822a30b1996-04-10 14:52:18 +0000128 elif 1 <= n <= len(options):
129 options[n-1] = (not options[n-1])
130
131
132def interact(list, pythondir, options, title):
Jack Jansen7571f301995-07-29 13:48:41 +0000133 """Let the user interact with the dialog"""
134 opythondir = pythondir
135 try:
136 # Try to go to the "correct" dir for GetDirectory
137 os.chdir(pythondir.as_pathname())
138 except os.error:
139 pass
140 d = GetNewDialog(DIALOG_ID, -1)
Jack Jansendb0bace1996-04-04 15:38:44 +0000141 tp, h, rect = d.GetDialogItem(TITLE_ITEM)
142 SetDialogItemText(h, title)
143 tp, h, rect = d.GetDialogItem(TEXT_ITEM)
Jack Jansen7571f301995-07-29 13:48:41 +0000144 SetDialogItemText(h, string.joinfields(list, '\r'))
Jack Jansendb0bace1996-04-04 15:38:44 +0000145## d.SetDialogDefaultItem(OK_ITEM)
146 d.SetDialogCancelItem(CANCEL_ITEM)
Jack Jansen7571f301995-07-29 13:48:41 +0000147 while 1:
148 n = ModalDialog(None)
149 if n == OK_ITEM:
150 break
151 if n == CANCEL_ITEM:
152 return None
Jack Jansendb0bace1996-04-04 15:38:44 +0000153## if n == REVERT_ITEM:
154## return [], pythondir
Jack Jansen7571f301995-07-29 13:48:41 +0000155 if n == DIR_ITEM:
Jack Jansen9062fa21995-08-14 12:21:12 +0000156 fss, ok = macfs.GetDirectory('Select python home folder:')
Jack Jansen7571f301995-07-29 13:48:41 +0000157 if ok:
158 pythondir = fss
Jack Jansen822a30b1996-04-10 14:52:18 +0000159 if n == OPTIONS_ITEM:
160 options = optinteract(options)
Jack Jansen7571f301995-07-29 13:48:41 +0000161 tmp = string.splitfields(GetDialogItemText(h), '\r')
162 rv = []
163 for i in tmp:
164 if i:
165 rv.append(i)
Jack Jansen822a30b1996-04-10 14:52:18 +0000166 return rv, pythondir, options
Jack Jansen7571f301995-07-29 13:48:41 +0000167
Jack Jansendb0bace1996-04-04 15:38:44 +0000168def getprefpath(id):
169 # Load the path and directory resources
Jack Jansen7571f301995-07-29 13:48:41 +0000170 try:
Jack Jansendb0bace1996-04-04 15:38:44 +0000171 sr = GetResource('STR#', id)
172 except (MacOS.Error, Res.Error):
173 return None, None
174 d = sr.data
175 l = restolist(d)
176 return l, sr
177
178def getprefdir(id):
179 try:
180 dr = GetResource('alis', id)
181 fss, fss_changed = macfs.RawAlias(dr.data).Resolve()
182 except (MacOS.Error, Res.Error):
183 return None, None, 1
184 return fss, dr, fss_changed
Jack Jansen822a30b1996-04-10 14:52:18 +0000185
186def getoptions(id):
187 try:
188 opr = GetResource('Popt', id)
189 except (MacOS.Error, Res.Error):
190 return [0]*7, None
191 return map(lambda x: ord(x), opr.data), opr
Jack Jansen7571f301995-07-29 13:48:41 +0000192
Jack Jansen6c4e9871996-09-06 22:25:34 +0000193def getgusioptions(id):
194 try:
195 opr = GetResource('GU\267I', id)
196 except (MacOS.Error, Res.Error):
197 return '????', '????', 0, None
198 data = opr.data
199 type = data[GUSIPOS_TYPE:GUSIPOS_TYPE+4]
200 creator = data[GUSIPOS_CREATOR:GUSIPOS_CREATOR+4]
201 flags = ord(data[GUSIPOS_FLAGS])
202 delay = (not not (flags & GUSIFLAGS_DELAY))
203 return creator, type, delay, opr
204
205def setgusioptions(opr, creator, type, delay):
206 data = opr.data
207 flags = ord(data[GUSIPOS_FLAGS])
208 if delay:
209 flags = flags | GUSIFLAGS_DELAY
210 else:
211 flags = flags & ~GUSIFLAGS_DELAY
212 data = type + creator + data[GUSIPOS_SKIP] + chr(flags) + data[GUSIPOS_FLAGS+1:]
213 return data
214
Jack Jansendb0bace1996-04-04 15:38:44 +0000215def openpreffile(rw):
Jack Jansen7571f301995-07-29 13:48:41 +0000216 # Find the preferences folder and our prefs file, create if needed.
217 vrefnum, dirid = macfs.FindFolder(kOnSystemDisk, 'pref', 0)
218 preff_fss = macfs.FSSpec((vrefnum, dirid, 'Python Preferences'))
219 try:
Jack Jansendb0bace1996-04-04 15:38:44 +0000220 preff_handle = FSpOpenResFile(preff_fss, rw)
Jack Jansen7571f301995-07-29 13:48:41 +0000221 except Res.Error:
222 # Create it
223 message('No preferences file, creating one...')
Jack Jansen532e3c21996-02-21 15:36:26 +0000224 FSpCreateResFile(preff_fss, 'Pyth', 'pref', smAllScripts)
Jack Jansendb0bace1996-04-04 15:38:44 +0000225 preff_handle = FSpOpenResFile(preff_fss, rw)
226 return preff_handle
227
228def openapplet(name):
229 fss = macfs.FSSpec(name)
Jack Jansen7571f301995-07-29 13:48:41 +0000230 try:
Jack Jansendb0bace1996-04-04 15:38:44 +0000231 app_handle = FSpOpenResFile(fss, WRITE)
232 except Res.Error:
233 message('File does not have a resource fork.')
234 sys.exit(0)
235 return app_handle
236
237
238def edit_preferences():
239 preff_handle = openpreffile(WRITE)
240
241 l, sr = getprefpath(PATH_STRINGS_ID)
242 if l == None:
Jack Jansen7571f301995-07-29 13:48:41 +0000243 message('Cannot find any sys.path resource! (Old python?)')
244 sys.exit(0)
Jack Jansendb0bace1996-04-04 15:38:44 +0000245
246 fss, dr, fss_changed = getprefdir(DIRECTORY_ID)
247 if fss == None:
Jack Jansen7571f301995-07-29 13:48:41 +0000248 fss = macfs.FSSpec(os.getcwd())
249 fss_changed = 1
Jack Jansen822a30b1996-04-10 14:52:18 +0000250
251 options, opr = getoptions(OPTIONS_ID)
252 saved_options = options[:]
Jack Jansen7571f301995-07-29 13:48:41 +0000253
Jack Jansen6c4e9871996-09-06 22:25:34 +0000254 creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
255 saved_gusi_options = creator, type, delaycons
256
Jack Jansen7571f301995-07-29 13:48:41 +0000257 # Let the user play away
Jack Jansen6c4e9871996-09-06 22:25:34 +0000258 result = interact(l, fss, (options, creator, type, delaycons),
259 'System-wide preferences')
Jack Jansen7571f301995-07-29 13:48:41 +0000260
261 # See what we have to update, and how
262 if result == None:
263 sys.exit(0)
264
Jack Jansen6c4e9871996-09-06 22:25:34 +0000265 pathlist, nfss, (options, creator, type, delaycons) = result
Jack Jansen7571f301995-07-29 13:48:41 +0000266 if nfss != fss:
267 fss_changed = 1
268
Jack Jansen822a30b1996-04-10 14:52:18 +0000269 if fss_changed:
270 alias = nfss.NewAlias()
271 if dr:
272 dr.data = alias.data
273 dr.ChangedResource()
274 else:
275 dr = Resource(alias.data)
276 dr.AddResource('alis', DIRECTORY_ID, '')
277
278 if pathlist != l:
279 if pathlist == []:
280 if sr.HomeResFile() == preff_handle:
281 sr.RemoveResource()
282 elif sr.HomeResFile() == preff_handle:
283 sr.data = listtores(pathlist)
284 sr.ChangedResource()
285 else:
286 sr = Resource(listtores(pathlist))
287 sr.AddResource('STR#', PATH_STRINGS_ID, '')
288
289 if options != saved_options:
290 newdata = reduce(lambda x, y: x+chr(y), options, '')
291 if opr and opr.HomeResFile() == preff_handle:
292 opr.data = newdata
293 opr.ChangedResource()
294 else:
295 opr = Resource(newdata)
296 opr.AddResource('Popt', OPTIONS_ID, '')
Jack Jansen6c4e9871996-09-06 22:25:34 +0000297
298 if (creator, type, delaycons) != saved_gusi_options:
299 newdata = setgusioptions(gusi_opr, creator, type, delaycons)
300 if gusi_opr.HomeResFile() == preff_handle:
301 gusi_opr.data = newdata
302 gusi_opr.ChangedResource()
303 else:
304 print 'Created new GUSI option'
305 ngusi_opr = Resource(gusi_opr.data)
306 ngusi_opr.AddResource('GU\267I', GUSI_ID, '')
Jack Jansen7571f301995-07-29 13:48:41 +0000307
308 CloseResFile(preff_handle)
Jack Jansendb0bace1996-04-04 15:38:44 +0000309
310def edit_applet(name):
311 pref_handle = openpreffile(READ)
312 app_handle = openapplet(name)
313
314 notfound = ''
315 l, sr = getprefpath(OVERRIDE_PATH_STRINGS_ID)
316 if l == None:
317 notfound = 'path'
318
319 l, dummy = getprefpath(PATH_STRINGS_ID)
320 if l == None:
321 message('Cannot find any sys.path resource! (Old python?)')
322 sys.exit(0)
323
324 fss, dr, fss_changed = getprefdir(OVERRIDE_DIRECTORY_ID)
325 if fss == None:
326 if notfound:
Jack Jansen822a30b1996-04-10 14:52:18 +0000327 notfound = notfound + ', directory'
Jack Jansendb0bace1996-04-04 15:38:44 +0000328 else:
329 notfound = 'directory'
330 fss, dummy, dummy2 = getprefdir(DIRECTORY_ID)
331 if fss == None:
332 fss = macfs.FSSpec(os.getcwd())
333 fss_changed = 1
Jack Jansen822a30b1996-04-10 14:52:18 +0000334
335 options, opr = getoptions(OVERRIDE_OPTIONS_ID)
336 if not opr:
337 if notfound:
338 notfound = notfound + ', options'
339 else:
340 notfound = 'options'
341 options, dummy = getoptions(OPTIONS_ID)
342 saved_options = options[:]
Jack Jansendb0bace1996-04-04 15:38:44 +0000343
Jack Jansen6c4e9871996-09-06 22:25:34 +0000344 creator, type, delaycons, gusi_opr = getgusioptions(OVERRIDE_GUSI_ID)
345 if not opr:
346 if notfound:
347 notfound = notfound + ', GUSI options'
348 else:
349 notfound = 'GUSI options'
350 creator, type, delaycons, dummy = getgusioptions(GUSI_ID)
351 saved_gusi_options = creator, type, delaycons
352
Jack Jansendb0bace1996-04-04 15:38:44 +0000353 dummy = dummy2 = None # Discard them.
354
355 if notfound:
356 message('Warning: initial %s taken from system-wide defaults'%notfound)
357 # Let the user play away
Jack Jansen6c4e9871996-09-06 22:25:34 +0000358 result = interact(l, fss, (options, creator, type, delaycons), name)
Jack Jansendb0bace1996-04-04 15:38:44 +0000359
360 # See what we have to update, and how
361 if result == None:
362 sys.exit(0)
363
Jack Jansen822a30b1996-04-10 14:52:18 +0000364 pathlist, nfss, options = result
Jack Jansendb0bace1996-04-04 15:38:44 +0000365 if nfss != fss:
366 fss_changed = 1
367
Jack Jansen822a30b1996-04-10 14:52:18 +0000368 if fss_changed:
369 alias = nfss.NewAlias()
370 if dr:
371 dr.data = alias.data
372 dr.ChangedResource()
373 else:
374 dr = Resource(alias.data)
375 dr.AddResource('alis', OVERRIDE_DIRECTORY_ID, '')
376
377 if pathlist != l:
378 if pathlist == []:
379 if sr.HomeResFile() == app_handle:
380 sr.RemoveResource()
381 elif sr and sr.HomeResFile() == app_handle:
382 sr.data = listtores(pathlist)
383 sr.ChangedResource()
384 else:
385 sr = Resource(listtores(pathlist))
386 sr.AddResource('STR#', OVERRIDE_PATH_STRINGS_ID, '')
387
388 if options != saved_options:
389 newdata = reduce(lambda x, y: x+chr(y), options, '')
390 if opr and opr.HomeResFile() == app_handle:
391 opr.data = newdata
392 opr.ChangedResource()
393 else:
394 opr = Resource(newdata)
395 opr.AddResource('Popt', OVERRIDE_OPTIONS_ID, '')
Jack Jansen6c4e9871996-09-06 22:25:34 +0000396
397 if (creator, type, delaycons) != saved_gusi_options:
398 newdata = setgusioptions(gusi_opr, creator, type, delaycons)
399 if gusi_opr.HomeResFile == app_handle:
400 gusi_opr.data = newdata
401 gusi_opr.ChangedResource()
402 else:
403 gusi_opr = Resource(gusi_opr.data)
404 gusi_opr.AddResource('GU\267I', OVERRIDE_GUSI_ID, '')
405
Jack Jansendb0bace1996-04-04 15:38:44 +0000406 CloseResFile(app_handle)
407
408def main():
409 try:
410 h = OpenResFile('EditPythonPrefs.rsrc')
411 except Res.Error:
412 pass # Assume we already have acces to our own resource
413
414 if len(sys.argv) <= 1:
415 edit_preferences()
416 else:
417 for appl in sys.argv[1:]:
418 edit_applet(appl)
419
Jack Jansen7571f301995-07-29 13:48:41 +0000420
421if __name__ == '__main__':
Jack Jansen7571f301995-07-29 13:48:41 +0000422 main()