blob: 3d7becead17e28ee592e4ec8532defd1d0c7e355 [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 Jansen10496eb1996-09-07 17:01:47 +000049OVERRIDE_GUSI_ID = 10241
Jack Jansen6c4e9871996-09-06 22:25:34 +000050
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 tp, h, rect = d.GetDialogItem(2)
90 SetDialogItemText(h, str)
91 while 1:
92 n = ModalDialog(None)
93 if n == 1: break
94
Jack Jansen6c4e9871996-09-06 22:25:34 +000095def optinteract((options, creator, type, delaycons)):
Jack Jansen822a30b1996-04-10 14:52:18 +000096 """Let the user interact with the options dialog"""
Jack Jansen6c4e9871996-09-06 22:25:34 +000097 old_options = (options[:], creator, type, delaycons)
Jack Jansen822a30b1996-04-10 14:52:18 +000098 d = GetNewDialog(OPT_DIALOG_ID, -1)
Jack Jansen6c4e9871996-09-06 22:25:34 +000099 tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
100 SetDialogItemText(h, creator)
101 tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
102 SetDialogItemText(h, type)
Jack Jansen822a30b1996-04-10 14:52:18 +0000103 d.SetDialogDefaultItem(OD_OK_ITEM)
104 d.SetDialogCancelItem(OD_CANCEL_ITEM)
105 while 1:
106 for i in range(len(options)):
107 tp, h, rect = d.GetDialogItem(i+1)
108 h.as_Control().SetControlValue(options[i])
Jack Jansen6c4e9871996-09-06 22:25:34 +0000109 tp, h, rect = d.GetDialogItem(OD_DELAYCONSOLE_ITEM)
110 h.as_Control().SetControlValue(delaycons)
Jack Jansen822a30b1996-04-10 14:52:18 +0000111 n = ModalDialog(None)
112 if n == OD_OK_ITEM:
Jack Jansen6c4e9871996-09-06 22:25:34 +0000113 tp, h, rect = d.GetDialogItem(OD_CREATOR_ITEM)
114 ncreator = GetDialogItemText(h)
115 tp, h, rect = d.GetDialogItem(OD_TYPE_ITEM)
116 ntype = GetDialogItemText(h)
117 if len(ncreator) == 4 and len(ntype) == 4:
118 return options, ncreator, ntype, delaycons
119 else:
120 sys.stderr.write('\007')
Jack Jansen822a30b1996-04-10 14:52:18 +0000121 elif n == OD_CANCEL_ITEM:
122 return old_options
Jack Jansen6c4e9871996-09-06 22:25:34 +0000123 elif n in (OD_CREATOR_ITEM, OD_TYPE_ITEM):
124 pass
125 elif n == OD_DELAYCONSOLE_ITEM:
126 delaycons = (not delaycons)
Jack Jansen822a30b1996-04-10 14:52:18 +0000127 elif 1 <= n <= len(options):
128 options[n-1] = (not options[n-1])
129
130
131def interact(list, pythondir, options, title):
Jack Jansen7571f301995-07-29 13:48:41 +0000132 """Let the user interact with the dialog"""
133 opythondir = pythondir
134 try:
135 # Try to go to the "correct" dir for GetDirectory
136 os.chdir(pythondir.as_pathname())
137 except os.error:
138 pass
139 d = GetNewDialog(DIALOG_ID, -1)
Jack Jansendb0bace1996-04-04 15:38:44 +0000140 tp, h, rect = d.GetDialogItem(TITLE_ITEM)
141 SetDialogItemText(h, title)
142 tp, h, rect = d.GetDialogItem(TEXT_ITEM)
Jack Jansen7571f301995-07-29 13:48:41 +0000143 SetDialogItemText(h, string.joinfields(list, '\r'))
Jack Jansendb0bace1996-04-04 15:38:44 +0000144## d.SetDialogDefaultItem(OK_ITEM)
145 d.SetDialogCancelItem(CANCEL_ITEM)
Jack Jansen7571f301995-07-29 13:48:41 +0000146 while 1:
147 n = ModalDialog(None)
148 if n == OK_ITEM:
149 break
150 if n == CANCEL_ITEM:
151 return None
Jack Jansendb0bace1996-04-04 15:38:44 +0000152## if n == REVERT_ITEM:
153## return [], pythondir
Jack Jansen7571f301995-07-29 13:48:41 +0000154 if n == DIR_ITEM:
Jack Jansen9062fa21995-08-14 12:21:12 +0000155 fss, ok = macfs.GetDirectory('Select python home folder:')
Jack Jansen7571f301995-07-29 13:48:41 +0000156 if ok:
157 pythondir = fss
Jack Jansen822a30b1996-04-10 14:52:18 +0000158 if n == OPTIONS_ITEM:
159 options = optinteract(options)
Jack Jansen7571f301995-07-29 13:48:41 +0000160 tmp = string.splitfields(GetDialogItemText(h), '\r')
161 rv = []
162 for i in tmp:
163 if i:
164 rv.append(i)
Jack Jansen822a30b1996-04-10 14:52:18 +0000165 return rv, pythondir, options
Jack Jansen7571f301995-07-29 13:48:41 +0000166
Jack Jansendb0bace1996-04-04 15:38:44 +0000167def getprefpath(id):
168 # Load the path and directory resources
Jack Jansen7571f301995-07-29 13:48:41 +0000169 try:
Jack Jansendb0bace1996-04-04 15:38:44 +0000170 sr = GetResource('STR#', id)
171 except (MacOS.Error, Res.Error):
172 return None, None
173 d = sr.data
174 l = restolist(d)
175 return l, sr
176
177def getprefdir(id):
178 try:
179 dr = GetResource('alis', id)
180 fss, fss_changed = macfs.RawAlias(dr.data).Resolve()
181 except (MacOS.Error, Res.Error):
182 return None, None, 1
183 return fss, dr, fss_changed
Jack Jansen822a30b1996-04-10 14:52:18 +0000184
185def getoptions(id):
186 try:
187 opr = GetResource('Popt', id)
188 except (MacOS.Error, Res.Error):
Jack Jansen10496eb1996-09-07 17:01:47 +0000189 return [0]*9, None
190 options = map(lambda x: ord(x), opr.data)
191 while len(options) < 9:
192 options = options + [0]
193 return options, opr
Jack Jansen7571f301995-07-29 13:48:41 +0000194
Jack Jansen6c4e9871996-09-06 22:25:34 +0000195def getgusioptions(id):
196 try:
197 opr = GetResource('GU\267I', id)
198 except (MacOS.Error, Res.Error):
199 return '????', '????', 0, None
200 data = opr.data
201 type = data[GUSIPOS_TYPE:GUSIPOS_TYPE+4]
202 creator = data[GUSIPOS_CREATOR:GUSIPOS_CREATOR+4]
203 flags = ord(data[GUSIPOS_FLAGS])
204 delay = (not not (flags & GUSIFLAGS_DELAY))
205 return creator, type, delay, opr
206
207def setgusioptions(opr, creator, type, delay):
208 data = opr.data
209 flags = ord(data[GUSIPOS_FLAGS])
210 if delay:
211 flags = flags | GUSIFLAGS_DELAY
212 else:
213 flags = flags & ~GUSIFLAGS_DELAY
214 data = type + creator + data[GUSIPOS_SKIP] + chr(flags) + data[GUSIPOS_FLAGS+1:]
215 return data
216
Jack Jansendb0bace1996-04-04 15:38:44 +0000217def openpreffile(rw):
Jack Jansen7571f301995-07-29 13:48:41 +0000218 # Find the preferences folder and our prefs file, create if needed.
219 vrefnum, dirid = macfs.FindFolder(kOnSystemDisk, 'pref', 0)
220 preff_fss = macfs.FSSpec((vrefnum, dirid, 'Python Preferences'))
221 try:
Jack Jansendb0bace1996-04-04 15:38:44 +0000222 preff_handle = FSpOpenResFile(preff_fss, rw)
Jack Jansen7571f301995-07-29 13:48:41 +0000223 except Res.Error:
224 # Create it
225 message('No preferences file, creating one...')
Jack Jansen532e3c21996-02-21 15:36:26 +0000226 FSpCreateResFile(preff_fss, 'Pyth', 'pref', smAllScripts)
Jack Jansendb0bace1996-04-04 15:38:44 +0000227 preff_handle = FSpOpenResFile(preff_fss, rw)
228 return preff_handle
229
230def openapplet(name):
231 fss = macfs.FSSpec(name)
Jack Jansen7571f301995-07-29 13:48:41 +0000232 try:
Jack Jansendb0bace1996-04-04 15:38:44 +0000233 app_handle = FSpOpenResFile(fss, WRITE)
234 except Res.Error:
235 message('File does not have a resource fork.')
236 sys.exit(0)
237 return app_handle
238
239
240def edit_preferences():
241 preff_handle = openpreffile(WRITE)
242
243 l, sr = getprefpath(PATH_STRINGS_ID)
244 if l == None:
Jack Jansen7571f301995-07-29 13:48:41 +0000245 message('Cannot find any sys.path resource! (Old python?)')
246 sys.exit(0)
Jack Jansendb0bace1996-04-04 15:38:44 +0000247
248 fss, dr, fss_changed = getprefdir(DIRECTORY_ID)
249 if fss == None:
Jack Jansen7571f301995-07-29 13:48:41 +0000250 fss = macfs.FSSpec(os.getcwd())
251 fss_changed = 1
Jack Jansen822a30b1996-04-10 14:52:18 +0000252
253 options, opr = getoptions(OPTIONS_ID)
254 saved_options = options[:]
Jack Jansen7571f301995-07-29 13:48:41 +0000255
Jack Jansen6c4e9871996-09-06 22:25:34 +0000256 creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
257 saved_gusi_options = creator, type, delaycons
258
Jack Jansen7571f301995-07-29 13:48:41 +0000259 # Let the user play away
Jack Jansen6c4e9871996-09-06 22:25:34 +0000260 result = interact(l, fss, (options, creator, type, delaycons),
261 'System-wide preferences')
Jack Jansen7571f301995-07-29 13:48:41 +0000262
263 # See what we have to update, and how
264 if result == None:
265 sys.exit(0)
266
Jack Jansen6c4e9871996-09-06 22:25:34 +0000267 pathlist, nfss, (options, creator, type, delaycons) = result
Jack Jansen7571f301995-07-29 13:48:41 +0000268 if nfss != fss:
269 fss_changed = 1
270
Jack Jansen822a30b1996-04-10 14:52:18 +0000271 if fss_changed:
272 alias = nfss.NewAlias()
273 if dr:
274 dr.data = alias.data
275 dr.ChangedResource()
276 else:
277 dr = Resource(alias.data)
278 dr.AddResource('alis', DIRECTORY_ID, '')
279
280 if pathlist != l:
281 if pathlist == []:
282 if sr.HomeResFile() == preff_handle:
283 sr.RemoveResource()
284 elif sr.HomeResFile() == preff_handle:
285 sr.data = listtores(pathlist)
286 sr.ChangedResource()
287 else:
288 sr = Resource(listtores(pathlist))
289 sr.AddResource('STR#', PATH_STRINGS_ID, '')
290
291 if options != saved_options:
292 newdata = reduce(lambda x, y: x+chr(y), options, '')
293 if opr and opr.HomeResFile() == preff_handle:
294 opr.data = newdata
295 opr.ChangedResource()
296 else:
297 opr = Resource(newdata)
298 opr.AddResource('Popt', OPTIONS_ID, '')
Jack Jansen6c4e9871996-09-06 22:25:34 +0000299
300 if (creator, type, delaycons) != saved_gusi_options:
301 newdata = setgusioptions(gusi_opr, creator, type, delaycons)
302 if gusi_opr.HomeResFile() == preff_handle:
303 gusi_opr.data = newdata
304 gusi_opr.ChangedResource()
305 else:
Jack Jansen10496eb1996-09-07 17:01:47 +0000306 ngusi_opr = Resource(newdata)
Jack Jansen6c4e9871996-09-06 22:25:34 +0000307 ngusi_opr.AddResource('GU\267I', GUSI_ID, '')
Jack Jansen7571f301995-07-29 13:48:41 +0000308
309 CloseResFile(preff_handle)
Jack Jansendb0bace1996-04-04 15:38:44 +0000310
311def edit_applet(name):
312 pref_handle = openpreffile(READ)
313 app_handle = openapplet(name)
314
315 notfound = ''
316 l, sr = getprefpath(OVERRIDE_PATH_STRINGS_ID)
317 if l == None:
318 notfound = 'path'
319
320 l, dummy = getprefpath(PATH_STRINGS_ID)
321 if l == None:
322 message('Cannot find any sys.path resource! (Old python?)')
323 sys.exit(0)
324
325 fss, dr, fss_changed = getprefdir(OVERRIDE_DIRECTORY_ID)
326 if fss == None:
327 if notfound:
Jack Jansen822a30b1996-04-10 14:52:18 +0000328 notfound = notfound + ', directory'
Jack Jansendb0bace1996-04-04 15:38:44 +0000329 else:
330 notfound = 'directory'
331 fss, dummy, dummy2 = getprefdir(DIRECTORY_ID)
332 if fss == None:
333 fss = macfs.FSSpec(os.getcwd())
334 fss_changed = 1
Jack Jansen822a30b1996-04-10 14:52:18 +0000335
336 options, opr = getoptions(OVERRIDE_OPTIONS_ID)
337 if not opr:
338 if notfound:
339 notfound = notfound + ', options'
340 else:
341 notfound = 'options'
342 options, dummy = getoptions(OPTIONS_ID)
343 saved_options = options[:]
Jack Jansendb0bace1996-04-04 15:38:44 +0000344
Jack Jansen6c4e9871996-09-06 22:25:34 +0000345 creator, type, delaycons, gusi_opr = getgusioptions(OVERRIDE_GUSI_ID)
Jack Jansen10496eb1996-09-07 17:01:47 +0000346 if not gusi_opr:
Jack Jansen6c4e9871996-09-06 22:25:34 +0000347 if notfound:
348 notfound = notfound + ', GUSI options'
349 else:
350 notfound = 'GUSI options'
Jack Jansen10496eb1996-09-07 17:01:47 +0000351 creator, type, delaycons, gusi_opr = getgusioptions(GUSI_ID)
Jack Jansen6c4e9871996-09-06 22:25:34 +0000352 saved_gusi_options = creator, type, delaycons
353
Jack Jansendb0bace1996-04-04 15:38:44 +0000354 dummy = dummy2 = None # Discard them.
355
356 if notfound:
357 message('Warning: initial %s taken from system-wide defaults'%notfound)
358 # Let the user play away
Jack Jansen6c4e9871996-09-06 22:25:34 +0000359 result = interact(l, fss, (options, creator, type, delaycons), name)
Jack Jansendb0bace1996-04-04 15:38:44 +0000360
361 # See what we have to update, and how
362 if result == None:
363 sys.exit(0)
364
Jack Jansen10496eb1996-09-07 17:01:47 +0000365 pathlist, nfss, (options, creator, type, delaycons) = result
Jack Jansendb0bace1996-04-04 15:38:44 +0000366 if nfss != fss:
367 fss_changed = 1
368
Jack Jansen822a30b1996-04-10 14:52:18 +0000369 if fss_changed:
370 alias = nfss.NewAlias()
371 if dr:
372 dr.data = alias.data
373 dr.ChangedResource()
374 else:
375 dr = Resource(alias.data)
376 dr.AddResource('alis', OVERRIDE_DIRECTORY_ID, '')
377
378 if pathlist != l:
379 if pathlist == []:
380 if sr.HomeResFile() == app_handle:
381 sr.RemoveResource()
382 elif sr and sr.HomeResFile() == app_handle:
383 sr.data = listtores(pathlist)
384 sr.ChangedResource()
385 else:
386 sr = Resource(listtores(pathlist))
387 sr.AddResource('STR#', OVERRIDE_PATH_STRINGS_ID, '')
388
389 if options != saved_options:
390 newdata = reduce(lambda x, y: x+chr(y), options, '')
391 if opr and opr.HomeResFile() == app_handle:
392 opr.data = newdata
393 opr.ChangedResource()
394 else:
395 opr = Resource(newdata)
396 opr.AddResource('Popt', OVERRIDE_OPTIONS_ID, '')
Jack Jansen6c4e9871996-09-06 22:25:34 +0000397
398 if (creator, type, delaycons) != saved_gusi_options:
399 newdata = setgusioptions(gusi_opr, creator, type, delaycons)
Jack Jansen10496eb1996-09-07 17:01:47 +0000400 id, type, name = gusi_opr.GetResInfo()
401 if gusi_opr.HomeResFile() == app_handle and id == OVERRIDE_GUSI_ID:
Jack Jansen6c4e9871996-09-06 22:25:34 +0000402 gusi_opr.data = newdata
403 gusi_opr.ChangedResource()
404 else:
Jack Jansen10496eb1996-09-07 17:01:47 +0000405 ngusi_opr = Resource(newdata)
406 ngusi_opr.AddResource('GU\267I', OVERRIDE_GUSI_ID, '')
Jack Jansen6c4e9871996-09-06 22:25:34 +0000407
Jack Jansendb0bace1996-04-04 15:38:44 +0000408 CloseResFile(app_handle)
409
410def main():
411 try:
412 h = OpenResFile('EditPythonPrefs.rsrc')
413 except Res.Error:
414 pass # Assume we already have acces to our own resource
415
416 if len(sys.argv) <= 1:
417 edit_preferences()
418 else:
419 for appl in sys.argv[1:]:
420 edit_applet(appl)
421
Jack Jansen7571f301995-07-29 13:48:41 +0000422
423if __name__ == '__main__':
Jack Jansen7571f301995-07-29 13:48:41 +0000424 main()