blob: eda4bf782e02abd17a941dce9ea78fee264587a2 [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
Jack Jansen84872291996-10-22 15:33:02 +000017# Resource in the Python resource chain
18PREFNAME_NAME="PythonPreferenceFileName"
19
Jack Jansen7571f301995-07-29 13:48:41 +000020# resource IDs in our own resources (dialogs, etc)
21MESSAGE_ID = 256
22
Jack Jansen145c92d1996-10-11 11:30:26 +000023DIALOG_ID = 511
Jack Jansen7571f301995-07-29 13:48:41 +000024TEXT_ITEM = 1
25OK_ITEM = 2
26CANCEL_ITEM = 3
Jack Jansendb0bace1996-04-04 15:38:44 +000027DIR_ITEM = 4
28TITLE_ITEM = 5
Jack Jansen822a30b1996-04-10 14:52:18 +000029OPTIONS_ITEM = 7
30
31# The options dialog. There is a correspondence between
32# the dialog item numbers and the option.
Jack Jansen145c92d1996-10-11 11:30:26 +000033OPT_DIALOG_ID = 510
Jack Jansen6c4e9871996-09-06 22:25:34 +000034# 1 thru 9 are the options
35# The GUSI creator/type and delay-console
36OD_CREATOR_ITEM = 10
37OD_TYPE_ITEM = 11
38OD_DELAYCONSOLE_ITEM = 12
39OD_OK_ITEM = 13
40OD_CANCEL_ITEM = 14
Jack Jansen7571f301995-07-29 13:48:41 +000041
42# Resource IDs in the preferences file
43PATH_STRINGS_ID = 128
44DIRECTORY_ID = 128
Jack Jansendb0bace1996-04-04 15:38:44 +000045OPTIONS_ID = 128
Jack Jansen6c4e9871996-09-06 22:25:34 +000046GUSI_ID = 10240
Jack Jansen7571f301995-07-29 13:48:41 +000047
Jack Jansendb0bace1996-04-04 15:38:44 +000048# Override IDs (in the applet)
49OVERRIDE_PATH_STRINGS_ID = 129
50OVERRIDE_DIRECTORY_ID = 129
51OVERRIDE_OPTIONS_ID = 129
Jack Jansen10496eb1996-09-07 17:01:47 +000052OVERRIDE_GUSI_ID = 10241
Jack Jansen6c4e9871996-09-06 22:25:34 +000053
54# Things we know about the GUSI resource. Note the code knows these too.
55GUSIPOS_TYPE=0
56GUSIPOS_CREATOR=4
57GUSIPOS_SKIP=8
58GUSIPOS_FLAGS=9
Jack Jansen84872291996-10-22 15:33:02 +000059GUSIPOS_VERSION=10
60GUSIVERSION='0181'
61GUSIFLAGS_DELAY=0x20 # Mask
Jack Jansendb0bace1996-04-04 15:38:44 +000062
63READ = 1
Jack Jansen7571f301995-07-29 13:48:41 +000064WRITE = 2
65smAllScripts = -3
66kOnSystemDisk = 0x8000
67
68def 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
83def 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
90def message(str = "Hello, world!", id = MESSAGE_ID):
91 """Show a simple alert with a text message"""
92 d = GetNewDialog(id, -1)
Jack Jansen822a30b1996-04-10 14:52:18 +000093 d.SetDialogDefaultItem(1)
Jack Jansen7571f301995-07-29 13:48:41 +000094 tp, h, rect = d.GetDialogItem(2)
95 SetDialogItemText(h, str)
96 while 1:
97 n = ModalDialog(None)
98 if n == 1: break
99
Jack Jansen6c4e9871996-09-06 22:25:34 +0000100def optinteract((options, creator, type, delaycons)):
Jack Jansen822a30b1996-04-10 14:52:18 +0000101 """Let the user interact with the options dialog"""
Jack Jansen6c4e9871996-09-06 22:25:34 +0000102 old_options = (options[:], creator, type, delaycons)
Jack Jansen822a30b1996-04-10 14:52:18 +0000103 d = GetNewDialog(OPT_DIALOG_ID, -1)
Jack Jansen6c4e9871996-09-06 22:25:34 +0000104 tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
105 SetDialogItemText(h, creator)
106 tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
107 SetDialogItemText(h, type)
Jack Jansen822a30b1996-04-10 14:52:18 +0000108 d.SetDialogDefaultItem(OD_OK_ITEM)
109 d.SetDialogCancelItem(OD_CANCEL_ITEM)
110 while 1:
111 for i in range(len(options)):
112 tp, h, rect = d.GetDialogItem(i+1)
113 h.as_Control().SetControlValue(options[i])
Jack Jansen6c4e9871996-09-06 22:25:34 +0000114 tp, h, rect = d.GetDialogItem(OD_DELAYCONSOLE_ITEM)
115 h.as_Control().SetControlValue(delaycons)
Jack Jansen822a30b1996-04-10 14:52:18 +0000116 n = ModalDialog(None)
117 if n == OD_OK_ITEM:
Jack Jansen6c4e9871996-09-06 22:25:34 +0000118 tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
119 ncreator = GetDialogItemText(h)
120 tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
121 ntype = GetDialogItemText(h)
122 if len(ncreator) == 4 and len(ntype) == 4:
123 return options, ncreator, ntype, delaycons
124 else:
125 sys.stderr.write('\007')
Jack Jansen822a30b1996-04-10 14:52:18 +0000126 elif n == OD_CANCEL_ITEM:
127 return old_options
Jack Jansen6c4e9871996-09-06 22:25:34 +0000128 elif n in (OD_CREATOR_ITEM, OD_TYPE_ITEM):
129 pass
130 elif n == OD_DELAYCONSOLE_ITEM:
131 delaycons = (not delaycons)
Jack Jansen822a30b1996-04-10 14:52:18 +0000132 elif 1 <= n <= len(options):
133 options[n-1] = (not options[n-1])
134
135
136def interact(list, pythondir, options, title):
Jack Jansen7571f301995-07-29 13:48:41 +0000137 """Let the user interact with the dialog"""
138 opythondir = pythondir
139 try:
140 # Try to go to the "correct" dir for GetDirectory
141 os.chdir(pythondir.as_pathname())
142 except os.error:
143 pass
144 d = GetNewDialog(DIALOG_ID, -1)
Jack Jansendb0bace1996-04-04 15:38:44 +0000145 tp, h, rect = d.GetDialogItem(TITLE_ITEM)
146 SetDialogItemText(h, title)
147 tp, h, rect = d.GetDialogItem(TEXT_ITEM)
Jack Jansen7571f301995-07-29 13:48:41 +0000148 SetDialogItemText(h, string.joinfields(list, '\r'))
Jack Jansendb0bace1996-04-04 15:38:44 +0000149## d.SetDialogDefaultItem(OK_ITEM)
150 d.SetDialogCancelItem(CANCEL_ITEM)
Jack Jansen7571f301995-07-29 13:48:41 +0000151 while 1:
152 n = ModalDialog(None)
153 if n == OK_ITEM:
154 break
155 if n == CANCEL_ITEM:
156 return None
Jack Jansendb0bace1996-04-04 15:38:44 +0000157## if n == REVERT_ITEM:
158## return [], pythondir
Jack Jansen7571f301995-07-29 13:48:41 +0000159 if n == DIR_ITEM:
Jack Jansen9062fa21995-08-14 12:21:12 +0000160 fss, ok = macfs.GetDirectory('Select python home folder:')
Jack Jansen7571f301995-07-29 13:48:41 +0000161 if ok:
162 pythondir = fss
Jack Jansen822a30b1996-04-10 14:52:18 +0000163 if n == OPTIONS_ITEM:
164 options = optinteract(options)
Jack Jansen7571f301995-07-29 13:48:41 +0000165 tmp = string.splitfields(GetDialogItemText(h), '\r')
166 rv = []
167 for i in tmp:
168 if i:
169 rv.append(i)
Jack Jansen822a30b1996-04-10 14:52:18 +0000170 return rv, pythondir, options
Jack Jansen7571f301995-07-29 13:48:41 +0000171
Jack Jansendb0bace1996-04-04 15:38:44 +0000172def getprefpath(id):
173 # Load the path and directory resources
Jack Jansen7571f301995-07-29 13:48:41 +0000174 try:
Jack Jansendb0bace1996-04-04 15:38:44 +0000175 sr = GetResource('STR#', id)
176 except (MacOS.Error, Res.Error):
177 return None, None
178 d = sr.data
179 l = restolist(d)
180 return l, sr
181
182def getprefdir(id):
183 try:
184 dr = GetResource('alis', id)
185 fss, fss_changed = macfs.RawAlias(dr.data).Resolve()
186 except (MacOS.Error, Res.Error):
187 return None, None, 1
188 return fss, dr, fss_changed
Jack Jansen822a30b1996-04-10 14:52:18 +0000189
190def getoptions(id):
191 try:
192 opr = GetResource('Popt', id)
193 except (MacOS.Error, Res.Error):
Jack Jansen10496eb1996-09-07 17:01:47 +0000194 return [0]*9, None
195 options = map(lambda x: ord(x), opr.data)
196 while len(options) < 9:
197 options = options + [0]
198 return options, opr
Jack Jansen7571f301995-07-29 13:48:41 +0000199
Jack Jansen6c4e9871996-09-06 22:25:34 +0000200def getgusioptions(id):
201 try:
202 opr = GetResource('GU\267I', id)
203 except (MacOS.Error, Res.Error):
204 return '????', '????', 0, None
205 data = opr.data
206 type = data[GUSIPOS_TYPE:GUSIPOS_TYPE+4]
207 creator = data[GUSIPOS_CREATOR:GUSIPOS_CREATOR+4]
208 flags = ord(data[GUSIPOS_FLAGS])
Jack Jansen84872291996-10-22 15:33:02 +0000209 version = data[GUSIPOS_VERSION:GUSIPOS_VERSION+4]
210 if version <> GUSIVERSION:
211 message('GU\267I resource version "%s", fixing to "%s"'%(version, GUSIVERSION))
212 flags = 0
Jack Jansen6c4e9871996-09-06 22:25:34 +0000213 delay = (not not (flags & GUSIFLAGS_DELAY))
214 return creator, type, delay, opr
215
216def setgusioptions(opr, creator, type, delay):
217 data = opr.data
218 flags = ord(data[GUSIPOS_FLAGS])
Jack Jansen84872291996-10-22 15:33:02 +0000219 version = data[GUSIPOS_VERSION:GUSIPOS_VERSION+4]
220 if version <> GUSIVERSION:
221 flags = 0x88
222 version = GUSIVERSION
Jack Jansen6c4e9871996-09-06 22:25:34 +0000223 if delay:
224 flags = flags | GUSIFLAGS_DELAY
225 else:
226 flags = flags & ~GUSIFLAGS_DELAY
Jack Jansen84872291996-10-22 15:33:02 +0000227 data = type + creator + data[GUSIPOS_SKIP] + chr(flags) + GUSIVERSION + data[GUSIPOS_VERSION+4:]
Jack Jansen6c4e9871996-09-06 22:25:34 +0000228 return data
229
Jack Jansendb0bace1996-04-04 15:38:44 +0000230def openpreffile(rw):
Jack Jansen7571f301995-07-29 13:48:41 +0000231 # Find the preferences folder and our prefs file, create if needed.
232 vrefnum, dirid = macfs.FindFolder(kOnSystemDisk, 'pref', 0)
Jack Jansen84872291996-10-22 15:33:02 +0000233 try:
234 pnhandle = GetNamedResource('STR ', PREFNAME_NAME)
235 except Res.Error:
236 message("No %s resource (old Python?)"%PREFNAME_NAME)
237 sys.exit(1)
238 prefname = pnhandle.data[1:]
239 preff_fss = macfs.FSSpec((vrefnum, dirid, prefname))
Jack Jansen7571f301995-07-29 13:48:41 +0000240 try:
Jack Jansendb0bace1996-04-04 15:38:44 +0000241 preff_handle = FSpOpenResFile(preff_fss, rw)
Jack Jansen7571f301995-07-29 13:48:41 +0000242 except Res.Error:
243 # Create it
244 message('No preferences file, creating one...')
Jack Jansen532e3c21996-02-21 15:36:26 +0000245 FSpCreateResFile(preff_fss, 'Pyth', 'pref', smAllScripts)
Jack Jansendb0bace1996-04-04 15:38:44 +0000246 preff_handle = FSpOpenResFile(preff_fss, rw)
247 return preff_handle
248
249def openapplet(name):
250 fss = macfs.FSSpec(name)
Jack Jansen7571f301995-07-29 13:48:41 +0000251 try:
Jack Jansendb0bace1996-04-04 15:38:44 +0000252 app_handle = FSpOpenResFile(fss, WRITE)
253 except Res.Error:
254 message('File does not have a resource fork.')
255 sys.exit(0)
256 return app_handle
257
258
259def edit_preferences():
260 preff_handle = openpreffile(WRITE)
261
262 l, sr = getprefpath(PATH_STRINGS_ID)
263 if l == None:
Jack Jansen7571f301995-07-29 13:48:41 +0000264 message('Cannot find any sys.path resource! (Old python?)')
265 sys.exit(0)
Jack Jansendb0bace1996-04-04 15:38:44 +0000266
267 fss, dr, fss_changed = getprefdir(DIRECTORY_ID)
268 if fss == None:
Jack Jansen7571f301995-07-29 13:48:41 +0000269 fss = macfs.FSSpec(os.getcwd())
270 fss_changed = 1
Jack Jansen822a30b1996-04-10 14:52:18 +0000271
272 options, opr = getoptions(OPTIONS_ID)
273 saved_options = options[:]
Jack Jansen7571f301995-07-29 13:48:41 +0000274
Jack Jansen6c4e9871996-09-06 22:25:34 +0000275 creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
276 saved_gusi_options = creator, type, delaycons
277
Jack Jansen7571f301995-07-29 13:48:41 +0000278 # Let the user play away
Jack Jansen6c4e9871996-09-06 22:25:34 +0000279 result = interact(l, fss, (options, creator, type, delaycons),
280 'System-wide preferences')
Jack Jansen7571f301995-07-29 13:48:41 +0000281
282 # See what we have to update, and how
283 if result == None:
284 sys.exit(0)
285
Jack Jansen6c4e9871996-09-06 22:25:34 +0000286 pathlist, nfss, (options, creator, type, delaycons) = result
Jack Jansen7571f301995-07-29 13:48:41 +0000287 if nfss != fss:
288 fss_changed = 1
289
Jack Jansen822a30b1996-04-10 14:52:18 +0000290 if fss_changed:
291 alias = nfss.NewAlias()
292 if dr:
293 dr.data = alias.data
294 dr.ChangedResource()
295 else:
296 dr = Resource(alias.data)
297 dr.AddResource('alis', DIRECTORY_ID, '')
298
299 if pathlist != l:
300 if pathlist == []:
301 if sr.HomeResFile() == preff_handle:
302 sr.RemoveResource()
303 elif sr.HomeResFile() == preff_handle:
304 sr.data = listtores(pathlist)
305 sr.ChangedResource()
306 else:
307 sr = Resource(listtores(pathlist))
308 sr.AddResource('STR#', PATH_STRINGS_ID, '')
309
310 if options != saved_options:
311 newdata = reduce(lambda x, y: x+chr(y), options, '')
312 if opr and opr.HomeResFile() == preff_handle:
313 opr.data = newdata
314 opr.ChangedResource()
315 else:
316 opr = Resource(newdata)
317 opr.AddResource('Popt', OPTIONS_ID, '')
Jack Jansen6c4e9871996-09-06 22:25:34 +0000318
319 if (creator, type, delaycons) != saved_gusi_options:
320 newdata = setgusioptions(gusi_opr, creator, type, delaycons)
321 if gusi_opr.HomeResFile() == preff_handle:
322 gusi_opr.data = newdata
323 gusi_opr.ChangedResource()
324 else:
Jack Jansen10496eb1996-09-07 17:01:47 +0000325 ngusi_opr = Resource(newdata)
Jack Jansen6c4e9871996-09-06 22:25:34 +0000326 ngusi_opr.AddResource('GU\267I', GUSI_ID, '')
Jack Jansen7571f301995-07-29 13:48:41 +0000327
328 CloseResFile(preff_handle)
Jack Jansendb0bace1996-04-04 15:38:44 +0000329
330def edit_applet(name):
331 pref_handle = openpreffile(READ)
332 app_handle = openapplet(name)
333
334 notfound = ''
335 l, sr = getprefpath(OVERRIDE_PATH_STRINGS_ID)
336 if l == None:
337 notfound = 'path'
338
339 l, dummy = getprefpath(PATH_STRINGS_ID)
340 if l == None:
341 message('Cannot find any sys.path resource! (Old python?)')
342 sys.exit(0)
343
344 fss, dr, fss_changed = getprefdir(OVERRIDE_DIRECTORY_ID)
345 if fss == None:
346 if notfound:
Jack Jansen822a30b1996-04-10 14:52:18 +0000347 notfound = notfound + ', directory'
Jack Jansendb0bace1996-04-04 15:38:44 +0000348 else:
349 notfound = 'directory'
350 fss, dummy, dummy2 = getprefdir(DIRECTORY_ID)
351 if fss == None:
352 fss = macfs.FSSpec(os.getcwd())
353 fss_changed = 1
Jack Jansen822a30b1996-04-10 14:52:18 +0000354
355 options, opr = getoptions(OVERRIDE_OPTIONS_ID)
356 if not opr:
357 if notfound:
358 notfound = notfound + ', options'
359 else:
360 notfound = 'options'
361 options, dummy = getoptions(OPTIONS_ID)
362 saved_options = options[:]
Jack Jansendb0bace1996-04-04 15:38:44 +0000363
Jack Jansen6c4e9871996-09-06 22:25:34 +0000364 creator, type, delaycons, gusi_opr = getgusioptions(OVERRIDE_GUSI_ID)
Jack Jansen10496eb1996-09-07 17:01:47 +0000365 if not gusi_opr:
Jack Jansen6c4e9871996-09-06 22:25:34 +0000366 if notfound:
367 notfound = notfound + ', GUSI options'
368 else:
369 notfound = 'GUSI options'
Jack Jansen10496eb1996-09-07 17:01:47 +0000370 creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
Jack Jansen6c4e9871996-09-06 22:25:34 +0000371 saved_gusi_options = creator, type, delaycons
372
Jack Jansendb0bace1996-04-04 15:38:44 +0000373 dummy = dummy2 = None # Discard them.
374
375 if notfound:
376 message('Warning: initial %s taken from system-wide defaults'%notfound)
377 # Let the user play away
Jack Jansen145c92d1996-10-11 11:30:26 +0000378 print 'DBG interaction'
Jack Jansen6c4e9871996-09-06 22:25:34 +0000379 result = interact(l, fss, (options, creator, type, delaycons), name)
Jack Jansendb0bace1996-04-04 15:38:44 +0000380
381 # See what we have to update, and how
382 if result == None:
383 sys.exit(0)
384
Jack Jansen10496eb1996-09-07 17:01:47 +0000385 pathlist, nfss, (options, creator, type, delaycons) = result
Jack Jansendb0bace1996-04-04 15:38:44 +0000386 if nfss != fss:
387 fss_changed = 1
388
Jack Jansen822a30b1996-04-10 14:52:18 +0000389 if fss_changed:
390 alias = nfss.NewAlias()
391 if dr:
392 dr.data = alias.data
393 dr.ChangedResource()
394 else:
395 dr = Resource(alias.data)
396 dr.AddResource('alis', OVERRIDE_DIRECTORY_ID, '')
397
398 if pathlist != l:
399 if pathlist == []:
400 if sr.HomeResFile() == app_handle:
401 sr.RemoveResource()
402 elif sr and sr.HomeResFile() == app_handle:
403 sr.data = listtores(pathlist)
404 sr.ChangedResource()
405 else:
406 sr = Resource(listtores(pathlist))
407 sr.AddResource('STR#', OVERRIDE_PATH_STRINGS_ID, '')
408
409 if options != saved_options:
410 newdata = reduce(lambda x, y: x+chr(y), options, '')
411 if opr and opr.HomeResFile() == app_handle:
412 opr.data = newdata
413 opr.ChangedResource()
414 else:
415 opr = Resource(newdata)
416 opr.AddResource('Popt', OVERRIDE_OPTIONS_ID, '')
Jack Jansen6c4e9871996-09-06 22:25:34 +0000417
418 if (creator, type, delaycons) != saved_gusi_options:
419 newdata = setgusioptions(gusi_opr, creator, type, delaycons)
Jack Jansen10496eb1996-09-07 17:01:47 +0000420 id, type, name = gusi_opr.GetResInfo()
421 if gusi_opr.HomeResFile() == app_handle and id == OVERRIDE_GUSI_ID:
Jack Jansen6c4e9871996-09-06 22:25:34 +0000422 gusi_opr.data = newdata
423 gusi_opr.ChangedResource()
424 else:
Jack Jansen10496eb1996-09-07 17:01:47 +0000425 ngusi_opr = Resource(newdata)
426 ngusi_opr.AddResource('GU\267I', OVERRIDE_GUSI_ID, '')
Jack Jansen6c4e9871996-09-06 22:25:34 +0000427
Jack Jansendb0bace1996-04-04 15:38:44 +0000428 CloseResFile(app_handle)
429
430def main():
431 try:
432 h = OpenResFile('EditPythonPrefs.rsrc')
433 except Res.Error:
434 pass # Assume we already have acces to our own resource
435
436 if len(sys.argv) <= 1:
437 edit_preferences()
438 else:
439 for appl in sys.argv[1:]:
440 edit_applet(appl)
441
Jack Jansen7571f301995-07-29 13:48:41 +0000442
443if __name__ == '__main__':
Jack Jansen7571f301995-07-29 13:48:41 +0000444 main()