Module guihelper
[hide private]
[frames] | no frames]

Source Code for Module guihelper

  1  ### BITPIM 
  2  ### 
  3  ### Copyright (C) 2003-2004 Roger Binns <rogerb@rogerbinns.com> 
  4  ### 
  5  ### This program is free software; you can redistribute it and/or modify 
  6  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
  7  ### 
  8  ### $Id: guihelper.py 4620 2008-06-28 02:53:17Z djpham $ 
  9   
 10  "Various helper routines for gui based code" 
 11   
 12  # These routines were initially in gui.py but that led to circular imports 
 13  # which confused the heck out of pychecker 
 14   
 15  # standard modules 
 16  from __future__ import with_statement 
 17  import contextlib 
 18  import os 
 19  import glob 
 20  import sys 
 21   
 22  # wx modules 
 23  import wx 
 24   
 25  # my modules 
 26  import common  # note we modify the common module contents 
 27   
 28  ### 
 29  ### The various IDs we use.  Code below munges the integers into sequence 
 30  ### 
 31   
 32  # Main menu items 
 33   
 34  ID_FILENEW=1 
 35  ID_FILEOPEN=1 
 36  ID_FILESAVE=1 
 37  ID_FILEIMPORT=1 
 38  ID_FILEEXPORT=1 
 39  ID_FILEPRINT=1 
 40  ID_FILEPRINTPREVIEW=1 
 41  ID_FILEEXIT=1 
 42  ID_EDITADDENTRY=1 
 43  ID_EDITDELETEENTRY=1 
 44  ID_EDITSELECTALL=1 
 45  ID_EDITSETTINGS=1 
 46  ID_EDITPHONEINFO=1 
 47  ID_EDITDETECT=1 
 48  ID_EDITCOPY=1 
 49  ID_EDITPASTE=1 
 50  ID_EDITRENAME=1 
 51  ID_DATAGETPHONE=1 
 52  ID_DATASENDPHONE=1 
 53  ID_DATAHISTORICAL=1 
 54  ID_DATANEWDB=1 
 55  ID_AUTOSYNCSETTINGS=1 
 56  ID_AUTOSYNCEXECUTE=1 
 57  ID_VIEWCOLUMNS=1 
 58  ID_VIEWPREVIEW=1 
 59  ID_VIEWLOGDATA=1 
 60  ID_VIEWCLEARLOGS=1 
 61  ID_VIEWFILESYSTEM=1 
 62  ID_HELPHELP=1 
 63  ID_HELPCONTENTS=1 
 64  ID_HELPTOUR=1 
 65  ID_HELPSUPPORT=1 
 66  ID_HELP_UPDATE=1 
 67  ID_HELPABOUT=1 
 68  ID_HELPPHONE=1 
 69  ID_HELPHOWTOS=1 
 70  ID_HELPFAQ=1 
 71  ID_DR_SETTINGS=1 
 72  ID_DEBUG_SCRIPT=1 
 73  ID_FILEVIEW_THUMBNAIL=1 
 74  ID_FILEVIEW_LIST=1 
 75   
 76  # file/filesystem viewer context menus 
 77  ID_FV_SAVE=1 
 78  ID_FV_HEXVIEW=1 
 79  ID_FV_OVERWRITE=1 
 80  ID_FV_MOVE=1 
 81  ID_FV_NEWSUBDIR=1 
 82  ID_FV_NEWFILE=1 
 83  ID_FV_DELETE=1 
 84  ID_FV_OPEN=1 
 85  ID_FV_RENAME=1 
 86  ID_FV_REFRESH=1 
 87  ID_FV_PROPERTIES=1 
 88  ID_FV_ADD=1 
 89  ID_FV_BACKUP=1 
 90  ID_FV_BACKUP_TREE=1 
 91  ID_FV_RESTORE=1 
 92  ID_FV_PASTE=1 
 93  ID_FV_TOTAL_REFRESH=1 
 94  ID_FV_OFFLINEPHONE=1 
 95  ID_FV_REBOOTPHONE=1 
 96  ID_FV_MODEMMODE=1 
 97  ID_FV_COPY=1 
 98  ID_FV_REPLACE=1 
 99   
100  # export/import IDs 
101  ID_EXPORT_VCARD_CONTACTS=1 
102  ID_EXPORT_GROUPWARE_CONTACTS=1 
103  ID_EXPORT_CSV_CONTACTS=1 
104  ID_EXPORT_CSV_CALENDAR=1 
105  ID_EXPORT_SMS=1 
106  ID_EXPORT_CSV_CALL_HISTORY=1 
107  ID_EXPORT_MEDIA_TO_DIR=1 
108  ID_EXPORT_MEDIA_TO_ZIP=1 
109  ID_IMPORT_CSV_CONTACTS=1 
110  ID_IMPORT_CSV_CALENDAR=1 
111  ID_IMPORT_VCARDS=1 
112  ID_IMPORT_VCALENDAR=1 
113  ID_IMPORT_ICALENDAR=1 
114  ID_IMPORT_GCALENDAR=1 
115  ID_IMPORT_OUTLOOK_CONTACTS=1 
116  ID_IMPORT_OUTLOOK_CALENDAR=1 
117  ID_IMPORT_OUTLOOK_NOTES=1 
118  ID_IMPORT_OUTLOOK_TASKS=1 
119  ID_IMPORT_EVO_CONTACTS=1 
120  ID_IMPORT_QTOPIA_CONTACTS=1 
121  ID_IMPORT_GROUPWARE_CONTACTS=1 
122  ID_CALENDAR_WIZARD=1 
123  ID_IMPORT_WPL=1 
124  ID_EXPORT_ICALENDAR=1 
125   
126  # keep map around 
127  idmap={} 
128  # Start at 2 (if anything ends up being one then this code didn't spot it 
129  for idmapname in locals().keys(): 
130      if idmapname.startswith('ID_'): 
131          idnum=wx.NewId() 
132          # locals()[idmapname]=idnum 
133          exec "%s = %d" % (idmapname, idnum ) 
134          idmap[idnum]=idmapname 
135   
136  ### 
137  ### Various functions not attached to classes 
138  ### 
139   
140   
141  # These are the mime-types as used internally in wxWidgets 
142  _wxmimemapping={ 
143      'bmp': 'image/x-bmp', 
144      'ico': 'image/x-ico', 
145      'cur': 'image/x-cur', 
146      'ani': 'image/x-ani', 
147      'gif': 'image/gif', 
148      'iff': 'image/iff', 
149      'jpg': 'image/jpeg', 
150      'jpeg': 'image/jpeg', 
151      'pcx': 'image/pcx', 
152      'png': 'image/png', 
153      'pnm': 'image/pnm', 
154      'xpm': 'image/xpm', 
155      } 
156 157 -def getwxmimetype(filename):
158 "Returns wx's mime type for the extension of filename, or None" 159 return _wxmimemapping.get(getextension(filename.lower()), None)
160
161 -def BusyWrapper(method):
162 def _busywrapper(*args, **kwargs): 163 wx.BeginBusyCursor() 164 try: 165 return method(*args, **kwargs) 166 finally: 167 wx.EndBusyCursor()
168 169 setattr(_busywrapper, "__doc__", getattr(method, "__doc__")) 170 171 return _busywrapper 172
173 @contextlib.contextmanager 174 -def MWBusyWrapper(mw):
175 mw.OnBusyStart() 176 try: 177 yield mw 178 finally: 179 mw.OnBusyEnd()
180
181 @contextlib.contextmanager 182 -def WXDialogWrapper(dlg, showmodal=False):
183 """ A wrapper for the wx.Dialog class that automatically calls Destroy""" 184 try: 185 yield (dlg, dlg.ShowModal()) if showmodal else dlg 186 finally: 187 dlg.Destroy()
188
189 @BusyWrapper 190 -def MessageDialog(*args, **kwargs):
191 with WXDialogWrapper(wx.MessageDialog(*args, **kwargs), 192 True): 193 pass
194
195 # Filename functions. These work on brew names which use forward slash / 196 # as the directory delimiter. The builtin Python functions can't be used 197 # as they are platform specific (eg they use \ on Windows) 198 199 -def getextension(str):
200 """Returns the extension of a filename (characters after last period) 201 202 An empty string is returned if the file has no extension. The period 203 character is not returned""" 204 str=basename(str) 205 if str.rfind('.')>=0: 206 return str[str.rfind('.')+1:] 207 return ""
208
209 -def basename(str):
210 """Returns the last part of the name (everything after last /)""" 211 if str.rfind('/')<0: return str 212 return str[str.rfind('/')+1:]
213
214 -def dirname(str):
215 """Returns everything before the last / in the name""" 216 if str.rfind('/')<0: return "" 217 return str[:str.rfind('/')]
218
219 -def IsMSWindows():
220 """Are we running on Windows? 221 222 @rtype: Bool""" 223 return wx.Platform=='__WXMSW__'
224
225 -def IsGtk():
226 """Are we running on GTK (Linux) 227 228 @rtype: Bool""" 229 return wx.Platform=='__WXGTK__'
230
231 -def IsMac():
232 """Are we running on Mac 233 234 @rtype: Bool""" 235 return wx.Platform=='__WXMAC__'
236
237 238 -def getbitmap(name):
239 """Gets a bitmap from the resource directory 240 241 @rtype: wxBitmap 242 """ 243 return getimage(name).ConvertToBitmap()
244
245 -def getimage(name):
246 """Gets an image from the resource directory 247 248 @rtype: wx.Image 249 """ 250 for ext in ("", ".png", ".jpg"): 251 if os.path.exists(getresourcefile(name+ext)): 252 return wx.Image(getresourcefile(name+ext)) 253 print "You need to make "+name+".png" 254 return getimage('unknown')
255
256 257 -def getresourcefile(filename):
258 """Returns name of file by adding it to resource directory pathname 259 260 No attempt is made to verify the file exists 261 @rtype: string 262 """ 263 return os.path.join(resourcedirectory, filename)
264
265 -def gethelpfilename():
266 """Returns what name we use for the helpfile 267 268 Without trailing extension as wxBestHelpController figures that out""" 269 270 # we look in a help subdirectory first which is 271 # present in the developer tree 272 j=os.path.join 273 paths=( (helpdirectory, True), 274 (resourcedirectory, False) ) 275 276 if IsMSWindows(): 277 name="bitpim.chm" 278 else: 279 name="bitpim.htb" 280 281 for p,mention in paths: 282 if os.path.isfile(j(p, name)): 283 if mention: 284 print "Using help file from "+p 285 return j(p, "bitpim") 286 287 assert False
288
289 -def getresourcefiles(wildcard):
290 "Returns a list of filenames matching the wildcard in the resource directory" 291 l=glob.glob(os.path.join(resourcedirectory, wildcard)) 292 l.sort() 293 return l
294 295 # Where to find bitmaps etc 296 resourcedirectory=os.path.join(common.get_main_dir(), 'resources') 297 helpdirectory=os.path.join(common.get_main_dir(), 'help')
298 299 # See strorunicode comment in common 300 if wx.USE_UNICODE: 301 - def strorunicode(s):
302 if s is None: return s 303 if isinstance(s, unicode): return s 304 return str(s)
305 306 common.strorunicode=strorunicode 307 del strorunicode 308 309 else:
310 - def strorunicode(s):
311 if s is None: return s 312 try: 313 return str(s) 314 except UnicodeEncodeError: 315 return s.encode("ascii", "replace")
316 317 common.strorunicode=strorunicode 318 del strorunicode
319 320 # mime-type stuff 321 -def GetOpenCommand(mimetypes, filename):
322 # go through list of mime-types until we can find a command for opening filename 323 for mt in mimetypes: 324 ft=wx.TheMimeTypesManager.GetFileTypeFromMimeType(mt) 325 if ft is None: 326 continue 327 if IsGtk(): 328 # protect file names with spaces 329 cmd=ft.GetOpenCommand('"%s"'%filename) 330 else: 331 cmd=ft.GetOpenCommand(filename) 332 if cmd is not None and len(cmd): 333 return cmd 334 return None
335 336 # Art provider stuff 337 338 # Our constants 339 _ourart={ 340 "ART_ADD_WALLPAPER": "add_picture", 341 "ART_DEL_WALLPAPER": "delete_picture", 342 "ART_ARROW_UP": "arrow_up", 343 "ART_ARROW_DOWN": "arrow_down", 344 "ART_ARROW_LEFT": "arrow_left", 345 "ART_ARROW_RIGHT": "arrow_right", 346 "ART_ADD_FIELD": "add_field", 347 "ART_DEL_FIELD": "delete_field", 348 "ART_ADD_CONTACT": "add_contact", 349 "ART_DEL_CONTACT": "delete_contact", 350 "ART_ADD_RINGER": "add_ringer", 351 "ART_DEL_RINGER": "delete_ringer", 352 "ART_ADD_MEMO": "add_memo", 353 "ART_DEL_MEMO": "delete_memo", 354 "ART_ADD_TODO": "add_todo", 355 "ART_DEL_TODO": "delete_todo", 356 "ART_ADD_SMS": "add_sms", 357 "ART_DEL_SMS": "delete_sms", 358 "ART_SEL_MEDIA": "select_media", 359 "ART_SEL_IMAGE": "select_image", 360 "ART_SEL_VIDEO": "select_video", 361 "ART_SEL_CAMERA": "select_camera", 362 "ART_SEL_SOUNDS": "select_sounds", 363 "ART_SEL_PHONEBOOK": "select_phonebook", 364 "ART_SEL_WALLPAPER": "select_wallpaper", 365 "ART_SEL_RINGERS": "select_ringers", 366 "ART_SEL_CALENDAR": "select_calendar", 367 "ART_SEL_CALLHISTORY": "select_call_history", 368 "ART_SEL_CALLS": "select_calls", 369 "ART_SEL_SMS": "select_sms", 370 "ART_SEL_MESSAGE": "select_message", 371 "ART_SEL_FILE": "select_file", 372 "ART_SEL_LOG": "select_log", 373 "ART_SEL_MEMO": "select_memo", 374 "ART_SEL_TODO": "select_todo", 375 "ART_SEL_PLAYLIST": "select_playlist", 376 "ART_SEL_PROTOCOL": "select_protocol", 377 "ART_SEL_CONSOLE": "select_console", 378 "ART_SEL_ROOT_IMAGE": "select_root", 379 "ART_SEL_PHONE_ROOT": "phone_root", 380 "ART_SEL_PHONE": "phone_root", 381 "ART_DATAGETPHONE": "datagetphone", 382 "ART_DATASENDPHONE": "datasendphone", 383 "ART_AUTOSYNCEXECUTE": "autosyncexecute", 384 "ART_HELPHELP": "helphelp", 385 "ART_EDITPHONEINFO": "editphoneinfo", 386 "ART_EDITDETECT": "editdetect", 387 "ART_EDITSETTINGS": "editsettings", 388 "ART_DATAHISTORICAL": "data_history", 389 "ART_MEDIA_LIST_VIEW": "media_list_view", 390 "ART_MEDIA_THUMB_VIEW": "media_thumb_view", 391 "ART_FOLDER_OPEN": "folder_open", 392 "ART_FOLDER": "folder" 393 }
394 395 # populate namespace 396 for s in _ourart: globals()[s]=s 397 398 -class ArtProvider(wx.ArtProvider):
399 """ArtProvider manages the art for the application""" 400
401 - def CreateBitmap(self, artid, client, size):
402 """Loads a bitmap and returns it depending on the parameters 403 """ 404 if artid in _ourart: 405 return getbitmap(_ourart[artid]) 406 return wx.NullBitmap
407
408 -class MultiMessageBox:
409
410 - def __init__(self, parent, title="Bitpim", dlg_msg=""):
411 self.__title=title 412 self.__dlg_msg=dlg_msg 413 self.__parent=parent 414 self.__msgs={}
415
416 - def AddMessage(self, msg, priority=99):
417 """ 418 Add a message to the list of messages to be displayed 419 Each message appears on it's own line 420 """ 421 # find the insertion point for the message 422 # the key is in the format "priority.index", this creates a unique key which is 423 # sortable in priority and insertion order 424 loop=0 425 key="%d.%05d" % (priority, loop) 426 while self.__msgs.has_key(key): 427 loop=loop+1 428 key="%d.%05d" % (priority, loop) 429 self.__msgs[key]={'msg': msg} 430 return
431
432 - def ShowMessages(self, max_rows=0, max_columns=0):
433 """ 434 Displays the messages in a list in a dialog 435 max_rows: Max visible messages, if number of messages exceed 436 this a scroll bar will appear 437 max_columns: Max visible width in characters 438 returns: button pressed to exit dialog 439 """ 440 keys=self.__msgs.keys() 441 keys.sort() 442 out_list=[] 443 for k in keys: 444 msg=self.__msgs[k]['msg'] 445 out_list.append(msg) 446 #construct the dialog for display 447 msg_dlg=wx.Dialog(self.__parent, -1, self.__title, 448 style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.SYSTEM_MENU|wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX) 449 main_bs=wx.BoxSizer(wx.VERTICAL) 450 main_bs.Add(wx.StaticText(msg_dlg, -1, self.__dlg_msg), 0, wx.ALL|wx.ALIGN_LEFT, 5) 451 msgs=wx.ListBox(msg_dlg) 452 msgs.Set(out_list) 453 main_bs.Add(msgs, 0, wx.ALL|wx.EXPAND, 5) 454 main_bs.Add(wx.Button(msg_dlg, wx.ID_OK, 'OK'), 0, wx.ALIGN_CENTRE|wx.ALL, 5) 455 msg_dlg.SetSizer(main_bs) 456 msg_dlg.SetAutoLayout(True) 457 main_bs.Fit(msg_dlg) 458 # show the dialog 459 res=msg_dlg.ShowModal() 460 print "multi "+`res` 461 msg_dlg.Destroy() 462 return res
463
464 - def MsgCount(self):
465 return len(self.__msgs)
466
467 - def ClearMessages(self):
468 self.__msgs.clear()
469