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 
    247 screenbounds = Qd.GetQDGlobalsScreenBits().bounds
    248 screenbounds = screenbounds[0]+4, screenbounds[1]+4, \
    249     screenbounds[2]-4, screenbounds[3]-4
    250 
    251 kControlProgressBarIndeterminateTag = 'inde'    # from Controls.py
    252 
    253 
    254 class ProgressBar:
    255     def __init__(self, title="Working...", maxval=0, label="", id=263):
    256         self.w = None
    257         self.d = None
    258         _initialize()
    259         self.d = GetNewDialog(id, -1)
    260         self.w = self.d.GetDialogWindow()
    261         self.label(label)
    262         self.title(title)
    263         self.set(0, maxval)
    264         self.d.AutoSizeDialog()
    265         self.w.ShowWindow()
    266         self.d.DrawDialog()
    267 
    268     def __del__(self):
    269         if self.w:
    270             self.w.BringToFront()
    271             self.w.HideWindow()
    272         del self.w
    273         del self.d
    274 
    275     def title(self, newstr=""):
    276         """title(text) - Set title of progress window"""
    277         self.w.BringToFront()
    278         self.w.SetWTitle(newstr)
    279 
    280     def label(self, *newstr):
    281         """label(text) - Set text in progress box"""
    282         self.w.BringToFront()
    283         if newstr:
    284             self._label = lf2cr(newstr[0])
    285         text_h = self.d.GetDialogItemAsControl(2)
    286         SetDialogItemText(text_h, self._label)
    287 
    288     def _update(self, value):
    289         maxval = self.maxval
    290         if maxval == 0:     # an indeterminate bar
    291             Ctl.IdleControls(self.w)    # spin the barber pole
    292         else:               # a determinate bar
    293             if maxval > 32767:
    294                 value = int(value/(maxval/32767.0))
    295                 maxval = 32767
    296             maxval = int(maxval)
    297             value = int(value)
    298             progbar = self.d.GetDialogItemAsControl(3)
    299             progbar.SetControlMaximum(maxval)
    300             progbar.SetControlValue(value)  # set the bar length
    301 
    302         # Test for cancel button
    303         ready, ev = Evt.WaitNextEvent( Events.mDownMask, 1  )
    304         if ready :
    305             what,msg,when,where,mod = ev
    306             part = Win.FindWindow(where)[0]
    307             if Dlg.IsDialogEvent(ev):
    308                 ds = Dlg.DialogSelect(ev)
    309                 if ds[0] and ds[1] == self.d and ds[-1] == 1:
    310                     self.w.HideWindow()
    311                     self.w = None
    312                     self.d = None
    313                     raise KeyboardInterrupt, ev
    314             else:
    315                 if part == 4:   # inDrag
    316                     self.w.DragWindow(where, screenbounds)
    317                 else:
    318                     MacOS.HandleEvent(ev)
    319 
    320 
    321     def set(self, value, max=None):
    322         """set(value) - Set progress bar position"""
    323         if max is not None:
    324             self.maxval = max
    325             bar = self.d.GetDialogItemAsControl(3)
    326             if max <= 0:    # indeterminate bar
    327                 bar.SetControlData(0,kControlProgressBarIndeterminateTag,'\x01')
    328             else:           # determinate bar
    329                 bar.SetControlData(0,kControlProgressBarIndeterminateTag,'\x00')
    330         if value < 0:
    331             value = 0
    332         elif value > self.maxval:
    333             value = self.maxval
    334         self.curval = value
    335         self._update(value)
    336 
    337     def inc(self, n=1):
    338         """inc(amt) - Increment progress bar position"""
    339         self.set(self.curval + n)
    340 
    341 ARGV_ID=265
    342 ARGV_ITEM_OK=1
    343 ARGV_ITEM_CANCEL=2
    344 ARGV_OPTION_GROUP=3
    345 ARGV_OPTION_EXPLAIN=4
    346 ARGV_OPTION_VALUE=5
    347 ARGV_OPTION_ADD=6
    348 ARGV_COMMAND_GROUP=7
    349 ARGV_COMMAND_EXPLAIN=8
    350 ARGV_COMMAND_ADD=9
    351 ARGV_ADD_OLDFILE=10
    352 ARGV_ADD_NEWFILE=11
    353 ARGV_ADD_FOLDER=12
    354 ARGV_CMDLINE_GROUP=13
    355 ARGV_CMDLINE_DATA=14
    356 
    357 ##def _myModalDialog(d):
    358 ##      while 1:
    359 ##          ready, ev = Evt.WaitNextEvent(0xffff, -1)
    360 ##          print 'DBG: WNE', ready, ev
    361 ##          if ready :
    362 ##              what,msg,when,where,mod = ev
    363 ##              part, window = Win.FindWindow(where)
    364 ##              if Dlg.IsDialogEvent(ev):
    365 ##                  didit, dlgdone, itemdone = Dlg.DialogSelect(ev)
    366 ##                  print 'DBG: DialogSelect', didit, dlgdone, itemdone, d
    367 ##                  if didit and dlgdone == d:
    368 ##                      return itemdone
    369 ##              elif window == d.GetDialogWindow():
    370 ##                  d.GetDialogWindow().SelectWindow()
    371 ##                  if part == 4:   # inDrag
    372 ##                          d.DragWindow(where, screenbounds)
    373 ##                  else:
    374 ##                      MacOS.HandleEvent(ev)
    375 ##              else:
    376 ##                  MacOS.HandleEvent(ev)
    377 ##
    378 def _setmenu(control, items):
    379     mhandle = control.GetControlData_Handle(Controls.kControlMenuPart,
    380             Controls.kControlPopupButtonMenuHandleTag)
    381     menu = Menu.as_Menu(mhandle)
    382     for item in items:
    383         if type(item) == type(()):
    384             label = item[0]
    385         else:
    386             label = item
    387         if label[-1] == '=' or label[-1] == ':':
    388             label = label[:-1]
    389         menu.AppendMenu(label)
    390 ##          mhandle, mid = menu.getpopupinfo()
    391 ##          control.SetControlData_Handle(Controls.kControlMenuPart,
    392 ##                  Controls.kControlPopupButtonMenuHandleTag, mhandle)
    393     control.SetControlMinimum(1)
    394     control.SetControlMaximum(len(items)+1)
    395 
    396 def _selectoption(d, optionlist, idx):
    397     if idx < 0 or idx >= len(optionlist):
    398         MacOS.SysBeep()
    399         return
    400     option = optionlist[idx]
    401     if type(option) == type(()):
    402         if len(option) == 4:
    403             help = option[2]
    404         elif len(option) > 1:
    405             help = option[-1]
    406         else:
    407             help = ''
    408     else:
    409         help = ''
    410     h = d.GetDialogItemAsControl(ARGV_OPTION_EXPLAIN)
    411     if help and len(help) > 250:
    412         help = help[:250] + '...'
    413     Dlg.SetDialogItemText(h, help)
    414     hasvalue = 0
    415     if type(option) == type(()):
    416         label = option[0]
    417     else:
    418         label = option
    419     if label[-1] == '=' or label[-1] == ':':
    420         hasvalue = 1
    421     h = d.GetDialogItemAsControl(ARGV_OPTION_VALUE)
    422     Dlg.SetDialogItemText(h, '')
    423     if hasvalue:
    424         d.ShowDialogItem(ARGV_OPTION_VALUE)
    425         d.SelectDialogItemText(ARGV_OPTION_VALUE, 0, 0)
    426     else:
    427         d.HideDialogItem(ARGV_OPTION_VALUE)
    428 
    429 
    430 def GetArgv(optionlist=None, commandlist=None, addoldfile=1, addnewfile=1, addfolder=1, id=ARGV_ID):
    431     _initialize()
    432     _interact()
    433     d = GetNewDialog(id, -1)
    434     if not d:
    435         print "EasyDialogs: Can't get DLOG resource with id =", id, " (missing resource file?)"
    436         return
    437 #       h = d.GetDialogItemAsControl(3)
    438 #       SetDialogItemText(h, lf2cr(prompt))
    439 #       h = d.GetDialogItemAsControl(4)
    440 #       SetDialogItemText(h, lf2cr(default))
    441 #       d.SelectDialogItemText(4, 0, 999)
    442 #       d.SetDialogItem(4, 0, 255)
    443     if optionlist:
    444         _setmenu(d.GetDialogItemAsControl(ARGV_OPTION_GROUP), optionlist)
    445         _selectoption(d, optionlist, 0)
    446     else:
    447         d.GetDialogItemAsControl(ARGV_OPTION_GROUP).DeactivateControl()
    448     if commandlist:
    449         _setmenu(d.GetDialogItemAsControl(ARGV_COMMAND_GROUP), commandlist)
    450         if type(commandlist[0]) == type(()) and len(commandlist[0]) > 1:
    451             help = commandlist[0][-1]
    452             h = d.GetDialogItemAsControl(ARGV_COMMAND_EXPLAIN)
    453             Dlg.SetDialogItemText(h, help)
    454     else:
    455         d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).DeactivateControl()
    456     if not addoldfile:
    457         d.GetDialogItemAsControl(ARGV_ADD_OLDFILE).DeactivateControl()
    458     if not addnewfile:
    459         d.GetDialogItemAsControl(ARGV_ADD_NEWFILE).DeactivateControl()
    460     if not addfolder:
    461         d.GetDialogItemAsControl(ARGV_ADD_FOLDER).DeactivateControl()
    462     d.SetDialogDefaultItem(ARGV_ITEM_OK)
    463     d.SetDialogCancelItem(ARGV_ITEM_CANCEL)
    464     d.GetDialogWindow().ShowWindow()
    465     d.DrawDialog()
    466     if hasattr(MacOS, 'SchedParams'):
    467         appsw = MacOS.SchedParams(1, 0)
    468     try:
    469         while 1:
    470             stringstoadd = []
    471             n = ModalDialog(None)
    472             if n == ARGV_ITEM_OK:
    473                 break
    474             elif n == ARGV_ITEM_CANCEL:
    475                 raise SystemExit
    476             elif n == ARGV_OPTION_GROUP:
    477                 idx = d.GetDialogItemAsControl(ARGV_OPTION_GROUP).GetControlValue()-1
    478                 _selectoption(d, optionlist, idx)
    479             elif n == ARGV_OPTION_VALUE:
    480                 pass
    481             elif n == ARGV_OPTION_ADD:
    482                 idx = d.GetDialogItemAsControl(ARGV_OPTION_GROUP).GetControlValue()-1
    483                 if 0 <= idx < len(optionlist):
    484                     option = optionlist[idx]
    485                     if type(option) == type(()):
    486                         option = option[0]
    487                     if option[-1] == '=' or option[-1] == ':':
    488                         option = option[:-1]
    489                         h = d.GetDialogItemAsControl(ARGV_OPTION_VALUE)
    490                         value = Dlg.GetDialogItemText(h)
    491                     else:
    492                         value = ''
    493                     if len(option) == 1:
    494                         stringtoadd = '-' + option
    495                     else:
    496                         stringtoadd = '--' + option
    497                     stringstoadd = [stringtoadd]
    498                     if value:
    499                         stringstoadd.append(value)
    500                 else:
    501                     MacOS.SysBeep()
    502             elif n == ARGV_COMMAND_GROUP:
    503                 idx = d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).GetControlValue()-1
    504                 if 0 <= idx < len(commandlist) and type(commandlist[idx]) == type(()) and \
    505                         len(commandlist[idx]) > 1:
    506                     help = commandlist[idx][-1]
    507                     h = d.GetDialogItemAsControl(ARGV_COMMAND_EXPLAIN)
    508                     Dlg.SetDialogItemText(h, help)
    509             elif n == ARGV_COMMAND_ADD:
    510                 idx = d.GetDialogItemAsControl(ARGV_COMMAND_GROUP).GetControlValue()-1
    511                 if 0 <= idx < len(commandlist):
    512                     command = commandlist[idx]
    513                     if type(command) == type(()):
    514                         command = command[0]
    515                     stringstoadd = [command]
    516                 else:
    517                     MacOS.SysBeep()
    518             elif n == ARGV_ADD_OLDFILE:
    519                 pathname = AskFileForOpen()
    520                 if pathname:
    521                     stringstoadd = [pathname]
    522             elif n == ARGV_ADD_NEWFILE:
    523                 pathname = AskFileForSave()
    524                 if pathname:
    525                     stringstoadd = [pathname]
    526             elif n == ARGV_ADD_FOLDER:
    527                 pathname = AskFolder()
    528                 if pathname:
    529                     stringstoadd = [pathname]
    530             elif n == ARGV_CMDLINE_DATA:
    531                 pass # Nothing to do
    532             else:
    533                 raise RuntimeError, "Unknown dialog item %d"%n
    534 
    535             for stringtoadd in stringstoadd:
    536                 if '"' in stringtoadd or "'" in stringtoadd or " " in stringtoadd:
    537                     stringtoadd = repr(stringtoadd)
    538                 h = d.GetDialogItemAsControl(ARGV_CMDLINE_DATA)
    539                 oldstr = GetDialogItemText(h)
    540                 if oldstr and oldstr[-1] != ' ':
    541                     oldstr = oldstr + ' '
    542                 oldstr = oldstr + stringtoadd
    543                 if oldstr[-1] != ' ':
    544                     oldstr = oldstr + ' '
    545                 SetDialogItemText(h, oldstr)
    546                 d.SelectDialogItemText(ARGV_CMDLINE_DATA, 0x7fff, 0x7fff)
    547         h = d.GetDialogItemAsControl(ARGV_CMDLINE_DATA)
    548         oldstr = GetDialogItemText(h)
    549         tmplist = string.split(oldstr)
    550         newlist = []
    551         while tmplist:
    552             item = tmplist[0]
    553             del tmplist[0]
    554             if item[0] == '"':
    555                 while item[-1] != '"':
    556                     if not tmplist:
    557                         raise RuntimeError, "Unterminated quoted argument"
    558                     item = item + ' ' + tmplist[0]
    559                     del tmplist[0]
    560                 item = item[1:-1]
    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             newlist.append(item)
    569         return newlist
    570     finally:
    571         if hasattr(MacOS, 'SchedParams'):
    572             MacOS.SchedParams(*appsw)
    573         del d
    574 
    575 def _process_Nav_args(dftflags, **args):
    576     import Carbon.AppleEvents
    577     import Carbon.AE
    578     import Carbon.File
    579     for k in args.keys():
    580         if args[k] is None:
    581             del args[k]
    582     # Set some defaults, and modify some arguments
    583     if 'dialogOptionFlags' not in args:
    584         args['dialogOptionFlags'] = dftflags
    585     if 'defaultLocation' in args and \
    586             not isinstance(args['defaultLocation'], Carbon.AE.AEDesc):
    587         defaultLocation = args['defaultLocation']
    588         if isinstance(defaultLocation, Carbon.File.FSSpec):
    589             args['defaultLocation'] = Carbon.AE.AECreateDesc(
    590                     Carbon.AppleEvents.typeFSS, defaultLocation.data)
    591         else:
    592             if not isinstance(defaultLocation, Carbon.File.FSRef):
    593                 defaultLocation = Carbon.File.FSRef(defaultLocation)
    594             args['defaultLocation'] = Carbon.AE.AECreateDesc(
    595                     Carbon.AppleEvents.typeFSRef, defaultLocation.data)
    596     if 'typeList' in args and not isinstance(args['typeList'], Carbon.Res.ResourceType):
    597         typeList = args['typeList'][:]
    598         # Workaround for OSX typeless files:
    599         if 'TEXT' in typeList and not '\0\0\0\0' in typeList:
    600             typeList = typeList + ('\0\0\0\0',)
    601         data = 'Pyth' + struct.pack("hh", 0, len(typeList))
    602         for type in typeList:
    603             data = data+type
    604         args['typeList'] = Carbon.Res.Handle(data)
    605     tpwanted = str
    606     if 'wanted' in args:
    607         tpwanted = args['wanted']
    608         del args['wanted']
    609     return args, tpwanted
    610 
    611 def _dummy_Nav_eventproc(msg, data):
    612     pass
    613 
    614 _default_Nav_eventproc = _dummy_Nav_eventproc
    615 
    616 def SetDefaultEventProc(proc):
    617     global _default_Nav_eventproc
    618     rv = _default_Nav_eventproc
    619     if proc is None:
    620         proc = _dummy_Nav_eventproc
    621     _default_Nav_eventproc = proc
    622     return rv
    623 
    624 def AskFileForOpen(
    625         message=None,
    626         typeList=None,
    627         # From here on the order is not documented
    628         version=None,
    629         defaultLocation=None,
    630         dialogOptionFlags=None,
    631         location=None,
    632         clientName=None,
    633         windowTitle=None,
    634         actionButtonLabel=None,
    635         cancelButtonLabel=None,
    636         preferenceKey=None,
    637         popupExtension=None,
    638         eventProc=_dummy_Nav_eventproc,
    639         previewProc=None,
    640         filterProc=None,
    641         wanted=None,
    642         multiple=None):
    643     """Display a dialog asking the user for a file to open.
    644 
    645     wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
    646     the other arguments can be looked up in Apple's Navigation Services documentation"""
    647 
    648     default_flags = 0x56 # Or 0xe4?
    649     args, tpwanted = _process_Nav_args(default_flags, version=version,
    650         defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
    651         location=location,clientName=clientName,windowTitle=windowTitle,
    652         actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
    653         message=message,preferenceKey=preferenceKey,
    654         popupExtension=popupExtension,eventProc=eventProc,previewProc=previewProc,
    655         filterProc=filterProc,typeList=typeList,wanted=wanted,multiple=multiple)
    656     _interact()
    657     try:
    658         rr = Nav.NavChooseFile(args)
    659         good = 1
    660     except Nav.error, arg:
    661         if arg[0] != -128: # userCancelledErr
    662             raise Nav.error, arg
    663         return None
    664     if not rr.validRecord or not rr.selection:
    665         return None
    666     if issubclass(tpwanted, Carbon.File.FSRef):
    667         return tpwanted(rr.selection_fsr[0])
    668     if issubclass(tpwanted, Carbon.File.FSSpec):
    669         return tpwanted(rr.selection[0])
    670     if issubclass(tpwanted, str):
    671         return tpwanted(rr.selection_fsr[0].as_pathname())
    672     if issubclass(tpwanted, unicode):
    673         return tpwanted(rr.selection_fsr[0].as_pathname(), 'utf8')
    674     raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)
    675 
    676 def AskFileForSave(
    677         message=None,
    678         savedFileName=None,
    679         # From here on the order is not documented
    680         version=None,
    681         defaultLocation=None,
    682         dialogOptionFlags=None,
    683         location=None,
    684         clientName=None,
    685         windowTitle=None,
    686         actionButtonLabel=None,
    687         cancelButtonLabel=None,
    688         preferenceKey=None,
    689         popupExtension=None,
    690         eventProc=_dummy_Nav_eventproc,
    691         fileType=None,
    692         fileCreator=None,
    693         wanted=None,
    694         multiple=None):
    695     """Display a dialog asking the user for a filename to save to.
    696 
    697     wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
    698     the other arguments can be looked up in Apple's Navigation Services documentation"""
    699 
    700 
    701     default_flags = 0x07
    702     args, tpwanted = _process_Nav_args(default_flags, version=version,
    703         defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
    704         location=location,clientName=clientName,windowTitle=windowTitle,
    705         actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
    706         savedFileName=savedFileName,message=message,preferenceKey=preferenceKey,
    707         popupExtension=popupExtension,eventProc=eventProc,fileType=fileType,
    708         fileCreator=fileCreator,wanted=wanted,multiple=multiple)
    709     _interact()
    710     try:
    711         rr = Nav.NavPutFile(args)
    712         good = 1
    713     except Nav.error, arg:
    714         if arg[0] != -128: # userCancelledErr
    715             raise Nav.error, arg
    716         return None
    717     if not rr.validRecord or not rr.selection:
    718         return None
    719     if issubclass(tpwanted, Carbon.File.FSRef):
    720         raise TypeError, "Cannot pass wanted=FSRef to AskFileForSave"
    721     if issubclass(tpwanted, Carbon.File.FSSpec):
    722         return tpwanted(rr.selection[0])
    723     if issubclass(tpwanted, (str, unicode)):
    724         # This is gross, and probably incorrect too
    725         vrefnum, dirid, name = rr.selection[0].as_tuple()
    726         pardir_fss = Carbon.File.FSSpec((vrefnum, dirid, ''))
    727         pardir_fsr = Carbon.File.FSRef(pardir_fss)
    728         pardir_path = pardir_fsr.FSRefMakePath()  # This is utf-8
    729         name_utf8 = unicode(name, 'macroman').encode('utf8')
    730         fullpath = os.path.join(pardir_path, name_utf8)
    731         if issubclass(tpwanted, unicode):
    732             return unicode(fullpath, 'utf8')
    733         return tpwanted(fullpath)
    734     raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)
    735 
    736 def AskFolder(
    737         message=None,
    738         # From here on the order is not documented
    739         version=None,
    740         defaultLocation=None,
    741         dialogOptionFlags=None,
    742         location=None,
    743         clientName=None,
    744         windowTitle=None,
    745         actionButtonLabel=None,
    746         cancelButtonLabel=None,
    747         preferenceKey=None,
    748         popupExtension=None,
    749         eventProc=_dummy_Nav_eventproc,
    750         filterProc=None,
    751         wanted=None,
    752         multiple=None):
    753     """Display a dialog asking the user for select a folder.
    754 
    755     wanted is the return type wanted: FSSpec, FSRef, unicode or string (default)
    756     the other arguments can be looked up in Apple's Navigation Services documentation"""
    757 
    758     default_flags = 0x17
    759     args, tpwanted = _process_Nav_args(default_flags, version=version,
    760         defaultLocation=defaultLocation, dialogOptionFlags=dialogOptionFlags,
    761         location=location,clientName=clientName,windowTitle=windowTitle,
    762         actionButtonLabel=actionButtonLabel,cancelButtonLabel=cancelButtonLabel,
    763         message=message,preferenceKey=preferenceKey,
    764         popupExtension=popupExtension,eventProc=eventProc,filterProc=filterProc,
    765         wanted=wanted,multiple=multiple)
    766     _interact()
    767     try:
    768         rr = Nav.NavChooseFolder(args)
    769         good = 1
    770     except Nav.error, arg:
    771         if arg[0] != -128: # userCancelledErr
    772             raise Nav.error, arg
    773         return None
    774     if not rr.validRecord or not rr.selection:
    775         return None
    776     if issubclass(tpwanted, Carbon.File.FSRef):
    777         return tpwanted(rr.selection_fsr[0])
    778     if issubclass(tpwanted, Carbon.File.FSSpec):
    779         return tpwanted(rr.selection[0])
    780     if issubclass(tpwanted, str):
    781         return tpwanted(rr.selection_fsr[0].as_pathname())
    782     if issubclass(tpwanted, unicode):
    783         return tpwanted(rr.selection_fsr[0].as_pathname(), 'utf8')
    784     raise TypeError, "Unknown value for argument 'wanted': %s" % repr(tpwanted)
    785 
    786 
    787 def test():
    788     import time
    789 
    790     Message("Testing EasyDialogs.")
    791     optionlist = (('v', 'Verbose'), ('verbose', 'Verbose as long option'),
    792                 ('flags=', 'Valued option'), ('f:', 'Short valued option'))
    793     commandlist = (('start', 'Start something'), ('stop', 'Stop something'))
    794     argv = GetArgv(optionlist=optionlist, commandlist=commandlist, addoldfile=0)
    795     Message("Command line: %s"%' '.join(argv))
    796     for i in range(len(argv)):
    797         print 'arg[%d] = %r' % (i, argv[i])
    798     ok = AskYesNoCancel("Do you want to proceed?")
    799     ok = AskYesNoCancel("Do you want to identify?", yes="Identify", no="No")
    800     if ok > 0:
    801         s = AskString("Enter your first name", "Joe")
    802         s2 = AskPassword("Okay %s, tell us your nickname"%s, s, cancel="None")
    803         if not s2:
    804             Message("%s has no secret nickname"%s)
    805         else:
    806             Message("Hello everybody!!\nThe secret nickname of %s is %s!!!"%(s, s2))
    807     else:
    808         s = 'Anonymous'
    809     rv = AskFileForOpen(message="Gimme a file, %s"%s, wanted=Carbon.File.FSSpec)
    810     Message("rv: %s"%rv)
    811     rv = AskFileForSave(wanted=Carbon.File.FSRef, savedFileName="%s.txt"%s)
    812     Message("rv.as_pathname: %s"%rv.as_pathname())
    813     rv = AskFolder()
    814     Message("Folder name: %s"%rv)
    815     text = ( "Working Hard...", "Hardly Working..." ,
    816             "So far, so good!", "Keep on truckin'" )
    817     bar = ProgressBar("Progress, progress...", 0, label="Ramping up...")
    818     try:
    819         if hasattr(MacOS, 'SchedParams'):
    820             appsw = MacOS.SchedParams(1, 0)
    821         for i in xrange(20):
    822             bar.inc()
    823             time.sleep(0.05)
    824         bar.set(0,100)
    825         for i in xrange(100):
    826             bar.set(i)
    827             time.sleep(0.05)
    828             if i % 10 == 0:
    829                 bar.label(text[(i/10) % 4])
    830         bar.label("Done.")
    831         time.sleep(1.0)     # give'em a chance to see "Done."
    832     finally:
    833         del bar
    834         if hasattr(MacOS, 'SchedParams'):
    835             MacOS.SchedParams(*appsw)
    836 
    837 if __name__ == '__main__':
    838     try:
    839         test()
    840     except KeyboardInterrupt:
    841         Message("Operation Canceled.")
    842