1"""Easy to use dialogs.
2
3Message(msg) -- display a message and an OK button.
4AskString(prompt, default) -- ask for a string, display OK and Cancel buttons.
5AskPassword(prompt, default) -- like AskString(), but shows text as bullets.
6AskYesNoCancel(question, default) -- display a question and Yes, No and Cancel buttons.
7GetArgv(optionlist, commandlist) -- fill a sys.argv-like list using a dialog
8AskFileForOpen(...) -- Ask the user for an existing file
9AskFileForSave(...) -- Ask the user for an output file
10AskFolder(...) -- Ask the user to select a folder
11bar = Progress(label, maxvalue) -- Display a progress bar
12bar.set(value) -- Set value
13bar.inc( *amount ) -- increment value by amount (default=1)
14bar.label( *newlabel ) -- get or set text label.
15
16More documentation in each function.
17This module uses DLOG resources 260 and on.
18Based upon STDWIN dialogs with the same names and functions.
19"""
20
21from warnings import warnpy3k
22warnpy3k("In 3.x, the EasyDialogs module is removed.", stacklevel=2)
23
24from Carbon.Dlg import GetNewDialog, SetDialogItemText, GetDialogItemText, ModalDialog
25from Carbon import Qd
26from Carbon import QuickDraw
27from Carbon import Dialogs
28from Carbon import Windows
29from Carbon import Dlg,Win,Evt,Events # sdm7g
30from Carbon import Ctl
31from Carbon import Controls
32from Carbon import Menu
33from Carbon import AE
34import Nav
35import MacOS
36import string
37from Carbon.ControlAccessor import *    # Also import Controls constants
38import Carbon.File
39import macresource
40import os
41import sys
42
43__all__ = ['Message', 'AskString', 'AskPassword', 'AskYesNoCancel',
44    'GetArgv', 'AskFileForOpen', 'AskFileForSave', 'AskFolder',
45    'ProgressBar']
46
47_initialized = 0
48
49def _initialize():
50    global _initialized
51    if _initialized: return
52    macresource.need("DLOG", 260, "dialogs.rsrc", __name__)
53
54def _interact():
55    """Make sure the application is in the foreground"""
56    AE.AEInteractWithUser(50000000)
57
58def cr2lf(text):
59    if '\r' in text:
60        text = string.join(string.split(text, '\r'), '\n')
61    return text
62
63def lf2cr(text):
64    if '\n' in text:
65        text = string.join(string.split(text, '\n'), '\r')
66    if len(text) > 253:
67        text = text[:253] + '\311'
68    return text
69
70def Message(msg, id=260, ok=None):
71    """Display a MESSAGE string.
72
73    Return when the user clicks the OK button or presses Return.
74
75    The MESSAGE string can be at most 255 characters long.
76    """
77    _initialize()
78    _interact()
79    d = GetNewDialog(id, -1)
80    if not d:
81        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
82        return
83    h = d.GetDialogItemAsControl(2)
84    SetDialogItemText(h, lf2cr(msg))
85    if ok is not None:
86        h = d.GetDialogItemAsControl(1)
87        h.SetControlTitle(ok)
88    d.SetDialogDefaultItem(1)
89    d.AutoSizeDialog()
90    d.GetDialogWindow().ShowWindow()
91    while 1:
92        n = ModalDialog(None)
93        if n == 1:
94            return
95
96
97def AskString(prompt, default = "", id=261, ok=None, cancel=None):
98    """Display a PROMPT string and a text entry field with a DEFAULT string.
99
100    Return the contents of the text entry field when the user clicks the
101    OK button or presses Return.
102    Return None when the user clicks the Cancel button.
103
104    If omitted, DEFAULT is empty.
105
106    The PROMPT and DEFAULT strings, as well as the return value,
107    can be at most 255 characters long.
108    """
109
110    _initialize()
111    _interact()
112    d = GetNewDialog(id, -1)
113    if not d:
114        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
115        return
116    h = d.GetDialogItemAsControl(3)
117    SetDialogItemText(h, lf2cr(prompt))
118    h = d.GetDialogItemAsControl(4)
119    SetDialogItemText(h, lf2cr(default))
120    d.SelectDialogItemText(4, 0, 999)
121#       d.SetDialogItem(4, 0, 255)
122    if ok is not None:
123        h = d.GetDialogItemAsControl(1)
124        h.SetControlTitle(ok)
125    if cancel is not None:
126        h = d.GetDialogItemAsControl(2)
127        h.SetControlTitle(cancel)
128    d.SetDialogDefaultItem(1)
129    d.SetDialogCancelItem(2)
130    d.AutoSizeDialog()
131    d.GetDialogWindow().ShowWindow()
132    while 1:
133        n = ModalDialog(None)
134        if n == 1:
135            h = d.GetDialogItemAsControl(4)
136            return cr2lf(GetDialogItemText(h))
137        if n == 2: return None
138
139def AskPassword(prompt,  default='', id=264, ok=None, cancel=None):
140    """Display a PROMPT string and a text entry field with a DEFAULT string.
141    The string is displayed as bullets only.
142
143    Return the contents of the text entry field when the user clicks the
144    OK button or presses Return.
145    Return None when the user clicks the Cancel button.
146
147    If omitted, DEFAULT is empty.
148
149    The PROMPT and DEFAULT strings, as well as the return value,
150    can be at most 255 characters long.
151    """
152    _initialize()
153    _interact()
154    d = GetNewDialog(id, -1)
155    if not d:
156        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
157        return
158    h = d.GetDialogItemAsControl(3)
159    SetDialogItemText(h, lf2cr(prompt))
160    pwd = d.GetDialogItemAsControl(4)
161    bullets = '\245'*len(default)
162##      SetControlData(pwd, kControlEditTextPart, kControlEditTextTextTag, bullets)
163    SetControlData(pwd, kControlEditTextPart, kControlEditTextPasswordTag, default)
164    d.SelectDialogItemText(4, 0, 999)
165    Ctl.SetKeyboardFocus(d.GetDialogWindow(), pwd, kControlEditTextPart)
166    if ok is not None:
167        h = d.GetDialogItemAsControl(1)
168        h.SetControlTitle(ok)
169    if cancel is not None:
170        h = d.GetDialogItemAsControl(2)
171        h.SetControlTitle(cancel)
172    d.SetDialogDefaultItem(Dialogs.ok)
173    d.SetDialogCancelItem(Dialogs.cancel)
174    d.AutoSizeDialog()
175    d.GetDialogWindow().ShowWindow()
176    while 1:
177        n = ModalDialog(None)
178        if n == 1:
179            h = d.GetDialogItemAsControl(4)
180            return cr2lf(GetControlData(pwd, kControlEditTextPart, kControlEditTextPasswordTag))
181        if n == 2: return None
182
183def AskYesNoCancel(question, default = 0, yes=None, no=None, cancel=None, id=262):
184    """Display a QUESTION string which can be answered with Yes or No.
185
186    Return 1 when the user clicks the Yes button.
187    Return 0 when the user clicks the No button.
188    Return -1 when the user clicks the Cancel button.
189
190    When the user presses Return, the DEFAULT value is returned.
191    If omitted, this is 0 (No).
192
193    The QUESTION string can be at most 255 characters.
194    """
195
196    _initialize()
197    _interact()
198    d = GetNewDialog(id, -1)
199    if not d:
200        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
201        return
202    # Button assignments:
203    # 1 = default (invisible)
204    # 2 = Yes
205    # 3 = No
206    # 4 = Cancel
207    # The question string is item 5
208    h = d.GetDialogItemAsControl(5)
209    SetDialogItemText(h, lf2cr(question))
210    if yes is not None:
211        if yes == '':
212            d.HideDialogItem(2)
213        else:
214            h = d.GetDialogItemAsControl(2)
215            h.SetControlTitle(yes)
216    if no is not None:
217        if no == '':
218            d.HideDialogItem(3)
219        else:
220            h = d.GetDialogItemAsControl(3)
221            h.SetControlTitle(no)
222    if cancel is not None:
223        if cancel == '':
224            d.HideDialogItem(4)
225        else:
226            h = d.GetDialogItemAsControl(4)
227            h.SetControlTitle(cancel)
228    d.SetDialogCancelItem(4)
229    if default == 1:
230        d.SetDialogDefaultItem(2)
231    elif default == 0:
232        d.SetDialogDefaultItem(3)
233    elif default == -1:
234        d.SetDialogDefaultItem(4)
235    d.AutoSizeDialog()
236    d.GetDialogWindow().ShowWindow()
237    while 1:
238        n = ModalDialog(None)
239        if n == 1: return default
240        if n == 2: return 1
241        if n == 3: return 0
242        if n == 4: return -1
243
244
245
246# The deprecated Carbon QuickDraw APIs are no longer available as of
247# OS X 10.8.  Raise an ImportError here in that case so that callers
248# of EasyDialogs, like BuildApplet, will do the right thing.
249
250try:
251    screenbounds = Qd.GetQDGlobalsScreenBits().bounds
252except AttributeError:
253    raise ImportError("QuickDraw APIs not available")
254
255screenbounds = screenbounds[0]+4, screenbounds[1]+4, \
256    screenbounds[2]-4, screenbounds[3]-4
257
258kControlProgressBarIndeterminateTag = 'inde'    # from Controls.py
259
260
261class ProgressBar:
262    def __init__(self, title="Working...", maxval=0, label="", id=263):
263        self.w = None
264        self.d = None
265        _initialize()
266        self.d = GetNewDialog(id, -1)
267        self.w = self.d.GetDialogWindow()
268        self.label(label)
269        self.title(title)
270        self.set(0, maxval)
271        self.d.AutoSizeDialog()
272        self.w.ShowWindow()
273        self.d.DrawDialog()
274
275    def __del__(self):
276        if self.w:
277            self.w.BringToFront()
278            self.w.HideWindow()
279        del self.w
280        del self.d
281
282    def title(self, newstr=""):
283        """title(text) - Set title of progress window"""
284        self.w.BringToFront()
285        self.w.SetWTitle(newstr)
286
287    def label(self, *newstr):
288        """label(text) - Set text in progress box"""
289        self.w.BringToFront()
290        if newstr:
291            self._label = lf2cr(newstr[0])
292        text_h = self.d.GetDialogItemAsControl(2)
293        SetDialogItemText(text_h, self._label)
294
295    def _update(self, value):
296        maxval = self.maxval
297        if maxval == 0:     # an indeterminate bar
298            Ctl.IdleControls(self.w)    # spin the barber pole
299        else:               # a determinate bar
300            if maxval > 32767:
301                value = int(value/(maxval/32767.0))
302                maxval = 32767
303            maxval = int(maxval)
304            value = int(value)
305            progbar = self.d.GetDialogItemAsControl(3)
306            progbar.SetControlMaximum(maxval)
307            progbar.SetControlValue(value)  # set the bar length
308
309        # Test for cancel button
310        ready, ev = Evt.WaitNextEvent( Events.mDownMask, 1  )
311        if ready :
312            what,msg,when,where,mod = ev
313            part = Win.FindWindow(where)[0]
314            if Dlg.IsDialogEvent(ev):
315                ds = Dlg.DialogSelect(ev)
316                if ds[0] and ds[1] == self.d and ds[-1] == 1:
317                    self.w.HideWindow()
318                    self.w = None
319                    self.d = None
320                    raise KeyboardInterrupt, ev
321            else:
322                if part == 4:   # inDrag
323                    self.w.DragWindow(where, screenbounds)
324                else:
325                    MacOS.HandleEvent(ev)
326
327
328    def set(self, value, max=None):
329        """set(value) - Set progress bar position"""
330        if max is not None:
331            self.maxval = max
332            bar = self.d.GetDialogItemAsControl(3)
333            if max <= 0:    # indeterminate bar
334                bar.SetControlData(0,kControlProgressBarIndeterminateTag,'\x01')
335            else:           # determinate bar
336                bar.SetControlData(0,kControlProgressBarIndeterminateTag,'\x00')
337        if value < 0:
338            value = 0
339        elif value > self.maxval:
340            value = self.maxval
341        self.curval = value
342        self._update(value)
343
344    def inc(self, n=1):
345        """inc(amt) - Increment progress bar position"""
346        self.set(self.curval + n)
347
348ARGV_ID=265
349ARGV_ITEM_OK=1
350ARGV_ITEM_CANCEL=2
351ARGV_OPTION_GROUP=3
352ARGV_OPTION_EXPLAIN=4
353ARGV_OPTION_VALUE=5
354ARGV_OPTION_ADD=6
355ARGV_COMMAND_GROUP=7
356ARGV_COMMAND_EXPLAIN=8
357ARGV_COMMAND_ADD=9
358ARGV_ADD_OLDFILE=10
359ARGV_ADD_NEWFILE=11
360ARGV_ADD_FOLDER=12
361ARGV_CMDLINE_GROUP=13
362ARGV_CMDLINE_DATA=14
363
364##def _myModalDialog(d):
365##      while 1:
366##          ready, ev = Evt.WaitNextEvent(0xffff, -1)
367##          print 'DBG: WNE', ready, ev
368##          if ready :
369##              what,msg,when,where,mod = ev
370##              part, window = Win.FindWindow(where)
371##              if Dlg.IsDialogEvent(ev):
372##                  didit, dlgdone, itemdone = Dlg.DialogSelect(ev)
373##                  print 'DBG: DialogSelect', didit, dlgdone, itemdone, d
374##                  if didit and dlgdone == d:
375##                      return itemdone
376##              elif window == d.GetDialogWindow():
377##                  d.GetDialogWindow().SelectWindow()
378##                  if part == 4:   # inDrag
379##                          d.DragWindow(where, screenbounds)
380##                  else:
381##                      MacOS.HandleEvent(ev)
382##              else:
383##                  MacOS.HandleEvent(ev)
384##
385def _setmenu(control, items):
386    mhandle = control.GetControlData_Handle(Controls.kControlMenuPart,
387            Controls.kControlPopupButtonMenuHandleTag)
388    menu = Menu.as_Menu(mhandle)
389    for item in items:
390        if type(item) == type(()):
391            label = item[0]
392        else:
393            label = item
394        if label[-1] == '=' or label[-1] == ':':
395            label = label[:-1]
396        menu.AppendMenu(label)
397##          mhandle, mid = menu.getpopupinfo()
398##          control.SetControlData_Handle(Controls.kControlMenuPart,
399##                  Controls.kControlPopupButtonMenuHandleTag, mhandle)
400    control.SetControlMinimum(1)
401    control.SetControlMaximum(len(items)+1)
402
403def _selectoption(d, optionlist, idx):
404    if idx < 0 or idx >= len(optionlist):
405        MacOS.SysBeep()
406        return
407    option = optionlist[idx]
408    if type(option) == type(()):
409        if len(option) == 4:
410            help = option[2]
411        elif len(option) > 1:
412            help = option[-1]
413        else:
414            help = ''
415    else:
416        help = ''
417    h = d.GetDialogItemAsControl(ARGV_OPTION_EXPLAIN)
418    if help and len(help) > 250:
419        help = help[:250] + '...'
420    Dlg.SetDialogItemText(h, help)
421    hasvalue = 0
422    if type(option) == type(()):
423        label = option[0]
424    else:
425        label = option
426    if label[-1] == '=' or label[-1] == ':':
427        hasvalue = 1
428    h = d.GetDialogItemAsControl(ARGV_OPTION_VALUE)
429    Dlg.SetDialogItemText(h, '')
430    if hasvalue:
431        d.ShowDialogItem(ARGV_OPTION_VALUE)
432        d.SelectDialogItemText(ARGV_OPTION_VALUE, 0, 0)
433    else:
434        d.HideDialogItem(ARGV_OPTION_VALUE)
435
436
437def GetArgv(optionlist=None, commandlist=None, addoldfile=1, addnewfile=1, addfolder=1, id=ARGV_ID):
438    _initialize()
439    _interact()
440    d = GetNewDialog(id, -1)
441    if not d:
442        print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
443        return
444#       h = d.GetDialogItemAsControl(3)
445#       SetDialogItemText(h, lf2cr(prompt))
446#       h = d.GetDialogItemAsControl(4)
447#       SetDialogItemText(h, lf2cr(default))
448#       d.SelectDialogItemText(4, 0, 999)
449#       d.SetDialogItem(4, 0, 255)
450    if optionlist:
451        _setmenu(d.GetDialogItemAsControl(ARGV_OPTION_GROUP), optionlist)
452        _selectoption(d, optionlist, 0)
453    else:
454        d.GetDialogItemAsControl(ARGV_OPTION_GROUP).DeactivateControl()
455    if commandlist:
456        _setmenu(d.GetDialogItemAsControl(ARGV_COMMAND_GROUP), commandlist)
457        if type(commandlist[0]) == type(()) and len(commandlist[0]) > 1:
458            help = commandlist[0][-1]
459            h = d.GetDialogItemAsControl(ARGV_COMMAND_EXPLAIN)
460            Dlg.SetDialogItemText(h, help)
461    else:
462        d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).DeactivateControl()
463    if not addoldfile:
464        d.GetDialogItemAsControl(ARGV_ADD_OLDFILE).DeactivateControl()
465    if not addnewfile:
466        d.GetDialogItemAsControl(ARGV_ADD_NEWFILE).DeactivateControl()
467    if not addfolder:
468        d.GetDialogItemAsControl(ARGV_ADD_FOLDER).DeactivateControl()
469    d.SetDialogDefaultItem(ARGV_ITEM_OK)
470    d.SetDialogCancelItem(ARGV_ITEM_CANCEL)
471    d.GetDialogWindow().ShowWindow()
472    d.DrawDialog()
473    if hasattr(MacOS, 'SchedParams'):
474        appsw = MacOS.SchedParams(1, 0)
475    try:
476        while 1:
477            stringstoadd = []
478            n = ModalDialog(None)
479            if n == ARGV_ITEM_OK:
480                break
481            elif n == ARGV_ITEM_CANCEL:
482                raise SystemExit
483            elif n == ARGV_OPTION_GROUP:
484                idx = d.GetDialogItemAsControl(ARGV_OPTION_GROUP).GetControlValue()-1
485                _selectoption(d, optionlist, idx)
486            elif n == ARGV_OPTION_VALUE:
487                pass
488            elif n == ARGV_OPTION_ADD:
489                idx = d.GetDialogItemAsControl(ARGV_OPTION_GROUP).GetControlValue()-1
490                if 0 <= idx < len(optionlist):
491                    option = optionlist[idx]
492                    if type(option) == type(()):
493                        option = option[0]
494                    if option[-1] == '=' or option[-1] == ':':
495                        option = option[:-1]
496                        h = d.GetDialogItemAsControl(ARGV_OPTION_VALUE)
497                        value = Dlg.GetDialogItemText(h)
498                    else:
499                        value = ''
500                    if len(option) == 1:
501                        stringtoadd = '-' + option
502                    else:
503                        stringtoadd = '--' + option
504                    stringstoadd = [stringtoadd]
505                    if value:
506                        stringstoadd.append(value)
507                else:
508                    MacOS.SysBeep()
509            elif n == ARGV_COMMAND_GROUP:
510                idx = d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).GetControlValue()-1
511                if 0 <= idx < len(commandlist) and type(commandlist[idx]) == type(()) and \
512                        len(commandlist[idx]) > 1:
513                    help = commandlist[idx][-1]
514                    h = d.GetDialogItemAsControl(ARGV_COMMAND_EXPLAIN)
515                    Dlg.SetDialogItemText(h, help)
516            elif n == ARGV_COMMAND_ADD:
517                idx = d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).GetControlValue()-1
518                if 0 <= idx < len(commandlist):
519                    command = commandlist[idx]
520                    if type(command) == type(()):
521                        command = command[0]
522                    stringstoadd = [command]
523                else:
524                    MacOS.SysBeep()
525            elif n == ARGV_ADD_OLDFILE:
526                pathname = AskFileForOpen()
527                if pathname:
528                    stringstoadd = [pathname]
529            elif n == ARGV_ADD_NEWFILE:
530                pathname = AskFileForSave()
531                if pathname:
532                    stringstoadd = [pathname]
533            elif n == ARGV_ADD_FOLDER:
534                pathname = AskFolder()
535                if pathname:
536                    stringstoadd = [pathname]
537            elif n == ARGV_CMDLINE_DATA:
538                pass # Nothing to do
539            else:
540                raise RuntimeError, "Unknown dialog item %d"%n
541
542            for stringtoadd in stringstoadd:
543                if '"' in stringtoadd or "'" in stringtoadd or " " in stringtoadd:
544                    stringtoadd = repr(stringtoadd)
545                h = d.GetDialogItemAsControl(ARGV_CMDLINE_DATA)
546                oldstr = GetDialogItemText(h)
547                if oldstr and oldstr[-1] != ' ':
548                    oldstr = oldstr + ' '
549                oldstr = oldstr + stringtoadd
550                if oldstr[-1] != ' ':
551                    oldstr = oldstr + ' '
552                SetDialogItemText(h, oldstr)
553                d.SelectDialogItemText(ARGV_CMDLINE_DATA, 0x7fff, 0x7fff)
554        h = d.GetDialogItemAsControl(ARGV_CMDLINE_DATA)
555        oldstr = GetDialogItemText(h)
556        tmplist = string.split(oldstr)
557        newlist = []
558        while tmplist:
559            item = tmplist[0]
560            del tmplist[0]
561            if item[0] == '"':
562                while item[-1] != '"':
563                    if not tmplist:
564                        raise RuntimeError, "Unterminated quoted argument"
565                    item = item + ' ' + tmplist[0]
566                    del tmplist[0]
567                item = item[1:-1]
568            if item[0] == "'":
569                while item[-1] != "'":
570                    if not tmplist:
571                        raise RuntimeError, "Unterminated quoted argument"
572                    item = item + ' ' + tmplist[0]
573                    del tmplist[0]
574                item = item[1:-1]
575            newlist.append(item)
576        return newlist
577    finally:
578        if hasattr(MacOS, 'SchedParams'):
579            MacOS.SchedParams(*appsw)
580        del d
581
582def _process_Nav_args(dftflags, **args):
583    import Carbon.AppleEvents
584    import Carbon.AE
585    import Carbon.File
586    for k in args.keys():
587        if args[k] is None:
588            del args[k]
589    # Set some defaults, and modify some arguments
590    if 'dialogOptionFlags' not in args:
591        args['dialogOptionFlags'] = dftflags
592    if 'defaultLocation' in args and \
593            not isinstance(args['defaultLocation'], Carbon.AE.AEDesc):
594        defaultLocation = args['defaultLocation']
595        if isinstance(defaultLocation, Carbon.File.FSSpec):
596            args['defaultLocation'] = Carbon.AE.AECreateDesc(
597                    Carbon.AppleEvents.typeFSS, defaultLocation.data)
598        else:
599            if not isinstance(defaultLocation, Carbon.File.FSRef):
600                defaultLocation = Carbon.File.FSRef(defaultLocation)
601            args['defaultLocation'] = Carbon.AE.AECreateDesc(
602                    Carbon.AppleEvents.typeFSRef, defaultLocation.data)
603    if 'typeList' in args and not isinstance(args['typeList'], Carbon.Res.ResourceType):
604        typeList = args['typeList'][:]
605        # Workaround for OSX typeless files:
606        if 'TEXT' in typeList and not '\0\0\0\0' in typeList:
607            typeList = typeList + ('\0\0\0\0',)
608        data = 'Pyth' + struct.pack("hh", 0, len(typeList))
609        for type in typeList:
610            data = data+type
611        args['typeList'] = Carbon.Res.Handle(data)
612    tpwanted = str
613    if 'wanted' in args:
614        tpwanted = args['wanted']
615        del args['wanted']
616    return args, tpwanted
617
618def _dummy_Nav_eventproc(msg, data):
619    pass
620
621_default_Nav_eventproc = _dummy_Nav_eventproc
622
623def SetDefaultEventProc(proc):
624    global _default_Nav_eventproc
625    rv = _default_Nav_eventproc
626    if proc is None:
627        proc = _dummy_Nav_eventproc
628    _default_Nav_eventproc = proc
629    return rv
630
631def AskFileForOpen(
632        message=None,
633        typeList=None,
634        # From here on the order is not documented
635        version=None,
636        defaultLocation=None,
637        dialogOptionFlags=None,
638        location=None,
639        clientName=None,
640        windowTitle=None,
641        actionButtonLabel=None,
642        cancelButtonLabel=None,
643        preferenceKey=None,
644        popupExtension=None,
645        eventProc=_dummy_Nav_eventproc,
646        previewProc=None,
647        filterProc=None,
648        wanted=None,
649        multiple=None):
650    """Display a dialog asking the user for a file to open.
651
652    wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
653    the other arguments can be looked up in Apple's Navigation Services documentation"""
654
655    default_flags = 0x56 # Or 0xe4?
656    args, tpwanted = _process_Nav_args(default_flags, version=version,
657        defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
658        location=location,clientName=clientName,windowTitle=windowTitle,
659        actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
660        message=message,preferenceKey=preferenceKey,
661        popupExtension=popupExtension,eventProc=eventProc,previewProc=previewProc,
662        filterProc=filterProc,typeList=typeList,wanted=wanted,multiple=multiple)
663    _interact()
664    try:
665        rr = Nav.NavChooseFile(args)
666        good = 1
667    except Nav.error, arg:
668        if arg[0] != -128: # userCancelledErr
669            raise Nav.error, arg
670        return None
671    if not rr.validRecord or not rr.selection:
672        return None
673    if issubclass(tpwanted, Carbon.File.FSRef):
674        return tpwanted(rr.selection_fsr[0])
675    if issubclass(tpwanted, Carbon.File.FSSpec):
676        return tpwanted(rr.selection[0])
677    if issubclass(tpwanted, str):
678        return tpwanted(rr.selection_fsr[0].as_pathname())
679    if issubclass(tpwanted, unicode):
680        return tpwanted(rr.selection_fsr[0].as_pathname(), 'utf8')
681    raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)
682
683def AskFileForSave(
684        message=None,
685        savedFileName=None,
686        # From here on the order is not documented
687        version=None,
688        defaultLocation=None,
689        dialogOptionFlags=None,
690        location=None,
691        clientName=None,
692        windowTitle=None,
693        actionButtonLabel=None,
694        cancelButtonLabel=None,
695        preferenceKey=None,
696        popupExtension=None,
697        eventProc=_dummy_Nav_eventproc,
698        fileType=None,
699        fileCreator=None,
700        wanted=None,
701        multiple=None):
702    """Display a dialog asking the user for a filename to save to.
703
704    wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
705    the other arguments can be looked up in Apple's Navigation Services documentation"""
706
707
708    default_flags = 0x07
709    args, tpwanted = _process_Nav_args(default_flags, version=version,
710        defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
711        location=location,clientName=clientName,windowTitle=windowTitle,
712        actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
713        savedFileName=savedFileName,message=message,preferenceKey=preferenceKey,
714        popupExtension=popupExtension,eventProc=eventProc,fileType=fileType,
715        fileCreator=fileCreator,wanted=wanted,multiple=multiple)
716    _interact()
717    try:
718        rr = Nav.NavPutFile(args)
719        good = 1
720    except Nav.error, arg:
721        if arg[0] != -128: # userCancelledErr
722            raise Nav.error, arg
723        return None
724    if not rr.validRecord or not rr.selection:
725        return None
726    if issubclass(tpwanted, Carbon.File.FSRef):
727        raise TypeError, "Cannot pass wanted=FSRef to AskFileForSave"
728    if issubclass(tpwanted, Carbon.File.FSSpec):
729        return tpwanted(rr.selection[0])
730    if issubclass(tpwanted, (str, unicode)):
731        # This is gross, and probably incorrect too
732        vrefnum, dirid, name = rr.selection[0].as_tuple()
733        pardir_fss = Carbon.File.FSSpec((vrefnum, dirid, ''))
734        pardir_fsr = Carbon.File.FSRef(pardir_fss)
735        pardir_path = pardir_fsr.FSRefMakePath()  # This is utf-8
736        name_utf8 = unicode(name, 'macroman').encode('utf8')
737        fullpath = os.path.join(pardir_path, name_utf8)
738        if issubclass(tpwanted, unicode):
739            return unicode(fullpath, 'utf8')
740        return tpwanted(fullpath)
741    raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)
742
743def AskFolder(
744        message=None,
745        # From here on the order is not documented
746        version=None,
747        defaultLocation=None,
748        dialogOptionFlags=None,
749        location=None,
750        clientName=None,
751        windowTitle=None,
752        actionButtonLabel=None,
753        cancelButtonLabel=None,
754        preferenceKey=None,
755        popupExtension=None,
756        eventProc=_dummy_Nav_eventproc,
757        filterProc=None,
758        wanted=None,
759        multiple=None):
760    """Display a dialog asking the user for select a folder.
761
762    wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
763    the other arguments can be looked up in Apple's Navigation Services documentation"""
764
765    default_flags = 0x17
766    args, tpwanted = _process_Nav_args(default_flags, version=version,
767        defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
768        location=location,clientName=clientName,windowTitle=windowTitle,
769        actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
770        message=message,preferenceKey=preferenceKey,
771        popupExtension=popupExtension,eventProc=eventProc,filterProc=filterProc,
772        wanted=wanted,multiple=multiple)
773    _interact()
774    try:
775        rr = Nav.NavChooseFolder(args)
776        good = 1
777    except Nav.error, arg:
778        if arg[0] != -128: # userCancelledErr
779            raise Nav.error, arg
780        return None
781    if not rr.validRecord or not rr.selection:
782        return None
783    if issubclass(tpwanted, Carbon.File.FSRef):
784        return tpwanted(rr.selection_fsr[0])
785    if issubclass(tpwanted, Carbon.File.FSSpec):
786        return tpwanted(rr.selection[0])
787    if issubclass(tpwanted, str):
788        return tpwanted(rr.selection_fsr[0].as_pathname())
789    if issubclass(tpwanted, unicode):
790        return tpwanted(rr.selection_fsr[0].as_pathname(), 'utf8')
791    raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)
792
793
794def test():
795    import time
796
797    Message("Testing EasyDialogs.")
798    optionlist = (('v', 'Verbose'), ('verbose', 'Verbose as long option'),
799                ('flags=', 'Valued option'), ('f:', 'Short valued option'))
800    commandlist = (('start', 'Start something'), ('stop', 'Stop something'))
801    argv = GetArgv(optionlist=optionlist, commandlist=commandlist, addoldfile=0)
802    Message("Command line: %s"%' '.join(argv))
803    for i in range(len(argv)):
804        print 'arg[%d] = %r' % (i, argv[i])
805    ok = AskYesNoCancel("Do you want to proceed?")
806    ok = AskYesNoCancel("Do you want to identify?", yes="Identify", no="No")
807    if ok > 0:
808        s = AskString("Enter your first name", "Joe")
809        s2 = AskPassword("Okay %s, tell us your nickname"%s, s, cancel="None")
810        if not s2:
811            Message("%s has no secret nickname"%s)
812        else:
813            Message("Hello everybody!!\nThe secret nickname of %s is %s!!!"%(s, s2))
814    else:
815        s = 'Anonymous'
816    rv = AskFileForOpen(message="Gimme a file, %s"%s, wanted=Carbon.File.FSSpec)
817    Message("rv: %s"%rv)
818    rv = AskFileForSave(wanted=Carbon.File.FSRef, savedFileName="%s.txt"%s)
819    Message("rv.as_pathname: %s"%rv.as_pathname())
820    rv = AskFolder()
821    Message("Folder name: %s"%rv)
822    text = ( "Working Hard...", "Hardly Working..." ,
823            "So far, so good!", "Keep on truckin'" )
824    bar = ProgressBar("Progress, progress...", 0, label="Ramping up...")
825    try:
826        if hasattr(MacOS, 'SchedParams'):
827            appsw = MacOS.SchedParams(1, 0)
828        for i in xrange(20):
829            bar.inc()
830            time.sleep(0.05)
831        bar.set(0,100)
832        for i in xrange(100):
833            bar.set(i)
834            time.sleep(0.05)
835            if i % 10 == 0:
836                bar.label(text[(i/10) % 4])
837        bar.label("Done.")
838        time.sleep(1.0)     # give'em a chance to see "Done."
839    finally:
840        del bar
841        if hasattr(MacOS, 'SchedParams'):
842            MacOS.SchedParams(*appsw)
843
844if __name__ == '__main__':
845    try:
846        test()
847    except KeyboardInterrupt:
848        Message("Operation Canceled.")
849