"Fossies" - the Fresh Open Source Software Archive

Member "spambayes-1.1a6/Outlook2000/dialogs/async_processor.py" (6 Dec 2008, 10860 Bytes) of archive /windows/mail/spambayes-1.1a6.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "async_processor.py" see the Fossies "Dox" file reference documentation.

    1 # An async command processor
    2 from dlgutils import *
    3 import win32gui, win32api, win32con, commctrl
    4 import win32process
    5 import time
    6 
    7 import processors
    8 
    9 verbose = 0
   10 
   11 IDC_START = 1100
   12 IDC_PROGRESS = 1101
   13 IDC_PROGRESS_TEXT = 1102
   14 
   15 MYWM_SETSTATUS = win32con.WM_USER+11
   16 MYWM_SETWARNING = win32con.WM_USER+12
   17 MYWM_SETERROR = win32con.WM_USER+13
   18 MYWM_FINISHED = win32con.WM_USER+14
   19 
   20 # This is called from another thread - hence we need to jump through hoops!
   21 class _Progress:
   22     def __init__(self, processor):
   23         self.hdlg = processor.window.hwnd
   24         self.hprogress = processor.GetControl(processor.statusbar_id)
   25         self.processor = processor
   26         self.stopping = False
   27         self.total_control_ticks = 40
   28         self.current_stage = 0
   29         self.set_stages( (("", 1.0),) )
   30 
   31     def set_stages(self, stages):
   32         self.stages = []
   33         start_pos = 0.0
   34         for name, prop in stages:
   35             stage = name, start_pos, prop
   36             start_pos += prop
   37             self.stages.append(stage)
   38         assert abs(start_pos-1.0) < 0.001, (
   39                "Proportions must add to 1.0 (%r,%r,%r)" %
   40                    (start_pos, stages, start_pos-1.0))
   41 
   42     def _next_stage(self):
   43         if self.current_stage == 0:
   44             win32api.PostMessage(self.hprogress, commctrl.PBM_SETRANGE, 0, MAKELPARAM(0,self.total_control_ticks))
   45             win32api.PostMessage(self.hprogress, commctrl.PBM_SETSTEP, 1, 0)
   46             win32api.PostMessage(self.hprogress, commctrl.PBM_SETPOS, 0, 0)
   47 
   48         self.current_stage += 1
   49         assert self.current_stage <= len(self.stages)
   50 
   51     def _get_current_stage(self):
   52         return self.stages[self.current_stage-1]
   53 
   54     def set_max_ticks(self, m):
   55         # skip to the stage.
   56         self._next_stage()
   57         self.current_stage_max = m
   58         self.current_stage_tick = -1 # ready to go to zero!
   59         # if earlier stages stopped early, skip ahead.
   60         self.tick()
   61 
   62     def tick(self):
   63         if self.current_stage_tick < self.current_stage_max:
   64             # Don't let us go beyond our stage max
   65             self.current_stage_tick += 1
   66         # Calc how far through this stage.
   67         this_prop = float(self.current_stage_tick) / self.current_stage_max
   68         # How far through the total.
   69         stage_name, start, end = self._get_current_stage()
   70         # Calc the perc of the total control.
   71         stage_name, start, prop = self._get_current_stage()
   72         total_prop = start + this_prop * prop
   73         # How may ticks is this on the control (but always have 1, so the
   74         # user knows the process has actually started.)
   75         control_tick = max(1,int(total_prop * self.total_control_ticks))
   76         if verbose:
   77             print "Tick", self.current_stage_tick, "is", this_prop, "through the stage,", total_prop, "through the total - ctrl tick is", control_tick
   78         win32api.PostMessage(self.hprogress, commctrl.PBM_SETPOS, control_tick)
   79 
   80     def _get_stage_text(self, text):
   81         stage_name, start, end = self._get_current_stage()
   82         if stage_name:
   83             text = stage_name + ": " + text
   84         return text
   85     def set_status(self, text):
   86         self.processor.progress_status = self._get_stage_text(text)
   87         win32api.PostMessage(self.hdlg, MYWM_SETSTATUS)
   88     def warning(self, text):
   89         self.processor.progress_warning = self._get_stage_text(text)
   90         win32api.PostMessage(self.hdlg, MYWM_SETWARNING)
   91     def error(self, text):
   92         self.processor.progress_error = self._get_stage_text(text)
   93         win32api.PostMessage(self.hdlg, MYWM_SETERROR)
   94     def request_stop(self):
   95         self.stopping = True
   96     def stop_requested(self):
   97         return self.stopping
   98 
   99 class AsyncCommandProcessor(processors.CommandButtonProcessor):
  100     def __init__(self, window, control_ids, func, start_text, stop_text, disable_ids):
  101         processors.CommandButtonProcessor.__init__(self, window, control_ids[:1], func, ())
  102         self.progress_status = ""
  103         self.progress_error = ""
  104         self.progress_warning = ""
  105         self.running = False
  106         self.statusbar_id = control_ids[1]
  107         self.statustext_id = control_ids[2]
  108         self.process_start_text = start_text
  109         self.process_stop_text = stop_text
  110         dids = self.disable_while_running_ids = []
  111         for id in disable_ids.split():
  112             dids.append(window.manager.dialog_parser.ids[id])
  113 
  114     def Init(self):
  115         win32gui.ShowWindow(self.GetControl(self.statusbar_id), win32con.SW_HIDE)
  116         self.SetStatusText("")
  117 
  118     def Done(self):
  119         if self.running:
  120             msg = "You must let the running process finish before closing this window"
  121             win32gui.MessageBox(self.window.hwnd, msg, "SpamBayes",
  122                                 win32con.MB_OK | win32con.MB_ICONEXCLAMATION)
  123         return not self.running
  124     def Term(self):
  125         # The Window is dieing!  We *must* kill it and wait for it to finish
  126         # else bad things happen once the main thread dies before us!
  127         if self.running:
  128             self.progress.request_stop()
  129             i = 0
  130             while self.running:
  131                 win32gui.PumpWaitingMessages(0,-1)
  132                 if i % 100 == 0:
  133                     print "Still waiting for async process to finish..."
  134                 time.sleep(0.01)
  135                 i += 1
  136         return True
  137 
  138     def GetMessages(self):
  139         return [MYWM_SETSTATUS, MYWM_SETWARNING, MYWM_SETERROR, MYWM_FINISHED]
  140 
  141     def SetEnabledStates(self, enabled):
  142         for id in self.disable_while_running_ids:
  143             win32gui.EnableWindow(self.GetControl(id), enabled)
  144 
  145     def OnMessage(self, msg, wparam, lparam):
  146         if msg == MYWM_SETSTATUS:
  147             self.OnProgressStatus(wparam, lparam)
  148         elif msg == MYWM_SETWARNING:
  149             self.OnProgressWarning(wparam, lparam)
  150         elif msg == MYWM_SETERROR:
  151             self.OnProgressError(wparam, lparam)
  152         elif msg == MYWM_FINISHED:
  153             self.OnFinished(wparam, lparam)
  154         else:
  155             raise RuntimeError, "Not one of my messages??"
  156 
  157     def OnFinished(self, wparam, lparam):
  158         self.seen_finished = True
  159         wasCancelled = wparam
  160         self.SetEnabledStates(True)
  161 
  162         if self.process_start_text:
  163             win32gui.SendMessage(self.GetControl(), win32con.WM_SETTEXT,
  164                                  0, self.process_start_text)
  165         win32gui.ShowWindow(self.GetControl(self.statusbar_id), win32con.SW_HIDE)
  166         if wasCancelled:
  167             self.SetStatusText("Cancelled")
  168 
  169     def SetStatusText(self, text):
  170         win32gui.SendMessage(self.GetControl(self.statustext_id),
  171                                 win32con.WM_SETTEXT,
  172                                 0, text)
  173 
  174     def OnProgressStatus(self, wparam, lparam):
  175         self.SetStatusText(self.progress_status)
  176 
  177     def OnProgressError(self, wparam, lparam):
  178         self.SetStatusText(self.progress_error)
  179         win32gui.MessageBox(self.window.hwnd,
  180                             self.progress_error, "SpamBayes",
  181                             win32con.MB_OK | win32con.MB_ICONEXCLAMATION)
  182         if not self.running and not self.seen_finished:
  183             self.OnFinished(0,0)
  184 
  185     def OnProgressWarning(self, wparam, lparam):
  186         pass
  187 
  188     def OnClicked(self, id):
  189         self.StartProcess()
  190 
  191     def StartProcess(self):
  192         if self.running:
  193             self.progress.request_stop()
  194         else:
  195             # Do anything likely to fail before we screw around with the
  196             # control states - this way the dialog doesn't look as 'dead'
  197             progress=_Progress(self)
  198             # Now screw around with the control states, restored when
  199             # the thread terminates.
  200             self.SetEnabledStates(False)
  201             if self.process_stop_text:
  202                 win32gui.SendMessage(self.GetControl(),
  203                                      win32con.WM_SETTEXT,
  204                                      0, self.process_stop_text)
  205             win32gui.SendMessage(self.GetControl(self.statustext_id),
  206                                  win32con.WM_SETTEXT, 0, "")
  207             win32gui.ShowWindow(self.GetControl(self.statusbar_id),
  208                                 win32con.SW_SHOW)
  209             # Local function for the thread target that notifies us when finished.
  210             def thread_target(h, progress):
  211                 try:
  212                     self.progress = progress
  213                     self.seen_finished = False
  214                     self.running = True
  215                     # Drop my thread priority, so outlook can keep repainting
  216                     # and doing its stuff without getting stressed.
  217                     import win32process, win32api
  218                     THREAD_PRIORITY_BELOW_NORMAL=-1
  219                     win32process.SetThreadPriority(win32api.GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL)
  220                     self.func( self.window.manager, self.window.config, progress)
  221                 finally:
  222                     try:
  223                         win32api.PostMessage(h, MYWM_FINISHED, self.progress.stop_requested())
  224                     except win32api.error:
  225                         # Bad window handle - already down.
  226                         pass
  227                     self.running = False
  228                     self.progress = None
  229 
  230             # back to the program :)
  231             import threading
  232             t = threading.Thread(target=thread_target, args =(self.window.hwnd, progress))
  233             t.start()
  234 
  235 if __name__=='__main__':
  236     verbose = 1
  237     # Test my "multi-stage" code
  238     class HackProgress(_Progress):
  239         def __init__(self): # dont use dlg
  240             self.hprogress = self.hdlg = 0
  241             self.dlg = None
  242             self.stopping = False
  243             self.total_control_ticks = 40
  244             self.current_stage = 0
  245             self.set_stages( (("", 1.0),) )
  246 
  247     print "Single stage test"
  248     p = HackProgress()
  249     p.set_max_ticks(10)
  250     for i in range(10):
  251         p.tick()
  252 
  253     print "First stage test"
  254     p = HackProgress()
  255     stages = ("Stage 1", 0.2), ("Stage 2", 0.8)
  256     p.set_stages(stages)
  257     # Do stage 1
  258     p.set_max_ticks(10)
  259     for i in range(10):
  260         p.tick()
  261     # Do stage 2
  262     p.set_max_ticks(20)
  263     for i in range(20):
  264         p.tick()
  265     print "Second stage test"
  266     p = HackProgress()
  267     stages = ("Stage 1", 0.9), ("Stage 2", 0.1)
  268     p.set_stages(stages)
  269     p.set_max_ticks(10)
  270     for i in range(7): # do a few less just to check
  271         p.tick()
  272     p.set_max_ticks(2)
  273     for i in range(2):
  274         p.tick()
  275     print "Third stage test"
  276     p = HackProgress()
  277     stages = ("Stage 1", 0.9), ("Stage 2", 0.1)
  278     p.set_stages(stages)
  279     p.set_max_ticks(300)
  280     for i in range(313): # do a few more just to check
  281         p.tick()
  282     p.set_max_ticks(2)
  283     for i in range(2):
  284         p.tick()
  285 
  286     print "Done!"