Home | History | Annotate | Download | only in plat-mac
      1 """Easy to use dialogs.
      2 
      3 Message(msg) -- display a message and an OK button.
      4 AskString(prompt, default) -- ask for a string, display OK and Cancel buttons.
      5 AskPassword(prompt, default) -- like AskString(), but shows text as bullets.
      6 AskYesNoCancel(question, default) -- display a question and Yes, No and Cancel buttons.
      7 GetArgv(optionlist, commandlist) -- fill a sys.argv-like list using a dialog
      8 AskFileForOpen(...) -- Ask the user for an existing file
      9 AskFileForSave(...) -- Ask the user for an output file
     10 AskFolder(...) -- Ask the user to select a folder
     11 bar = Progress(label, maxvalue) -- Display a progress bar
     12 bar.set(value) -- Set value
     13 bar.inc( *amount ) -- increment value by amount (default=1)
     14 bar.label( *newlabel ) -- get or set text label.
     15 
     16 More documentation in each function.
     17 This module uses DLOG resources 260 and on.
     18 Based upon STDWIN dialogs with the same names and functions.
     19 """
     20 
     21 from warnings import warnpy3k
     22 warnpy3k("In 3.x, the EasyDialogs module is removed.", stacklevel=2)
     23 
     24 from Carbon.Dlg import GetNewDialog, SetDialogItemText, GetDialogItemText, ModalDialog
     25 from Carbon import Qd
     26 from Carbon import QuickDraw
     27 from Carbon import Dialogs
     28 from Carbon import Windows
     29 from Carbon import Dlg,Win,Evt,Events # sdm7g
     30 from Carbon import Ctl
     31 from Carbon import Controls
     32 from Carbon import Menu
     33 from Carbon import AE
     34 import Nav
     35 import MacOS
     36 import string
     37 from Carbon.ControlAccessor import *    # Also import Controls constants
     38 import Carbon.File
     39 import macresource
     40 import os
     41 import sys
     42 
     43 __all__ = ['Message', 'AskString', 'AskPassword', 'AskYesNoCancel',
     44     'GetArgv', 'AskFileForOpen', 'AskFileForSave', 'AskFolder',
     45     'ProgressBar']
     46 
     47 _initialized = 0
     48 
     49 def _initialize():
     50     global _initialized
     51     if _initialized: return
     52     macresource.need("DLOG", 260, "dialogs.rsrc", __name__)
     53 
     54 def _interact():
     55     """Make sure the application is in the foreground"""
     56     AE.AEInteractWithUser(50000000)
     57 
     58 def cr2lf(text):
     59     if '\r' in text:
     60         text = string.join(string.split(text, '\r'), '\n')
     61     return text
     62 
     63 def 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 
     70 def 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 
     97 def 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 
    139 def 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 
    183 def 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 
    250 try:
    251     screenbounds = Qd.GetQDGlobalsScreenBits().bounds
    252 except AttributeError:
    253     raise ImportError("QuickDraw APIs not available")
    254 
    255 screenbounds = screenbounds[0]+4, screenbounds[1]+4, \
    256     screenbounds[2]-4, screenbounds[3]-4
    257 
    258 kControlProgressBarIndeterminateTag = 'inde'    # from Controls.py
    259 
    260 
    261 class 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 
    348 ARGV_ID=265
    349 ARGV_ITEM_OK=1
    350 ARGV_ITEM_CANCEL=2
    351 ARGV_OPTION_GROUP=3
    352 ARGV_OPTION_EXPLAIN=4
    353 ARGV_OPTION_VALUE=5
    354 ARGV_OPTION_ADD=6
    355 ARGV_COMMAND_GROUP=7
    356 ARGV_COMMAND_EXPLAIN=8
    357 ARGV_COMMAND_ADD=9
    358 ARGV_ADD_OLDFILE=10
    359 ARGV_ADD_NEWFILE=11
    360 ARGV_ADD_FOLDER=12
    361 ARGV_CMDLINE_GROUP=13
    362 ARGV_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 ##
    385 def _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 
    403 def _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 
    437 def 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 
    582 def _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 
    618 def _dummy_Nav_eventproc(msg, data):
    619     pass
    620 
    621 _default_Nav_eventproc = _dummy_Nav_eventproc
    622 
    623 def 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 
    631 def 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 
    683 def 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 
    743 def 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 
    794 def 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 
    844 if __name__ == '__main__':
    845     try:
    846         test()
    847     except KeyboardInterrupt:
    848         Message("Operation Canceled.")
    849