1
2
3
4
5
6
7
8
9
10 """The main gui code for BitPim"""
11
12
13 from __future__ import with_statement
14 import contextlib
15 import thread, threading
16 import Queue
17 import time
18 import os
19 import cStringIO
20 import zipfile
21 import re
22 import sys
23 import shutil
24 import types
25 import datetime
26 import sha
27 import codecs
28
29
30 import wx
31 import wx.lib.colourdb
32 import wx.html
33
34
35 import guiwidgets
36 import common
37 import version
38 import helpids
39 import comdiagnose
40 import phonebook
41 import importexport
42 import guihelper
43 import bphtml
44 import bitflingscan
45 import update
46 import phoneinfo
47 import phone_detect
48 import phone_media_codec
49 import pubsub
50 import phones.com_brew as com_brew
51 import auto_sync
52 import phone_root
53 import playlist
54 import fileview
55 import data_recording
56 import analyser
57 import t9editor
58 import newdb_wiz
59 import bp_config
60
61 if guihelper.IsMSWindows():
62 import win32api
63 import win32con
64 import win32gui
65 import msvcrt
66 else:
67 import fcntl
68
69
70
71
72 mainthreadid=thread.get_ident()
73 helperthreadid=-1
74
75
76
77
78 if guihelper.IsMSWindows():
85
87 _menu=wx.Menu()
88 _id=wx.NewId()
89 if self.mw.IsIconized():
90 _menu.Append(_id, 'Restore')
91 wx.EVT_MENU(self, _id, self.OnRestore)
92 else:
93 _menu.Append(_id, 'Minimize')
94 wx.EVT_MENU(self, _id, self.OnMinimize)
95 _menu.AppendSeparator()
96 _id=wx.NewId()
97 _menu.Append(_id, 'Close')
98 wx.EVT_MENU(self, _id, self.OnClose)
99 return _menu
100
102 _icon=wx.Icon(guihelper.getresourcefile('bitpim.ico'),
103 wx.BITMAP_TYPE_ICO)
104 if _icon.Ok():
105 self.SetIcon(_icon, 'BitPim')
106
110 self.mw.Iconize(False)
111 wx.PostEvent(self.mw, wx.IconizeEvent(self.mw.GetId(), False))
113 self.mw.Iconize(False)
115 self.mw.Iconize(True)
117 self.RemoveIcon()
118 self.mw.Close()
119
120
121
122
123
125 "Callback class. Extra arguments can be supplied at call time"
126 - def __init__(self, method, *args, **kwargs):
127 if __debug__:
128 global mainthreadid
129 assert mainthreadid==thread.get_ident()
130 self.method=method
131 self.args=args
132 self.kwargs=kwargs
133
135 if __debug__:
136 global mainthreadid
137 assert mainthreadid==thread.get_ident()
138 d=self.kwargs.copy()
139 d.update(kwargs)
140 apply(self.method, self.args+args, d)
141
143 - def __init__(self, method, *args, **kwargs):
144
145 if __debug__:
146 global mainthreadid
147 assert mainthreadid==thread.get_ident()
148 self.method=method
149 self.args=args
150 self.kwargs=kwargs
151
160
161
162
163
164
165
167 - def __init__(self, callback, *args, **kwargs):
178
180 if __debug__:
181 global mainthreadid
182
183 return apply(self.cb, self.args, self.kwargs)
184
185
186
187
188
189 thesplashscreen=None
190
210
212 dc=wx.MemoryDC()
213 dc.SelectObject(bmp)
214
215 x=23
216 y=40
217
218 if False:
219 str=version.name
220 dc.SetTextForeground( wx.NamedColour("MEDIUMORCHID4") )
221 dc.SetFont( self._gimmethedamnsizeirequested(25, wx.ROMAN, wx.NORMAL, wx.NORMAL) )
222 w,h=dc.GetTextExtent(str)
223 dc.DrawText(str, x, y)
224 y+=h+0
225
226 x=58
227 y=127
228 str=version.versionstring+"-"+version.vendor
229 dc.SetTextForeground( wx.NamedColour("MEDIUMBLUE") )
230 dc.SetFont( self._gimmethedamnsizeirequested(15, wx.ROMAN, wx.NORMAL, wx.NORMAL) )
231 w,h=dc.GetTextExtent(str)
232 dc.DrawText(str, x+10, y)
233 y+=h+0
234
235 dc.SelectObject(wx.NullBitmap)
236
238
239 if guihelper.IsGtk():
240 ps=ps*1.6
241 font=wx.TheFontList.FindOrCreateFont(int(ps), family, style, weight)
242 return font
243
246
250
253
256 threading.Thread.__init__(self, name="BitPim helper")
257 self.q=Queue.Queue()
258
260 self.dispatchto=dispatchto
261
267
269 global helperthreadid
270 helperthreadid=thread.get_ident()
271 first=1
272 while True:
273 if not first:
274 wx.PostEvent(self.dispatchto, HelperReturnEvent(self.dispatchto.endbusycb))
275 else:
276 first=0
277 item=self.q.get()
278 wx.PostEvent(self.dispatchto, HelperReturnEvent(self.dispatchto.startbusycb))
279 call=item[0]
280 resultcb=item[1]
281 ex=None
282 res=None
283 try:
284 res=call()
285 except Exception,e:
286 ex=e
287 if not hasattr(e,"gui_exc_info"):
288 ex.gui_exc_info=sys.exc_info()
289
290 wx.PostEvent(self.dispatchto, HelperReturnEvent(resultcb, ex, res))
291 if isinstance(ex, BitPimExit):
292
293 break
294
297
300
303
304 - def log(self, str):
305 if self.dispatchto.wantlog:
306 wx.PostEvent(self.dispatchto, HelperReturnEvent(self.dispatchto.logcb, str))
307
308 - def logdata(self, str, data, klass=None, data_type=None):
309 if self.dispatchto.wantlog:
310 wx.PostEvent(self.dispatchto, HelperReturnEvent(self.dispatchto.logdatacb, str, data, klass,
311 data_type))
312
313
314
315
316
317
320
324
325 _NotSafeObject=_NotSafeObject()
326
328 """Simple Event class that supports Context Manager"""
330 self._event=threading.Event()
333 - def __exit__(self, exc_type, exc_value, tb):
336 return self._event.set()
338 return self._event.clear()
340 return self._event.isSet()
341 - def wait(self, timeout=None):
342 return self._event.wait(timeout)
343
344 EVT_CALLBACK=None
345 -class MainApp(wx.App):
346 - def __init__(self, argv, config_filename=None):
347 self.frame=None
348 self.SAFEMODE=False
349 codecs.register(phone_media_codec.search_func)
350 self._config_filename=config_filename
351
352 self.critical=Event()
353 wx.App.__init__(self, redirect=False,
354 useBestVisual=not guihelper.IsGtk())
355
356 - def lock_file(self, filename):
357
358
359 try:
360 self.lockedfile=file(filename, 'w')
361 except IOError:
362
363 self.lockedfile=None
364 return True
365 try:
366 if guihelper.IsMSWindows():
367 msvcrt.locking(self.lockedfile.fileno(),
368 msvcrt.LK_NBLCK, 1)
369 else:
370
371 fcntl.flock(self.lockedfile.fileno(),
372 fcntl.LOCK_EX|fcntl.LOCK_NB)
373 return True
374 except IOError:
375 return False
376
377 - def usingsamedb(self):
378
379 return not self.lock_file(os.path.join(self.config._path, '.lock'))
380
382 self.made=False
383
384 wx.lib.colourdb.updateColourDB()
385
386
387 global mainthreadid
388 mainthreadid=thread.get_ident()
389
390
391 cfgstr='bitpim'
392 self.SetAppName(cfgstr)
393 self.SetVendorName(cfgstr)
394
395
396 self.config=bp_config.Config(self._config_filename)
397
398 if self.usingsamedb():
399 guihelper.MessageDialog(None, 'Another copy of BitPim is using the same data dir:\n%s'%self.config._path,
400 'BitPim Error',
401 style=wx.OK|wx.ICON_ERROR)
402 return False
403
404 self.wxconfig=wx.Config(cfgstr, style=wx.CONFIG_USE_LOCAL_FILE)
405
406
407 self.SAFEMODE=self.config.ReadInt("SafeMode", False)
408
409
410
411
412 self.helpcontroller=None
413
414
415 self.htmlprinter=bphtml.HtmlEasyPrinting(None, self.config, "printing")
416
417 global EVT_CALLBACK
418 EVT_CALLBACK=wx.NewEventType()
419
420
421 com_brew.file_cache=com_brew.FileCache(self.config.Read('path', ''))
422
423
424 MySplashScreen(self, self.config)
425
426 return True
427
428 - def ApplySafeMode(self):
429
430 if not self.SAFEMODE:
431 return
432 if self.frame is None:
433 return
434
435 objects={self.frame:
436 ( "dlgsendphone", "OnDataSendPhone", "OnDataSendPhoneGotFundamentals", "OnDataSendPhoneResults"),
437 self.frame.tree.filesystemwidget:
438 ( "OnFileDelete", "OnFileOverwrite", "OnNewSubdir", "OnNewFile", "OnDirDelete", "OnRestore"),
439 self.frame.wt:
440 ( "senddata", "writewallpaper", "writeringtone", "writephonebook", "writecalendar", "rmfile",
441 "writefile", "mkdir", "rmdir", "rmdirs", "restorefiles" ),
442 self.frame.phoneprofile:
443 ( "convertphonebooktophone", ),
444 self.frame.phonemodule.Phone:
445 ( "mkdir", "mkdirs", "rmdir", "rmfile", "rmdirs", "writefile", "savegroups", "savephonebook",
446 "savecalendar", "savewallpapers", "saveringtones")
447 }
448
449 for obj, names in objects.iteritems():
450 if obj is None:
451 continue
452 for name in names:
453 field=getattr(obj, name, None)
454 if field is None or field is _notsafefunc or field is _NotSafeObject:
455 continue
456 if isinstance(field, (types.MethodType, types.FunctionType)):
457 newval=_notsafefunc
458 else: newval=_NotSafeObject
459 setattr(obj, name, newval)
460
461
462 removeids=(guihelper.ID_DATASENDPHONE, guihelper.ID_FV_OVERWRITE, guihelper.ID_FV_NEWSUBDIR,
463 guihelper.ID_FV_NEWFILE, guihelper.ID_FV_DELETE, guihelper.ID_FV_RENAME,
464 guihelper.ID_FV_RESTORE, guihelper.ID_FV_ADD)
465 mb=self.frame.GetMenuBar()
466 menus=[mb.GetMenu(i) for i in range(mb.GetMenuCount())]
467 fsw=self.frame.tree.filesystemwidget
468 if fsw is not None:
469 menus.extend( [fsw.list.filemenu, fsw.tree.dirmenu, fsw.list.genericmenu] )
470 for menu in menus:
471 for id in removeids:
472 item=menu.FindItemById(id)
473 if item is not None:
474 menu.RemoveItem(item)
475
476
477
478
479
480
481
482
483
484 - def _setuphelp(self):
485 """Does all the nonsense to get help working"""
486 if guihelper.IsMSWindows():
487 self.helpcontroller=True
488 return
489 elif guihelper.IsMac():
490
491 from Carbon import AH
492 path=os.path.abspath(os.path.join(guihelper.resourcedirectory, "..", "..", ".."))
493
494 if os.path.exists(path) and path.endswith(".app"):
495 res=AH.AHRegisterHelpBook(path)
496 self.helpcontroller=True
497 return
498
499
500
501
502 wx.FileSystem_AddHandler(wx.ZipFSHandler())
503
504 self.helpcontroller=wx.html.HtmlHelpController()
505 self.helpcontroller.AddBook(guihelper.gethelpfilename()+".htb")
506 self.helpcontroller.UseConfig(self.wxconfig, "help")
507
508
509
510
511
512
513 - def displayhelpid(self, id):
514 """Display a specific Help Topic"""
515 if self.helpcontroller is None:
516 self._setuphelp()
517
518 if guihelper.IsMSWindows():
519 import win32help
520 fname=guihelper.gethelpfilename()+".chm>Help"
521 if id is None:
522 id=helpids.ID_WELCOME
523
524 _hwnd=win32gui.GetDesktopWindow()
525 win32help.HtmlHelp(_hwnd, fname, win32help.HH_DISPLAY_TOPIC, id)
526
527 win32help.HtmlHelp(_hwnd, fname, win32help.HH_SYNC, id)
528
529 elif guihelper.IsMac() and self.helpcontroller is True:
530 from Carbon import AH
531 res=AH.AHGotoPage('BitPim Help', id, None)
532
533 else:
534 if id is None:
535 self.helpcontroller.DisplayContents()
536 else:
537 self.helpcontroller.Display(id)
538
539 - def makemainwindow(self):
540 if self.made:
541 return
542 self.made=True
543
544 title='BitPim'
545 name=self.config.Read('name', None)
546 if name:
547 title+=' - '+name
548 self.frame=MainWindow(None, -1, title, self.config)
549 self.frame.Connect(-1, -1, EVT_CALLBACK, self.frame.OnCallback)
550 if guihelper.IsMac():
551 self.frame.MacSetMetalAppearance(True)
552
553
554 wt=WorkerThread()
555 wt.setdispatch(self.frame)
556 wt.setDaemon(1)
557 wt.start()
558 self.frame.wt=wt
559 self.SetTopWindow(self.frame)
560 self.SetExitOnFrameDelete(True)
561 self.ApplySafeMode()
562 wx.CallAfter(self.CheckDetectPhone)
563 wx.CallAfter(self.CheckUpdate)
564
565 if self.lockedfile is None:
566 self.usingsamedb()
567
568 update_delta={ 'Daily': 1, 'Weekly': 7, 'Monthly': 30 }
569 - def CheckUpdate(self):
570 if version.isdevelopmentversion():
571 return
572 if self.frame is None:
573 return
574
575 update_rate=self.config.Read('updaterate', '')
576 if not len(update_rate) or update_rate =='Never':
577 return
578 last_update=self.config.Read('last_update', '')
579 try:
580 if len(last_update):
581 last_date=datetime.date(int(last_update[:4]), int(last_update[4:6]),
582 int(last_update[6:]))
583 next_date=last_date+datetime.timedelta(\
584 self.update_delta.get(update_rate, 7))
585 else:
586 next_date=last_date=datetime.date.today()
587 except ValueError:
588
589 next_date=last_date=datetime.date.today()
590 if datetime.date.today()<next_date:
591 return
592 self.frame.AddPendingEvent(\
593 wx.PyCommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED,
594 guihelper.ID_HELP_UPDATE))
595
597 if self.config.ReadInt('autodetectstart', 0) or self.frame.needconfig:
598 self.frame.AddPendingEvent(
599 wx.PyCommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED,
600 guihelper.ID_EDITDETECT))
601
603 self.config.Flush()
604
605
606
607
608 sys.excepthook=donothingexceptionhandler
609
610 - def ExitMainLoop(self):
611 if guihelper.IsGtk():
612
613 self.OnExit()
614 sys.exit(0)
615 super(MainApp, self).ExitMainLoop()
616
617
620
621
622 -def run(argv, kwargs):
623 return MainApp(argv, **kwargs).MainLoop()
624
625
626
627
628
630 "A wrapper to help with callbacks that ignores arguments when invoked"
632 self.func=func
633 self.args=args
634 self.kwargs=kwargs
635
637 return self.func(*self.args, **self.kwargs)
638
639 -class MainWindow(wx.Frame):
640 - def __init__(self, parent, id, title, config):
641 wx.Frame.__init__(self, parent, id, title,
642 style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
643 wx.GetApp().frame=self
644
645 wx.GetApp().htmlprinter.SetParentFrame(self)
646
647 sys.excepthook=Callback(self.excepthook)
648
649 self.wt=None
650 self.progressminorcb=Callback(self.OnProgressMinor)
651 self.progressmajorcb=Callback(self.OnProgressMajor)
652 self.logcb=Callback(self.OnLog)
653 self.logdatacb=Callback(self.OnLogData)
654 self.startbusycb=Callback(self.OnBusyStart)
655 self.endbusycb=Callback(self.OnBusyEnd)
656 self.queue=Queue.Queue()
657
658
659 self.exceptiondialog=None
660 self.wantlog=1
661 self.config=config
662 self.progmajortext=""
663 self.__owner_name=''
664
665 self._taskbar=None
666 self._taskbar_on_closed=False
667 self._close_button=False
668 self.__phone_detect_at_startup=False
669 self._autodetect_delay=0
670 self._dr_rec=None
671 self._dr_play=None
672
673
674
675 sb=guiwidgets.MyStatusBar(self)
676 self.SetStatusBar(sb)
677 self.SetStatusBarPane(sb.GetHelpPane())
678
679
680
681
682 wx.ArtProvider.PushProvider(guihelper.ArtProvider())
683
684
685 ib=wx.IconBundle()
686 ib.AddIconFromFile(guihelper.getresourcefile("bitpim.ico"), wx.BITMAP_TYPE_ANY)
687 self.SetIcons(ib)
688
689
690
691 menuBar = wx.MenuBar()
692 menu = wx.Menu()
693
694
695
696 menu.Append(guihelper.ID_FILEPRINT, "&Print...", "Print phonebook")
697
698
699
700 impmenu=wx.Menu()
701 for x, desc, help, func in importexport.GetPhonebookImports():
702 if isinstance(func, tuple):
703
704 _submenu=wx.Menu()
705 for _id, _desc, _help, _func in func:
706 _submenu.Append(_id, _desc, _help)
707 if _func:
708 wx.EVT_MENU(self, _id, MenuCallback(_func, self))
709 impmenu.AppendMenu(x, desc, _submenu, help)
710 else:
711 impmenu.Append(x, desc, help)
712 wx.EVT_MENU(self, x, MenuCallback(func, self) )
713
714 menu.AppendMenu(guihelper.ID_FILEIMPORT, "&Import", impmenu)
715
716
717 expmenu=wx.Menu()
718 for x, desc, help, func in importexport.GetPhonebookExports():
719 expmenu.Append(x, desc, help)
720 wx.EVT_MENU(self, x, MenuCallback(func, self) )
721
722 menu.AppendMenu(guihelper.ID_FILEEXPORT, "&Export", expmenu)
723
724 if not guihelper.IsMac():
725 menu.AppendSeparator()
726 menu.Append(guihelper.ID_FILEEXIT, "E&xit", "Close down this program")
727 menuBar.Append(menu, "&File");
728 self.__menu_edit=menu=wx.Menu()
729 menu.Append(guihelper.ID_EDITSELECTALL, "&Select All\tCtrl+A", "Select All")
730 menu.AppendSeparator()
731 menu.Append(guihelper.ID_EDITADDENTRY, "&New...\tCtrl+N", "Add an item")
732 menu.Append(guihelper.ID_EDITCOPY, "&Copy\tCtrl+C", "Copy to the clipboard")
733 menu.Append(guihelper.ID_EDITPASTE,"&Paste\tCtrl+V", "Paste from the clipboard")
734 menu.Append(guihelper.ID_EDITDELETEENTRY, "&Delete", "Delete currently selected entry")
735 menu.Append(guihelper.ID_EDITRENAME, "&Rename\tF2", "Rename currently selected entry")
736 menu.AppendSeparator()
737 menu.Append(guihelper.ID_EDITDETECT,
738 "D&etect Phone", "Auto Detect Phone")
739 if guihelper.IsMac():
740 wx.App_SetMacPreferencesMenuItemId(guihelper.ID_EDITSETTINGS)
741 menu.Append(guihelper.ID_EDITSETTINGS, "Pre&ferences...", "Edit Settings")
742 else:
743 menu.AppendSeparator()
744 menu.Append(guihelper.ID_EDITSETTINGS, "&Settings", "Edit settings")
745 menuBar.Append(menu, "&Edit");
746
747 menu=wx.Menu()
748 menu.Append(guihelper.ID_DATAGETPHONE, "Get Phone &Data ...", "Loads data from the phone")
749 menu.Append(guihelper.ID_DATASENDPHONE, "&Send Phone Data ...", "Sends data to the phone")
750 menu.Append(guihelper.ID_DATAHISTORICAL, "&Historical Data ...", "View Current & Historical Data")
751 menu.AppendSeparator()
752 menu.Append(guihelper.ID_DATANEWDB, 'Create New Storage ...',
753 'Create a New BitPim Storage Area')
754 menuBar.Append(menu, "&Data")
755
756 menu=wx.Menu()
757 menu.Append(guihelper.ID_VIEWCOLUMNS, "&Columns ...", "Which columns to show")
758 menu.AppendCheckItem(guihelper.ID_VIEWPREVIEW, "&Phonebook Preview", "Toggle Phonebook Preview Pane")
759 menu.AppendSeparator()
760 menu.AppendCheckItem(guihelper.ID_VIEWLOGDATA, "&View protocol logging", "View protocol logging information")
761 menu.Append(guihelper.ID_VIEWCLEARLOGS, "Clear &Logs", "Clears the contents of the log panes")
762 menu.AppendSeparator()
763 menu.AppendCheckItem(guihelper.ID_VIEWFILESYSTEM, "View &Filesystem", "View filesystem on the phone")
764 menu.AppendSeparator()
765 menu.Append(guihelper.ID_EDITPHONEINFO,
766 "Phone &Info", "Display Phone Information")
767 menuBar.Append(menu, "&View")
768
769 menu=wx.Menu()
770 menu.Append(guihelper.ID_DR_SETTINGS, '&Data Recording',
771 'Data Recording Settings')
772
773
774 menuBar.Append(menu, "De&bug")
775
776 menu=wx.Menu()
777 if guihelper.IsMac():
778 menu.Append(guihelper.ID_HELPHELP, "&Help on this panel", "Help for the panel you are looking at")
779 else:
780 menu.Append(guihelper.ID_HELPHELP, "&Help", "Help for the panel you are looking at")
781 menu.Append(guihelper.ID_HELPTOUR, "&Tour", "Tour of BitPim")
782 menu.Append(guihelper.ID_HELPCONTENTS, "&Contents", "Table of contents for the online help")
783 menu.Append(guihelper.ID_HELPHOWTOS, "H&owTos", "Help on how to do certain function")
784 menu.Append(guihelper.ID_HELPFAQ, "&FAQ", "Frequently Asked Questions")
785 menu.Append(guihelper.ID_HELPSUPPORT, "&Support", "Getting support for BitPim")
786 menu.Append(guihelper.ID_HELPPHONE, "Your &Phone", "Help on specific phonemodel")
787 if version.vendor=='official':
788 menu.AppendSeparator()
789 menu.Append(guihelper.ID_HELP_UPDATE, "&Check for Update", "Check for any BitPim Update")
790 if guihelper.IsMac():
791 wx.App_SetMacAboutMenuItemId(guihelper.ID_HELPABOUT)
792 menu.Append(guihelper.ID_HELPABOUT, "&About BitPim", "Display program information")
793 wx.App_SetMacHelpMenuTitleName("&Help")
794 wx.App_SetMacExitMenuItemId(guihelper.ID_FILEEXIT)
795 else:
796 menu.AppendSeparator()
797 menu.Append(guihelper.ID_HELPABOUT, "&About", "Display program information")
798 menuBar.Append(menu, "&Help");
799 self.SetMenuBar(menuBar)
800
801
802 self.tb=self.CreateToolBar(wx.TB_HORIZONTAL)
803 self.tb.SetToolBitmapSize(wx.Size(32,32))
804 sz=self.tb.GetToolBitmapSize()
805
806
807 self.tb.AddSimpleTool(guihelper.ID_DATAGETPHONE, wx.ArtProvider.GetBitmap(guihelper.ART_DATAGETPHONE, wx.ART_TOOLBAR, sz),
808 "Get Phone Data", "Synchronize BitPim with Phone")
809 self.tb.AddLabelTool(guihelper.ID_DATASENDPHONE, "Send Phone Data", wx.ArtProvider.GetBitmap(guihelper.ART_DATASENDPHONE, wx.ART_TOOLBAR, sz),
810 shortHelp="Send Phone Data", longHelp="Synchronize Phone with BitPim")
811 self.tb.AddLabelTool(guihelper.ID_DATAHISTORICAL, "BitPim Help", wx.ArtProvider.GetBitmap(guihelper.ART_DATAHISTORICAL, wx.ART_TOOLBAR, sz),
812 shortHelp="Historical Data", longHelp="Show Historical Data")
813 self.tb.AddSeparator()
814 self.tb.AddLabelTool(guihelper.ID_EDITADDENTRY, "Add", wx.ArtProvider.GetBitmap(wx.ART_ADD_BOOKMARK, wx.ART_TOOLBAR, sz),
815 shortHelp="Add", longHelp="Add an item")
816 self.tb.AddLabelTool(guihelper.ID_EDITDELETEENTRY, "Delete", wx.ArtProvider.GetBitmap(wx.ART_DEL_BOOKMARK, wx.ART_TOOLBAR, sz),
817 shortHelp="Delete", longHelp="Delete item")
818 self.tb.AddLabelTool(guihelper.ID_EDITPHONEINFO, "Phone Info", wx.ArtProvider.GetBitmap(guihelper.ART_EDITPHONEINFO, wx.ART_TOOLBAR, sz),
819 shortHelp="Phone Info", longHelp="Show Phone Info")
820 self.tb.AddLabelTool(guihelper.ID_EDITDETECT, "Find Phone", wx.ArtProvider.GetBitmap(guihelper.ART_EDITDETECT, wx.ART_TOOLBAR, sz),
821 shortHelp="Find Phone", longHelp="Find Phone")
822 self.tb.AddLabelTool(guihelper.ID_EDITSETTINGS, "Edit Settings", wx.ArtProvider.GetBitmap(guihelper.ART_EDITSETTINGS, wx.ART_TOOLBAR, sz),
823 shortHelp="Edit Settings", longHelp="Edit BitPim Settings")
824 self.tb.AddSeparator()
825 self.tb.AddSimpleTool(guihelper.ID_AUTOSYNCEXECUTE, wx.ArtProvider.GetBitmap(guihelper.ART_AUTOSYNCEXECUTE, wx.ART_TOOLBAR, sz),
826 "Autosync Calendar", "Synchronize Phone Calendar with PC")
827 self.tb.AddSeparator()
828 self.tb.AddLabelTool(guihelper.ID_HELPHELP, "BitPim Help", wx.ArtProvider.GetBitmap(guihelper.ART_HELPHELP, wx.ART_TOOLBAR, sz),
829 shortHelp="BitPim Help", longHelp="BitPim Help")
830
831
832
833 self.tb.Realize()
834
835
836 self.dlggetphone=guiwidgets.GetPhoneDialog(self, "Get Data from Phone")
837 self.dlgsendphone=guiwidgets.SendPhoneDialog(self, "Send Data to Phone")
838
839
840 self.sw=wx.SplitterWindow(self, wx.NewId(), style=wx.SP_3D|wx.SP_NO_XP_THEME|wx.SP_LIVE_UPDATE)
841
842
843 self.tree = phone_root.PhoneTree(self.sw, self, wx.NewId())
844
845
846 wx.EVT_MENU(self, guihelper.ID_FILEPRINT, self.tree.OnFilePrint)
847 wx.EVT_MENU(self, guihelper.ID_FILEEXIT, self.OnExit)
848 wx.EVT_MENU(self, guihelper.ID_EDITSETTINGS, self.OnEditSettings)
849 wx.EVT_MENU(self, guihelper.ID_DATAGETPHONE, self.OnDataGetPhone)
850 wx.EVT_MENU(self, guihelper.ID_DATASENDPHONE, self.OnDataSendPhone)
851 wx.EVT_MENU(self, guihelper.ID_DATAHISTORICAL, self.tree.OnDataHistorical)
852 wx.EVT_MENU(self, guihelper.ID_DATANEWDB, self.OnNewDB)
853 wx.EVT_MENU(self, guihelper.ID_VIEWCOLUMNS, self.tree.OnViewColumns)
854 wx.EVT_MENU(self, guihelper.ID_VIEWPREVIEW, self.tree.OnViewPreview)
855 wx.EVT_MENU(self, guihelper.ID_VIEWCLEARLOGS, self.tree.OnViewClearLogs)
856 wx.EVT_MENU(self, guihelper.ID_VIEWLOGDATA, self.tree.OnViewLogData)
857 wx.EVT_MENU(self, guihelper.ID_VIEWFILESYSTEM, self.tree.OnViewFilesystem)
858 wx.EVT_MENU(self, guihelper.ID_EDITADDENTRY, self.tree.OnEditAddEntry)
859 wx.EVT_MENU(self, guihelper.ID_EDITDELETEENTRY, self.tree.OnEditDeleteEntry)
860 wx.EVT_MENU(self, guihelper.ID_EDITSELECTALL, self.tree.OnEditSelectAll)
861 wx.EVT_MENU(self, guihelper.ID_EDITCOPY, self.tree.OnCopyEntry)
862 wx.EVT_MENU(self, guihelper.ID_EDITPASTE, self.tree.OnPasteEntry)
863 wx.EVT_MENU(self, guihelper.ID_EDITRENAME, self.tree.OnRenameEntry)
864 wx.EVT_MENU(self, guihelper.ID_HELPABOUT, self.OnHelpAbout)
865 wx.EVT_MENU(self, guihelper.ID_HELPHELP, self.OnHelpHelp)
866 wx.EVT_MENU(self, guihelper.ID_HELPCONTENTS, self.OnHelpContents)
867 wx.EVT_MENU(self, guihelper.ID_HELPHOWTOS, self.OnHelpHowtos)
868 wx.EVT_MENU(self, guihelper.ID_HELPFAQ, self.OnHelpFAQ)
869 wx.EVT_MENU(self, guihelper.ID_HELPSUPPORT, self.OnHelpSupport)
870 wx.EVT_MENU(self, guihelper.ID_HELPTOUR, self.OnHelpTour)
871 wx.EVT_MENU(self, guihelper.ID_HELP_UPDATE, self.OnCheckUpdate)
872 wx.EVT_MENU(self, guihelper.ID_HELPPHONE, self.OnHelpPhone)
873 wx.EVT_MENU(self, guihelper.ID_EDITPHONEINFO, self.OnPhoneInfo)
874 wx.EVT_MENU(self, guihelper.ID_EDITDETECT, self.OnDetectPhone)
875 wx.EVT_MENU(self, guihelper.ID_AUTOSYNCSETTINGS, self.OnAutoSyncSettings)
876 wx.EVT_MENU(self, guihelper.ID_AUTOSYNCEXECUTE, self.OnAutoSyncExecute)
877 wx.EVT_MENU(self, guihelper.ID_DR_SETTINGS, self.OnDataRecording)
878 wx.EVT_CLOSE(self, self.OnClose)
879
880
881
882 if min(self.GetSize())<250:
883 self.SetSize( (640, 480) )
884
885
886 self.configdlg=guiwidgets.ConfigDialog(self, self)
887 self.needconfig=self.configdlg.needconfig()
888 self.configdlg.updatevariables()
889
890 pos=self.config.ReadInt("mainwindowsplitterpos", 200)
891 self.tree.active_panel.OnPreActivate()
892 self.sw.SplitVertically(self.tree, self.tree.active_panel, pos)
893 self.tree.active_panel.OnPostActivate()
894 self.sw.SetMinimumPaneSize(50)
895 wx.EVT_SPLITTER_SASH_POS_CHANGED(self, id, self.OnSplitterPosChanged)
896 self.tree.Expand(self.tree.root)
897
898
899
900 self.tree.CreatePhone("Phone", self.config, self.configpath, "bitpim.db")
901
902
903
904 self.calenders=importexport.GetCalenderAutoSyncImports()
905 self.autosyncsetting=auto_sync.AutoSyncSettingsDialog(self, self)
906 self.autosyncsetting.updatevariables()
907 self.CloseSplashScreen()
908
909
910 wx.EVT_UPDATE_UI(self, guihelper.ID_AUTOSYNCEXECUTE, self.AutosyncUpdateUIEvent)
911 wx.EVT_UPDATE_UI(self, guihelper.ID_DATASENDPHONE, self.tree.DataSendPhoneUpdateUIEvent)
912 wx.EVT_UPDATE_UI(self, guihelper.ID_EDITDELETEENTRY, self.tree.DataDeleteItemUpdateUIEvent)
913 wx.EVT_UPDATE_UI(self, guihelper.ID_EDITADDENTRY, self.tree.DataAddItemUpdateUIEvent)
914 wx.EVT_UPDATE_UI(self, guihelper.ID_DATAHISTORICAL, self.tree.HistoricalDataUpdateUIEvent)
915 wx.EVT_UPDATE_UI(self, guihelper.ID_VIEWCOLUMNS, self.tree.ViewColumnsUpdateUIEvent)
916 wx.EVT_UPDATE_UI(self, guihelper.ID_VIEWPREVIEW, self.tree.ViewPreviewDataUpdateUIEvent)
917 wx.EVT_UPDATE_UI(self, guihelper.ID_FILEPRINT, self.tree.FilePrintDataUpdateUIEvent)
918 wx.EVT_UPDATE_UI(self, guihelper.ID_EDITSELECTALL, self.tree.SelectAllDataUpdateUIEvent)
919 wx.EVT_UPDATE_UI(self, guihelper.ID_EDITCOPY, self.tree.EditCopyUpdateUIEvent)
920 wx.EVT_UPDATE_UI(self, guihelper.ID_EDITPASTE, self.tree.EditPasteUpdateUIEvent)
921 wx.EVT_UPDATE_UI(self, guihelper.ID_EDITRENAME, self.tree.EditRenameUpdateUIEvent)
922 wx.EVT_UPDATE_UI(self, guihelper.ID_VIEWLOGDATA, self.tree.ViewLogDataUIEvent)
923 wx.EVT_UPDATE_UI(self, guihelper.ID_VIEWFILESYSTEM, self.tree.ViewFileSystemUIEvent)
924 wx.EVT_UPDATE_UI(self, guihelper.ID_HELPPHONE, self.OnHelpPhoneUpdateUI)
925
926
927 guiwidgets.set_size("MainWin", self, screenpct=90)
928
929
930 self.Show()
931
932
933 if self.config.ReadInt("firstrun", True):
934 self.config.WriteInt("firstrun", False)
935 self.config.Flush()
936 wx.CallAfter(self.OnHelpTour)
937
938
939 if guihelper.IsMSWindows():
940 if self.config.ReadInt('taskbaricon', 0):
941 self._taskbar=TaskBarIcon(self)
942 self._taskbar_on_closed=self.config.ReadInt('taskbaricon1', 0)
943
944 self.oldwndproc = win32gui.SetWindowLong(self.GetHandle(),
945 win32con.GWL_WNDPROC,
946 self.MyWndProc)
947 if self._taskbar and self._taskbar.IsOk():
948 wx.EVT_ICONIZE(self, self.OnIconize)
949
950
951 pubsub.subscribe(self.OnReqChangeTab, pubsub.REQUEST_TAB_CHANGED)
952
953 self._setup_midnight_timer()
954
955 if self.IsIconized() and self._taskbar:
956
957
958 wx.CallAfter(self.Show, False)
959 self.GetStatusBar().set_app_status_ready()
960
961 if guihelper.IsGtk():
962 import comm_notify
963 comm_notify.start_server(self)
964
966 pos=self.sw.GetSashPosition()
967 self.config.WriteInt("mainwindowsplitterpos", pos)
968
969 - def SetActivePanel(self, panel):
970 w2=self.sw.GetWindow2()
971 if w2 is None or w2 is panel:
972 return
973 panel.OnPreActivate()
974 w2.Show(False)
975 self.sw.ReplaceWindow(w2, panel)
976 panel.Show(True)
977 panel.SetFocus()
978 panel.OnPostActivate()
979
982
985
988
991
994
997
1000
1003
1006
1009
1012
1015
1017 return self.tree.GetActivePhone().GetDatabase()
1018
1020 sz=self.tb.GetToolBitmapSize()
1021 pos=self.GetToolBar().GetToolPos(guihelper.ID_EDITADDENTRY)
1022 self.GetToolBar().DeleteTool(guihelper.ID_EDITADDENTRY)
1023 self.tooladd=self.tb.InsertLabelTool(pos, guihelper.ID_EDITADDENTRY, add_help,
1024 wx.ArtProvider.GetBitmap(add_image, wx.ART_TOOLBAR, sz),
1025 shortHelp=add_help, longHelp="Add an item")
1026 pos=self.GetToolBar().GetToolPos(guihelper.ID_EDITDELETEENTRY)
1027 self.GetToolBar().DeleteTool(guihelper.ID_EDITDELETEENTRY)
1028 self.tooldelete=self.tb.InsertLabelTool(pos, guihelper.ID_EDITDELETEENTRY, delete_help,
1029 wx.ArtProvider.GetBitmap(delete_image, wx.ART_TOOLBAR, sz),
1030 shortHelp=delete_help, longHelp="Delete item")
1031 self.tb.Realize()
1032
1033
1035
1036 global thesplashscreen
1037 if thesplashscreen is not None:
1038 try:
1039
1040 thesplashscreen.Show(False)
1041 except:
1042 pass
1043 thesplashscreen=None
1044 wx.SafeYield(onlyIfNeeded=True)
1045
1046 - def AutosyncUpdateUIEvent(self, event):
1047 event.Enable(self.autosyncsetting.IsConfigured())
1048
1049 - def OnExit(self,_=None):
1051
1052
1053 - def OnClose(self, event):
1054 if self._taskbar_on_closed and self._close_button and \
1055 event.CanVeto():
1056 self._close_button=False
1057 event.Veto()
1058 self.Iconize(True)
1059 return
1060 if not self.IsIconized():
1061 self.saveSize()
1062 if not self.wt:
1063
1064 self.Destroy()
1065 return
1066
1067 self.MakeCall( Request(self.wt.exit), Callback(self.OnCloseResults) )
1068
1069 - def OnCloseResults(self, exception, _):
1070 assert isinstance(exception, BitPimExit)
1071
1072 if self._taskbar:
1073 self._taskbar.Destroy()
1074 self.Destroy()
1075
1076 - def OnIconize(self, evt):
1077 if evt.Iconized():
1078 self.Show(False)
1079 else:
1080 self.Show(True)
1081 self.Raise()
1082
1083
1084 - def OnEditSettings(self, _=None):
1085 if wx.IsBusy():
1086 wx.MessageBox("BitPim is busy. You can't change settings until it has finished talking to your phone.",
1087 "BitPim is busy.", wx.OK|wx.ICON_EXCLAMATION)
1088 else:
1089
1090 self.__owner_name=''
1091 self.configdlg.ShowModal()
1092
1093
1094 - def OnHelpAbout(self,_):
1096
1097 - def OnHelpHelp(self, _):
1099
1100 - def OnHelpHowtos(self, _):
1102
1103 - def OnHelpFAQ(self, _):
1105
1106 - def OnHelpContents(self, _):
1107 wx.GetApp().displayhelpid(None)
1108
1109 - def OnHelpSupport(self, _):
1111
1112 - def OnHelpTour(self, _=None):
1114
1115 - def OnHelpPhoneUpdateUI(self, event):
1116 if self.phonemodule and hasattr(self.phonemodule.Phone, 'desc'):
1117 event.SetText(self.phonemodule.Phone.desc)
1118 else:
1119 event.SetText('Phone')
1120 event.Enable(bool(hasattr(self.phonemodule.Phone, "helpid") and\
1121 self.phonemodule.Phone.helpid))
1122 - def OnHelpPhone(self, _):
1123 wx.GetApp().displayhelpid(self.phonemodule.Phone.helpid)
1124 - def DoCheckUpdate(self):
1125 s=update.check_update()
1126 if not len(s):
1127
1128 return
1129
1130 self.config.Write('latest_version', s)
1131 self.config.Write('last_update',
1132 time.strftime('%Y%m%d', time.localtime()))
1133
1134 self.SetVersionsStatus()
1135
1136 - def OnCheckUpdate(self, _):
1138
1140 phone=self.config.Read('phonetype', 'None')
1141 port=self.config.Read('lgvx4400port', 'None')
1142 if self.__owner_name=='':
1143 self.GetStatusBar().set_phone_model('%s on %s'%(phone, port),
1144 stat)
1145 else:
1146 self.GetStatusBar().set_phone_model('%s %s on %s'%(self.__owner_name, phone, port),
1147 stat)
1148
1149 - def OnPhoneInfo(self, _):
1152 - def OnDisplayPhoneInfo(self, exception, phone_info):
1153 if self.HandleException(exception): return
1154 if phone_info is None:
1155
1156 dlg=wx.MessageDialog(self, "Phone Info not available",
1157 "Phone Info Error", style=wx.OK)
1158 else:
1159 dlg=phoneinfo.PhoneInfoDialog(self, phone_info)
1160 with guihelper.WXDialogWrapper(dlg, True):
1161 pass
1162
1163 - def OnDetectPhone(self, _=None):
1164 if wx.IsBusy():
1165
1166 self.queue.put((self.OnDetectPhone, (), {}), False)
1167 return
1168 self.__detect_phone()
1169 - def __detect_phone(self, using_port=None, check_auto_sync=0, delay=0, silent_fail=False):
1170 self.OnBusyStart()
1171 self.GetStatusBar().progressminor(0, 100, 'Phone detection in progress ...')
1172 self.MakeCall(Request(self.wt.detectphone, using_port, None, delay),
1173 Callback(self.OnDetectPhoneReturn, check_auto_sync, silent_fail))
1174 - def _detect_this_phone(self, check_auto_sync=0, delay=0, silent_fail=False):
1175
1176 self.OnBusyStart()
1177 self.GetStatusBar().progressminor(0, 100, 'Phone detection in progress ...')
1178 self.MakeCall(Request(self.wt.detectphone,
1179 self.config.Read('lgvx4400port', ''),
1180 self.config.Read('phonetype', ''), delay),
1181 Callback(self.OnDetectThisPhoneReturn, check_auto_sync,
1182 silent_fail))
1183 - def OnDetectThisPhoneReturn(self, check_auto_sync, silent_fail,
1184 exception, r):
1185 if self.HandleException(exception):
1186 self.OnBusyEnd()
1187 return
1188 if r:
1189
1190 return self.OnDetectPhoneReturn(check_auto_sync, silent_fail,
1191 exception, r)
1192
1193 self.queue.put((self.__detect_phone, (),
1194 { 'check_auto_sync': check_auto_sync,
1195 'silent_fail': silent_fail }), False)
1196 self.OnBusyEnd()
1197
1198 - def __get_owner_name(self, esn, style=wx.DEFAULT_DIALOG_STYLE):
1199 """ retrieve or ask user for the owner's name of this phone
1200 """
1201 if esn is None or not len(esn):
1202 return None
1203
1204 phone_id='phones/'+sha.new(esn).hexdigest()
1205 phone_name=self.config.Read(phone_id, '')
1206 with guihelper.WXDialogWrapper(wx.TextEntryDialog(self, "Owner's name:" ,
1207 "Enter Phone Owner's Name", phone_name),
1208 True) as (dlg, r):
1209 if r==wx.ID_OK:
1210
1211 phone_name=dlg.GetValue()
1212 self.config.Write(phone_id, phone_name)
1213 return phone_name
1214
1215 - def OnDetectPhoneReturn(self, check_auto_sync, silent_fail, exception, r):
1216 self._autodetect_delay=0
1217 self.OnBusyEnd()
1218 if self.HandleException(exception): return
1219 if r is None:
1220 if not silent_fail:
1221 self.__owner_name=''
1222 with guihelper.WXDialogWrapper(wx.MessageDialog(self, 'No phone detected/recognized.\nRun Settings?',
1223 'Phone Detection Failed', wx.YES_NO),
1224 True) as (_dlg, retcode):
1225 if retcode==wx.ID_YES:
1226 wx.CallAfter(self.OnEditSettings)
1227 self.SetPhoneModelStatus(guiwidgets.SB_Phone_Set)
1228 else:
1229 if silent_fail:
1230 self.__owner_name=None
1231 else:
1232 self.__owner_name=self.__get_owner_name(r.get('phone_esn', None))
1233 if self.__owner_name is None or self.__owner_name=='':
1234 self.__owner_name=''
1235 else:
1236 self.__owner_name+="'s"
1237 self.config.Write("phonetype", r['phone_name'])
1238 self.commportsetting=str(r['port'])
1239 self.wt.clearcomm()
1240 self.config.Write("lgvx4400port", r['port'])
1241 self.phonemodule=common.importas(r['phone_module'])
1242 self.phoneprofile=self.phonemodule.Profile()
1243 pubsub.publish(pubsub.PHONE_MODEL_CHANGED, self.phonemodule)
1244 self.SetPhoneModelStatus(guiwidgets.SB_Phone_Detected)
1245 if not silent_fail:
1246 if self.__owner_name =='':
1247 wx.MessageBox('Found %s on %s'%(r['phone_name'],
1248 r['port']),
1249 'Phone Detection', wx.OK)
1250 else:
1251 wx.MessageBox('Found %s %s on %s'%(self.__owner_name,
1252 r['phone_name'],
1253 r['port']),
1254 'Phone Detection', wx.OK)
1255 if check_auto_sync:
1256
1257 self.__autosync_phone(silent=1)
1258
1259 - def AddComm(self, name):
1260
1261 print 'New device on port:',name
1262
1263 check_auto_sync=auto_sync.UpdateOnConnect(self)
1264 if name and name.lower()==self.config.Read('lgvx4400port', '').lower():
1265 _func=self._detect_this_phone
1266 _args=(check_auto_sync, self._autodetect_delay, True)
1267 else:
1268 _func=self.__detect_phone
1269 _args=(name, check_auto_sync, self._autodetect_delay, True)
1270 if wx.IsBusy():
1271
1272 self.queue.put((_func, _args, {}), False)
1273 else:
1274 _func(*_args)
1275
1276 - def RemoveComm(self, name):
1277
1278 print "Device remove", name
1279
1280 if name and name.lower()==self.config.Read('lgvx4400port', '').lower():
1281 if self.wt:
1282 self.wt.clearcomm()
1283 self.SetPhoneModelStatus(guiwidgets.SB_Phone_Unavailable)
1284
1285 - def NotifyComm(self, evt):
1286 if evt.type==evt.add:
1287 self.AddComm(evt.comm)
1288 else:
1289 self.RemoveComm(evt.comm)
1290
1291 - def OnCommNotification(self, evt):
1292 print 'OnCommNotification'
1293 if wx.Thread_IsMain():
1294 self.NotifyComm(evt)
1295 else:
1296 wx.CallAfter(self.NotifyComm, evt)
1297
1298 - def WindowsOnDeviceChanged(self, type, name="", drives=[], flag=None):
1299 if not name.lower().startswith("com"):
1300 return
1301 if type=='DBT_DEVICEREMOVECOMPLETE':
1302 self.RemoveComm(name)
1303 return
1304 if type!='DBT_DEVICEARRIVAL':
1305
1306 return
1307 self.AddComm(name)
1308
1309 - def MyWndProc(self, hwnd, msg, wparam, lparam):
1310
1311 if msg==win32con.WM_DEVICECHANGE:
1312 try:
1313 type,params=DeviceChanged(wparam, lparam).GetEventInfo()
1314 self.OnDeviceChanged(type, **params)
1315 return True
1316 except:
1317
1318 return win32gui.CallWindowProc(self.oldwndproc, hwnd, msg,
1319 wparam, lparam)
1320
1321
1322
1323
1324 if msg == win32con.WM_DESTROY:
1325 win32api.SetWindowLong(self.GetHandle(),
1326 win32con.GWL_WNDPROC,
1327 self.oldwndproc)
1328 if self._taskbar_on_closed and \
1329 msg==win32con.WM_NCLBUTTONDOWN and \
1330 wparam==win32con.HTCLOSE:
1331
1332 self._close_button=True
1333
1334
1335
1336 return win32gui.CallWindowProc(self.oldwndproc,
1337 hwnd, msg, wparam, lparam)
1338
1339 if guihelper.IsMSWindows():
1340 OnDeviceChanged=WindowsOnDeviceChanged
1341
1343 current_v=version.version
1344 latest_v=self.config.Read('latest_version')
1345 self.GetStatusBar().set_versions(current_v, latest_v)
1346
1349
1350 - def OnNewDB(self, _):
1351 newdb_wiz.create_new_db(self, self.config)
1352
1353
1354
1355
1356
1357 - def OnDataGetPhone(self,_):
1358 todo=[]
1359 dlg=self.dlggetphone
1360 dlg.UpdateWithProfile(self.phoneprofile)
1361 if dlg.ShowModal()!=wx.ID_OK:
1362 return
1363 self._autodetect_delay=self.phoneprofile.autodetect_delay
1364 todo.append((self.wt.rebootcheck, "Phone Reboot"))
1365 wx.GetApp().critical.set()
1366 self.MakeCall(Request(self.wt.getdata, dlg, todo),
1367 Callback(self.OnDataGetPhoneResults))
1368
1369 - def OnDataGetPhoneResults(self, exception, results):
1370 with wx.GetApp().critical:
1371 if self.HandleException(exception): return
1372 self.OnLog(`results.keys()`)
1373 self.OnLog(`results['sync']`)
1374
1375 if results['sync'].has_key('phonebook'):
1376 v=results['sync']['phonebook']
1377
1378 print "phonebookmergesetting is",v
1379 if v=='MERGE':
1380 merge=True
1381 else:
1382 merge=False
1383 self.GetActivePhonebookWidget().importdata(results['phonebook'], results.get('categories', []), merge, results.get('group_wallpapers', []))
1384
1385
1386 updwp=False
1387 if results['sync'].has_key('wallpaper'):
1388 v=results['sync']['wallpaper']
1389 if v=='MERGE': raise Exception("Not implemented")
1390 updwp=True
1391 self.GetActiveWallpaperWidget().populatefs(results)
1392 self.GetActiveWallpaperWidget().populate(results)
1393
1394 if not updwp and results.has_key('wallpaper-index'):
1395 self.GetActiveWallpaperWidget().updateindex(results)
1396
1397 updrng=False
1398 if results['sync'].has_key('ringtone'):
1399 v=results['sync']['ringtone']
1400 if v=='MERGE': raise Exception("Not implemented")
1401 updrng=True
1402 self.GetActiveRingerWidget().populatefs(results)
1403 self.GetActiveRingerWidget().populate(results)
1404
1405 if not updrng and results.has_key('ringtone-index'):
1406 self.GetActiveRingerWidget().updateindex(results)
1407
1408 if results['sync'].has_key('calendar'):
1409 v=results['sync']['calendar']
1410 if v=='MERGE': raise Exception("Not implemented")
1411 results['calendar_version']=self.phoneprofile.BP_Calendar_Version
1412 self.GetActiveCalendarWidget().mergedata(results)
1413
1414
1415
1416 if results['sync'].has_key('memo'):
1417 v=results['sync']['memo']
1418 if v=='MERGE': raise Exception("Not implemented")
1419 self.GetActiveMemoWidget().populatefs(results)
1420 self.GetActiveMemoWidget().populate(results)
1421
1422 if results['sync'].has_key('todo'):
1423 v=results['sync']['todo']
1424 if v=='MERGE': raise NotImplementedError
1425 self.GetActiveTodoWidget().populatefs(results)
1426 self.GetActiveTodoWidget().populate(results)
1427
1428 if results['sync'].has_key('sms'):
1429 v=results['sync']['sms']
1430 if v=='MERGE':
1431 self.GetActiveSMSWidget().merge(results)
1432 else:
1433 self.GetActiveSMSWidget().populatefs(results)
1434 self.GetActiveSMSWidget().populate(results)
1435
1436 if results['sync'].has_key('call_history'):
1437 v=results['sync']['call_history']
1438 if v=='MERGE':
1439 self.GetActiveCallHistoryWidget().merge(results)
1440 else:
1441 self.GetActiveCallHistoryWidget().populatefs(results)
1442 self.GetActiveCallHistoryWidget().populate(results)
1443
1444 if results['sync'].has_key(playlist.playlist_key):
1445 if results['sync'][playlist.playlist_key]=='MERGE':
1446 raise NotImplementedError
1447 self.GetActivePlaylistWidget().populatefs(results)
1448 self.GetActivePlaylistWidget().populate(results)
1449
1450 if results['sync'].has_key(t9editor.dict_key):
1451 if results['sync'][t9editor.dict_key]=='MERGE':
1452 raise NotImplementedError
1453 self.GetActiveT9EditorWidget().populatefs(results)
1454 self.GetActiveT9EditorWidget().populate(results)
1455
1456
1457
1458 - def OnDataSendPhone(self, _):
1459 dlg=self.dlgsendphone
1460 print self.phoneprofile
1461 dlg.UpdateWithProfile(self.phoneprofile)
1462 if dlg.ShowModal()!=wx.ID_OK:
1463 return
1464 data={}
1465 convertors=[]
1466 todo=[]
1467 funcscb=[]
1468
1469
1470 v=dlg.GetWallpaperSetting()
1471 if v!=dlg.NOTREQUESTED:
1472 merge=True
1473 if v==dlg.OVERWRITE: merge=False
1474 if merge:
1475 want=self.GetActiveWallpaperWidget().SELECTED
1476 else:
1477 want=self.GetActiveWallpaperWidget().ALL
1478 self.GetActiveWallpaperWidget().getdata(data, want)
1479 todo.append( (self.wt.writewallpaper, "Wallpaper", merge) )
1480
1481
1482
1483 v=dlg.GetRingtoneSetting()
1484 if v!=dlg.NOTREQUESTED:
1485 merge=True
1486 if v==dlg.OVERWRITE: merge=False
1487 if merge:
1488 want=self.GetActiveRingerWidget().SELECTED
1489 else:
1490 want=self.GetActiveRingerWidget().ALL
1491 self.GetActiveRingerWidget().getdata(data, want)
1492 todo.append( (self.wt.writeringtone, "Ringtone", merge) )
1493
1494
1495
1496 v=dlg.GetCalendarSetting()
1497 if v!=dlg.NOTREQUESTED:
1498 merge=True
1499 if v==dlg.OVERWRITE: merge=False
1500 data['calendar_version']=self.phoneprofile.BP_Calendar_Version
1501 self.GetActiveCalendarWidget().getdata(data)
1502 todo.append( (self.wt.writecalendar, "Calendar", merge) )
1503
1504
1505 v=dlg.GetPhoneBookSetting()
1506 if v!=dlg.NOTREQUESTED:
1507 if v==dlg.OVERWRITE:
1508 self.GetActivePhonebookWidget().getdata(data)
1509 todo.append( (self.wt.writephonebook, "Phonebook") )
1510 convertors.append(self.GetActivePhonebookWidget().converttophone)
1511
1512 funcscb.append(self.GetActivePhonebookWidget().updateserials)
1513
1514
1515 v=dlg.GetMemoSetting()
1516 if v!=dlg.NOTREQUESTED:
1517 merge=v!=dlg.OVERWRITE
1518 self.GetActiveMemoWidget().getdata(data)
1519 todo.append((self.wt.writememo, "Memo", merge))
1520
1521
1522 v=dlg.GetTodoSetting()
1523 if v!=dlg.NOTREQUESTED:
1524 merge=v!=dlg.OVERWRITE
1525 self.GetActiveTodoWidget().getdata(data)
1526 todo.append((self.wt.writetodo, "Todo", merge))
1527
1528
1529 v=dlg.GetSMSSetting()
1530 if v!=dlg.NOTREQUESTED:
1531 merge=v!=dlg.OVERWRITE
1532 self.GetActiveSMSWidget().getdata(data)
1533 todo.append((self.wt.writesms, "SMS", merge))
1534
1535
1536 v=dlg.GetPlaylistSetting()
1537 if v!=dlg.NOTREQUESTED:
1538 merge=v!=dlg.OVERWRITE
1539 self.GetActivePlaylistWidget().getdata(data)
1540 todo.append((self.wt.writeplaylist, "Playlist", merge))
1541
1542
1543 v=dlg.GetT9Setting()
1544 if v!=dlg.NOTREQUESTED:
1545 merge=v!=dlg.OVERWRITE
1546 self.GetActiveT9EditorWidget().getdata(data)
1547 todo.append((self.wt.writet9, "T9", merge))
1548
1549 data['reboot_delay']=self.phoneprofile.reboot_delay
1550 self._autodetect_delay=self.phoneprofile.autodetect_delay
1551 todo.append((self.wt.rebootcheck, "Phone Reboot"))
1552 self.MakeCall(Request(self.wt.getfundamentals),
1553 Callback(self.OnDataSendPhoneGotFundamentals, data, todo, convertors, funcscb))
1554
1555 - def OnDataSendPhoneGotFundamentals(self,data,todo,convertors, funcscb, exception, results):
1556 if self.HandleException(exception): return
1557 data.update(results)
1558
1559
1560
1561
1562
1563 for f in convertors:
1564 f(data)
1565
1566
1567 self.MakeCall(Request(self.wt.senddata, data, todo),
1568 Callback(self.OnDataSendPhoneResults, funcscb))
1569
1570 - def OnDataSendPhoneResults(self, funcscb, exception, results):
1571 if self.HandleException(exception): return
1572 print results.keys()
1573 for f in funcscb:
1574 f(results)
1575
1576 - def GetCalendarData(self):
1577
1578 d={}
1579 return self.GetActiveCalendarWidget().getdata(d).get('calendar', {})
1580
1581
1582 - def OnAutoSyncSettings(self, _=None):
1583 if wx.IsBusy():
1584 with guihelper.WXDialogWrapper(wx.MessageBox("BitPim is busy. You can't change settings until it has finished talking to your phone.",
1585 "BitPim is busy.", wx.OK|wx.ICON_EXCLAMATION),
1586 True):
1587 pass
1588 else:
1589
1590 self.__owner_name=''
1591 self.autosyncsetting.ShowModal()
1592
1593 - def OnAutoSyncExecute(self, _=None):
1594 if wx.IsBusy():
1595 wx.MessageBox("BitPim is busy. You can't run autosync until it has finished talking to your phone.",
1596 "BitPim is busy.", wx.OK|wx.ICON_EXCLAMATION)
1597 return
1598 self.__autosync_phone()
1599
1600 - def __autosync_phone(self, silent=0):
1601 r=auto_sync.SyncSchedule(self).sync(self, silent)
1602
1603
1604 - def OnReqChangeTab(self, msg=None):
1605 if msg is None:
1606 return
1607 data=msg.data
1608 if not isinstance(data, int):
1609
1610 if __debug__:
1611 raise TypeError
1612 return
1613
1614
1615 - def OnBusyStart(self):
1616 self.GetStatusBar().set_app_status_busy()
1617 wx.BeginBusyCursor(wx.StockCursor(wx.CURSOR_ARROWWAIT))
1618
1619 - def OnBusyEnd(self):
1620 wx.EndBusyCursor()
1621 self.GetStatusBar().set_app_status_ready()
1622 self.OnProgressMajor(0,1)
1623
1624 if not self.queue.empty():
1625 _q=self.queue.get(False)
1626 wx.CallAfter(_q[0], *_q[1], **_q[2])
1627
1628
1629 - def OnProgressMinor(self, pos, max, desc=""):
1630 self.GetStatusBar().progressminor(pos, max, desc)
1631
1632 - def OnProgressMajor(self, pos, max, desc=""):
1633 self.GetStatusBar().progressmajor(pos, max, desc)
1634
1635 - def OnLog(self, str):
1636 if self.__phone_detect_at_startup:
1637 return
1638 str=common.strorunicode(str)
1639 if data_recording.DR_On:
1640 data_recording.record(data_recording.DR_Type_Note, str)
1641 self.tree.lw.log(str)
1642 if self.tree.lwdata is not None:
1643 self.tree.lwdata.log(str)
1644 if str.startswith("<!= "):
1645 p=str.index("=!>")+3
1646 guihelper.MessageDialog(self, str[p:], "Alert", style=wx.OK|wx.ICON_EXCLAMATION)
1647 self.OnLog("Alert dialog closed")
1648 log=OnLog
1649 - def OnLogData(self, str, data, klass=None, data_type=None):
1650 if data_recording.DR_On:
1651 data_recording.record(data_recording.DR_Type_Note, str)
1652 data_recording.record(data_type or data_recording.DR_Type_Data,
1653 data, klass)
1654 if self.tree.lwdata is not None:
1655 self.tree.lwdata.logdata(str,data, klass)
1656
1657 - def excepthook(self, type, value, traceback):
1658 if not hasattr(value, "gui_exc_info"):
1659 value.gui_exc_info=(type,value,traceback)
1660 self.HandleException(value)
1661
1662 - def HandleException(self, exception):
1663 """returns true if this function handled the exception
1664 and the caller should not do any further processing"""
1665 if exception is None: return False
1666 assert isinstance(exception, Exception)
1667 self.CloseSplashScreen()
1668
1669 if self.wt is not None:
1670 self.wt.clearcomm()
1671 text=None
1672 title=None
1673 style=None
1674
1675 if isinstance(exception, common.CommsDeviceNeedsAttention):
1676 text="%s: %s" % (exception.device, exception.message)
1677 title="Device needs attention - "+exception.device
1678 style=wx.OK|wx.ICON_INFORMATION
1679 help=lambda _: wx.GetApp().displayhelpid(helpids.ID_DEVICE_NEEDS_ATTENTION)
1680 elif isinstance(exception, common.CommsOpenFailure):
1681 text="%s: %s" % (exception.device, exception.message)
1682 title="Failed to open communications - "+exception.device
1683 style=wx.OK|wx.ICON_INFORMATION
1684 help=lambda _: wx.GetApp().displayhelpid(helpids.ID_FAILED_TO_OPEN_DEVICE)
1685 elif isinstance(exception, common.AutoPortsFailure):
1686 text=exception.message
1687 title="Failed to automatically detect port"
1688 style=wx.OK|wx.ICON_INFORMATION
1689 help=lambda _: wx.GetApp().displayhelpid(helpids.ID_FAILED_TO_AUTODETECT_PORT)
1690 elif isinstance(exception, common.HelperBinaryNotFound) and exception.basename=="pvconv":
1691 text="The Qualcomm PureVoice converter program (%s) was not found.\nPlease see the help. Directories looked in are:\n\n " +\
1692 "\n ".join(exception.paths)
1693 text=text % (exception.fullname,)
1694 title="Failed to find PureVoice converter"
1695 style=wx.OK|wx.ICON_INFORMATION
1696 help=lambda _: wx.GetApp().displayhelpid(helpids.ID_NO_PVCONV)
1697 elif isinstance(exception, common.PhoneBookBusyException):
1698 text="The phonebook is busy on your phone.\nExit back to the main screen and then repeat the operation."
1699 title="Phonebook busy on phone"
1700 style=wx.OK|wx.ICON_INFORMATION
1701 help=lambda _: wx.GetApp().displayhelpid(helpids.ID_PHONEBOOKBUSY)
1702 elif isinstance(exception, common.IntegrityCheckFailed):
1703 text="The phonebook on your phone is partially corrupt. Please read the\nhelp for more details on the cause and fix"
1704 title="IntegrityCheckFailed"
1705 style=wx.OK|wx.ICON_EXCLAMATION
1706 help=lambda _: wx.GetApp().displayhelpid(helpids.ID_LG_INTEGRITYCHECKFAILED)
1707 elif isinstance(exception, common.CommsDataCorruption):
1708 text=exception.message+"\nPlease see the help."
1709 title="Communications Error - "+exception.device
1710 style=wx.OK|wx.ICON_EXCLAMATION
1711 help=lambda _: wx.GetApp().displayhelpid(helpids.ID_COMMSDATAERROR)
1712 elif isinstance(exception, com_brew.BrewAccessDeniedException):
1713 text="Access to the file/directory has been blocked on this phone by the phone provider"
1714 title="Access Denied"
1715 style=wx.OK|wx.ICON_EXCLAMATION
1716 help=lambda _: wx.GetApp().displayhelpid(helpids.ID_BREW_ACCESS_DENIED)
1717 elif isinstance(exception, common.PhoneStringEncodeException):
1718 text="Unable to convert the text <%s> into a format your phone can understand, change the text to contain only %s characters" % (exception.string, `exception.codec`)
1719 title="Text Conversion Error"
1720 style=wx.OK|wx.ICON_EXCLAMATION
1721 help=lambda _: wx.GetApp().displayhelpid(helpids.ID_BREW_ACCESS_DENIED)
1722
1723 if text is not None:
1724 self.OnLog("Error: "+title+"\n"+text)
1725 with guihelper.WXDialogWrapper(guiwidgets.AlertDialogWithHelp(self,text, title, help, style=style),
1726 True):
1727 pass
1728 return True
1729
1730 if self.exceptiondialog is None:
1731 self.excepttime=time.time()
1732 self.exceptcount=0
1733 self.exceptiondialog=guiwidgets.ExceptionDialog(self, exception)
1734 try:
1735 self.OnLog("Exception: "+self.exceptiondialog.getexceptiontext())
1736 except AttributeError:
1737
1738 pass
1739 else:
1740 self.exceptcount+=1
1741 if self.exceptcount<10:
1742 print "Ignoring an exception as the exception dialog is already up"
1743 try:
1744 self.OnLog("Exception during exception swallowed")
1745 except AttributeError:
1746
1747 pass
1748 return True
1749
1750 self.exceptiondialog.ShowModal()
1751 self.exceptiondialog.Destroy()
1752 self.exceptiondialog=None
1753 return True
1754
1755
1756 - def _OnTimer(self, _):
1759
1760 - def _pub_timer(self):
1762
1763 - def _OnTimerReturn(self, exceptions, result):
1764 self._timer.Start(((3600*24)+1)*1000, True)
1765
1767 _today=datetime.datetime.now()
1768 _timer_val=24*3600-_today.hour*3600-_today.minute*60-_today.second+1
1769 self._timer=wx.Timer(self)
1770 wx.EVT_TIMER(self, self._timer.GetId(), self._OnTimer)
1771 self._timer.Start(_timer_val*1000, True)
1772 print _timer_val,'seconds till midnight'
1773
1774
1775 - def OnDataRecording(self, _):
1776 with guihelper.WXDialogWrapper(guiwidgets.DRRecFileDialog(self),
1777 True):
1778 pass
1779
1780
1781
1782 - def OnCallback(self, event):
1783 assert isinstance(event, HelperReturnEvent)
1784 event()
1785
1786 - def MakeCall(self, request, cbresult):
1787 assert isinstance(request, Request)
1788 assert isinstance(cbresult, Callback)
1789 self.wt.q.put( (request, cbresult) )
1790
1791
1792
1793 - def saveSize(self):
1794 guiwidgets.save_size("MainWin", self.GetRect())
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1817
1819 if __debug__: self.checkthread()
1820 for i in range(0,0):
1821 self.progressmajor(i, 2, "Shutting down helper thread")
1822 time.sleep(1)
1823 self.log("helper thread shut down")
1824 raise BitPimExit("helper thread shutdown")
1825
1826
1828 if self.commphone is None:
1829 return
1830 self.commphone.close()
1831 self.commphone=None
1832
1833
1835 if __debug__: self.checkthread()
1836 if self.commphone is None:
1837 import commport
1838 if self.dispatchto.commportsetting is None or \
1839 len(self.dispatchto.commportsetting)==0:
1840 raise common.CommsNeedConfiguring("Comm port not configured", "DEVICE")
1841
1842 if self.dispatchto.commportsetting=="auto":
1843 autofunc=comdiagnose.autoguessports
1844 else:
1845 autofunc=None
1846 comcfg=self.dispatchto.commparams
1847
1848 name=self.dispatchto.commportsetting
1849 if name.startswith("bitfling::"):
1850 klass=bitflingscan.CommConnection
1851 else:
1852 klass=commport.CommConnection
1853
1854 comport=klass(self, self.dispatchto.commportsetting, autolistfunc=autofunc,
1855 autolistargs=(self.dispatchto.phonemodule,),
1856 baud=comcfg['baud'], timeout=comcfg['timeout'],
1857 hardwareflow=comcfg['hardwareflow'],
1858 softwareflow=comcfg['softwareflow'],
1859 configparameters=comcfg)
1860
1861 try:
1862 self.commphone=self.dispatchto.phonemodule.Phone(self, comport)
1863 except:
1864 comport.close()
1865 raise
1866
1873
1875 if __debug__: self.checkthread()
1876 self.setupcomm()
1877 results=self.getfundamentals()
1878 com_brew.file_cache.esn=results.get('uniqueserial', None)
1879 willcall=[]
1880 sync={}
1881 for i in (
1882 (req.GetPhoneBookSetting, self.commphone.getphonebook, "Phone Book", "phonebook"),
1883 (req.GetCalendarSetting, self.commphone.getcalendar, "Calendar", "calendar",),
1884 (req.GetWallpaperSetting, self.commphone.getwallpapers, "Wallpaper", "wallpaper"),
1885 (req.GetRingtoneSetting, self.commphone.getringtones, "Ringtones", "ringtone"),
1886 (req.GetMemoSetting, self.commphone.getmemo, "Memo", "memo"),
1887 (req.GetTodoSetting, self.commphone.gettodo, "Todo", "todo"),
1888 (req.GetSMSSetting, self.commphone.getsms, "SMS", "sms"),
1889 (req.GetCallHistorySetting, self.commphone.getcallhistory, 'Call History', 'call_history'),
1890 (req.GetPlaylistSetting, self.commphone.getplaylist, 'Play List', 'playlist'),
1891 (req.GetT9Setting, self.commphone.gett9db, 'T9 DB', t9editor.dict_key),
1892 ):
1893 st=i[0]()
1894 if st==req.MERGE:
1895 sync[i[3]]="MERGE"
1896 willcall.append(i)
1897 elif st==req.OVERWRITE:
1898 sync[i[3]]="OVERWRITE"
1899 willcall.append(i)
1900
1901 results['sync']=sync
1902 count=0
1903 for i in willcall:
1904 self.progressmajor(count, len(willcall), i[2])
1905 count+=1
1906 i[1](results)
1907
1908 for xx in todo:
1909 func=xx[0]
1910 desc=xx[1]
1911 args=[results]
1912 if len(xx)>2:
1913 args.extend(xx[2:])
1914 apply(func, args)
1915
1916 return results
1917
1919 count=0
1920 for xx in todo:
1921 func=xx[0]
1922 desc=xx[1]
1923 args=[dict]
1924 if len(xx)>2:
1925 args.extend(xx[2:])
1926 self.progressmajor(count,len(todo),desc)
1927 apply(func, args)
1928 count+=1
1929 return dict
1930
1935
1940
1945
1947 if __debug__: self.checkthread()
1948 if results.has_key('rebootphone'):
1949 self.log("BitPim is rebooting your phone for changes to take effect")
1950 delay=0
1951 if results.has_key('reboot_delay'):
1952 delay=results['reboot_delay']
1953 self.phonerebootrequest(delay)
1954 self.clearcomm()
1955 elif results.get('clearcomm', False):
1956
1957 self.clearcomm()
1958
1963
1968
1973
1978
1983
1989
1991 if __debug__: self.checkthread()
1992 self.setupcomm()
1993 if hasattr(self.commphone, 'getphoneinfo'):
1994 phone_info=phoneinfo.PhoneInfo()
1995 getattr(self.commphone, 'getphoneinfo')(phone_info)
1996 return phone_info
1997
1998 - def detectphone(self, using_port=None, using_model=None, delay=0):
2002
2003
2005 if __debug__: self.checkthread()
2006 self.setupcomm()
2007 try:
2008 return self.commphone.getfilesystem(path, recurse)
2009 except:
2010 self.log('Failed to read dir: '+path)
2011 return {}
2012
2014 if __debug__: self.checkthread()
2015 self.setupcomm()
2016 try:
2017 return self.commphone.listfiles(path)
2018 except:
2019 self.log('Failed to read filesystem')
2020 return {}
2021
2023 results=self.commphone.listsubdirs(path)
2024 subdir_list=[x['name'] for k,x in results.items()]
2025 if recurse:
2026 for _subdir in subdir_list:
2027 try:
2028 results.update(self.getdironlylist(_subdir, recurse))
2029 except:
2030 self.log('Failed to list directories in ' +_subdir)
2031 return results
2032
2041
2043 if __debug__: self.checkthread()
2044 self.setupcomm()
2045 try:
2046 return self.getdironlylist(path, False)
2047 except:
2048 self.log('Failed to read filesystem')
2049 return {}
2050
2055
2060
2065
2070
2075
2080
2081
2086
2091
2096
2097
2099 if __debug__: self.checkthread()
2100 self.setupcomm()
2101 self.progressmajor(0,0,"Listing files")
2102 files=self.dirlisting(path, recurse)
2103 if path=="/" or path=="":
2104 strip=0
2105 else:
2106 strip=len(path)+1
2107
2108 keys=files.keys()
2109 keys.sort()
2110
2111 op=cStringIO.StringIO()
2112 with contextlib.closing(zipfile.ZipFile(op, "w", zipfile.ZIP_DEFLATED)) as zip:
2113 count=0
2114 for k in keys:
2115 try:
2116 count+=1
2117 if files[k]['type']!='file':
2118 continue
2119 self.progressmajor(count, len(keys)+1, "Getting files")
2120
2121 contents=self.getfile(k)
2122
2123
2124 time.sleep(0.3)
2125
2126 zi=zipfile.ZipInfo()
2127
2128
2129
2130 if k[strip]=='/':
2131 zi.filename=common.get_ascii_string(k[strip+1:], 'ignore')
2132 else:
2133 zi.filename=common.get_ascii_string(k[strip:], 'ignore')
2134 if files[k]['date'][0]==0:
2135 zi.date_time=(0,0,0,0,0,0)
2136 else:
2137 zi.date_time=time.gmtime(files[k]['date'][0])[:6]
2138 zi.compress_type=zipfile.ZIP_DEFLATED
2139 zip.writestr(zi, contents)
2140 except:
2141 self.log('Failed to read file: '+k)
2142 return op.getvalue()
2143
2167
2170
2171
2172
2173 if guihelper.IsMSWindows():
2174 import struct
2176
2177 DBT_DEVICEARRIVAL = 0x8000
2178 DBT_DEVICEQUERYREMOVE = 0x8001
2179 DBT_DEVICEQUERYREMOVEFAILED = 0x8002
2180 DBT_DEVICEREMOVEPENDING = 0x8003
2181 DBT_DEVICEREMOVECOMPLETE = 0x8004
2182 DBT_DEVICETYPESPECIFIC = 0x8005
2183 DBT_DEVNODES_CHANGED = 7
2184 DBT_CONFIGCHANGED = 0x18
2185
2186 DBT_DEVTYP_OEM = 0
2187 DBT_DEVTYP_DEVNODE = 1
2188 DBT_DEVTYP_VOLUME = 2
2189 DBT_DEVTYP_PORT = 3
2190 DBT_DEVTYP_NET = 4
2191
2192 DBTF_MEDIA = 0x0001
2193 DBTF_NET = 0x0002
2194
2196 self._info=None
2197 for name in dir(self):
2198 if name.startswith("DBT") and \
2199 not name.startswith("DBT_DEVTYP") and \
2200 getattr(self,name)==wparam:
2201 self._info=(name, dict(self._decode_struct(lparam)))
2202
2205
2207 if lparam==0: return ()
2208 format = "iii"
2209 buf = win32gui.PyMakeBuffer(struct.calcsize(format), lparam)
2210 dbch_size, dbch_devicetype, dbch_reserved = struct.unpack(format, buf)
2211
2212 buf = win32gui.PyMakeBuffer(dbch_size, lparam)
2213
2214 if dbch_devicetype==self.DBT_DEVTYP_PORT:
2215 name=""
2216 for b in buf[struct.calcsize(format):]:
2217 if b!="\x00":
2218 name+=b
2219 continue
2220 break
2221 return ("name", name),
2222
2223 if dbch_devicetype==self.DBT_DEVTYP_VOLUME:
2224
2225 format="iiiih0i"
2226 dbcv_size, dbcv_devicetype, dbcv_reserved, dbcv_unitmask, dbcv_flags = struct.unpack(format, buf)
2227 units=[chr(ord('A')+x) for x in range(26) if dbcv_unitmask&(2**x)]
2228 flag=""
2229 for name in dir(self):
2230 if name.startswith("DBTF_") and getattr(self, name)==dbcv_flags:
2231 flag=name
2232 break
2233
2234 return ("drives", units), ("flag", flag)
2235
2236 print "unhandled devicetype struct", dbch_devicetype
2237 return ()
2238