[Spambayes-checkins] spambayes/Outlook2000 addin.py,1.36,1.37

Mark Hammond mhammond@users.sourceforge.net
Sat Nov 23 10:34:26 2002


Update of /cvsroot/spambayes/spambayes/Outlook2000
In directory sc8-pr-cvs1:/tmp/cvs-serv9397

Modified Files:
	addin.py 
Log Message:
Ensure our UI is attached to every Outlook window, not just the first one when we start.  Involved a fair bit of reorganization!

Index: addin.py
===================================================================
RCS file: /cvsroot/spambayes/spambayes/Outlook2000/addin.py,v
retrieving revision 1.36
retrieving revision 1.37
diff -C2 -d -r1.36 -r1.37
*** addin.py	21 Nov 2002 02:57:05 -0000	1.36
--- addin.py	23 Nov 2002 10:34:24 -0000	1.37
***************
*** 100,104 ****
              tlb, index = ti.GetContainingTypeLib()
              tla = tlb.GetLibAttr()
!             mod = gencache.EnsureModule(tla[0], tla[1], tla[3], tla[4])
              disp_class = gencache.GetClassForProgID(str(disp_clsid))
          except pythoncom.com_error:
--- 100,104 ----
              tlb, index = ti.GetContainingTypeLib()
              tla = tlb.GetLibAttr()
!             gencache.EnsureModule(tla[0], tla[1], tla[3], tla[4])
              disp_class = gencache.GetClassForProgID(str(disp_clsid))
          except pythoncom.com_error:
***************
*** 213,222 ****
  
  # Event function fired from the "Show Clues" UI items.
! def ShowClues(mgr, app):
      from cgi import escape
  
!     msgstore_message = mgr.addin.GetSelectedMessages(False)
      if msgstore_message is None:
          return
      item = msgstore_message.GetOutlookItem()
      score, clues = mgr.score(msgstore_message, evidence=True, scale=False)
--- 213,224 ----
  
  # Event function fired from the "Show Clues" UI items.
! def ShowClues(mgr, explorer):
      from cgi import escape
  
!     app = explorer.Application
!     msgstore_message = explorer.GetSelectedMessages(False)
      if msgstore_message is None:
          return
+ 
      item = msgstore_message.GetOutlookItem()
      score, clues = mgr.score(msgstore_message, evidence=True, scale=False)
***************
*** 262,328 ****
      new_msg.Display()
  
- # Events from our Explorer instance - currently used to enable/disable
- # controls
- class ExplorerEvent:
-     def Init(self, manager, application, but_delete_as, but_recover_as):
-         self.manager = manager
-         self.application = application
-         self.but_delete_as = but_delete_as
-         self.but_recover_as = but_recover_as
-     def Close(self):
-         self.but_delete_as = self.but_recover_as = None
-     def OnFolderSwitch(self):
-         # Work out what folder we are in.
-         explorer = self.application.ActiveExplorer()
-         if explorer is None:
-             print "** Folder Change, but don't have an explorer"
-             return
- 
-         outlook_folder = explorer.CurrentFolder
-         show_delete_as = True
-         show_recover_as = False
-         try:
-             if outlook_folder is not None:
-                 mapi_folder = self.manager.message_store.GetFolder(outlook_folder)
-                 look_id = self.manager.config.filter.spam_folder_id
-                 if look_id:
-                     look_folder = self.manager.message_store.GetFolder(look_id)
-                     if mapi_folder == look_folder:
-                         # This is the Spam folder - only show "recover"
-                         show_recover_as = True
-                         show_delete_as = False
-                 # Check if uncertain
-                 look_id = self.manager.config.filter.unsure_folder_id
-                 if look_id:
-                     look_folder = self.manager.message_store.GetFolder(look_id)
-                     if mapi_folder == look_folder:
-                         show_recover_as = True
-                         show_delete_as = True
-         except:
-             print "Error finding the MAPI folders for a folder switch event"
-             import traceback
-             traceback.print_exc()
-         self.but_recover_as.Visible = show_recover_as
-         self.but_delete_as.Visible = show_delete_as
- 
  # The "Delete As Spam" and "Recover Spam" button
  # The event from Outlook's explorer that our folder has changed.
  class ButtonDeleteAsEventBase:
!     def Init(self, manager, application):
!         # NOTE - keeping a reference to 'explorer' in this event
!         # appears to cause an Outlook circular reference, and outlook
!         # never terminates (it does close, but the process remains alive)
!         # This is why we needed to use WithEvents, so the event class
!         # itself doesnt keep such a reference (and we need to keep a ref
!         # to the event class so it doesn't auto-disconnect!)
          self.manager = manager
!         self.application = application
  
      def Close(self):
!         self.manager = self.application = None
  
  class ButtonDeleteAsSpamEvent(ButtonDeleteAsEventBase):
!     def Init(self, manager, application):
!         ButtonDeleteAsEventBase.Init(self, manager, application)
          image = "delete_as_spam.bmp"
          self.Caption = "Delete As Spam"
--- 264,280 ----
      new_msg.Display()
  
  # The "Delete As Spam" and "Recover Spam" button
  # The event from Outlook's explorer that our folder has changed.
  class ButtonDeleteAsEventBase:
!     def Init(self, manager, explorer):
          self.manager = manager
!         self.explorer = explorer
  
      def Close(self):
!         self.manager = self.explorer = None
  
  class ButtonDeleteAsSpamEvent(ButtonDeleteAsEventBase):
!     def Init(self, manager, explorer):
!         ButtonDeleteAsEventBase.Init(self, manager, explorer)
          image = "delete_as_spam.bmp"
          self.Caption = "Delete As Spam"
***************
*** 334,338 ****
      def OnClick(self, button, cancel):
          msgstore = self.manager.message_store
!         msgstore_messages = self.manager.addin.GetSelectedMessages(True)
          if not msgstore_messages:
              return
--- 286,290 ----
      def OnClick(self, button, cancel):
          msgstore = self.manager.message_store
!         msgstore_messages = self.explorer.GetSelectedMessages(True)
          if not msgstore_messages:
              return
***************
*** 356,361 ****
  
  class ButtonRecoverFromSpamEvent(ButtonDeleteAsEventBase):
!     def Init(self, manager, application):
!         ButtonDeleteAsEventBase.Init(self, manager, application)
          image = "recover_ham.bmp"
          self.Caption = "Recover from Spam"
--- 308,313 ----
  
  class ButtonRecoverFromSpamEvent(ButtonDeleteAsEventBase):
!     def Init(self, manager, explorer):
!         ButtonDeleteAsEventBase.Init(self, manager, explorer)
          image = "recover_ham.bmp"
          self.Caption = "Recover from Spam"
***************
*** 369,373 ****
      def OnClick(self, button, cancel):
          msgstore = self.manager.message_store
!         msgstore_messages = self.manager.addin.GetSelectedMessages(True)
          if not msgstore_messages:
              return
--- 321,325 ----
      def OnClick(self, button, cancel):
          msgstore = self.manager.message_store
!         msgstore_messages = self.explorer.GetSelectedMessages(True)
          if not msgstore_messages:
              return
***************
*** 375,381 ****
          # Get the inbox as the default place to restore to
          # (incase we dont know (early code) or folder removed etc
          inbox_folder = msgstore.GetFolder(
!                     self.application.Session.GetDefaultFolder(
!                         constants.olFolderInbox))
          import train
          for msgstore_message in msgstore_messages:
--- 327,333 ----
          # Get the inbox as the default place to restore to
          # (incase we dont know (early code) or folder removed etc
+         app = self.explorer.Application
          inbox_folder = msgstore.GetFolder(
!                     app.Session.GetDefaultFolder(constants.olFolderInbox))
          import train
          for msgstore_message in msgstore_messages:
***************
*** 408,411 ****
--- 360,515 ----
      button.PasteFace()
  
+ # A class that manages an "Outlook Explorer" - that is, a top-level window
+ # All UI elements are managed here, and there is one instance per explorer.
+ class ExplorerWithEvents:
+     def Init(self, manager, explorer_list):
+         self.manager = manager
+         self.have_setup_ui = False
+         self.explorer_list = explorer_list
+ 
+     def SetupUI(self):
+         application = self.Application
+         manager = self.manager
+         self.buttons = []
+         activeExplorer = self
+         bars = activeExplorer.CommandBars
+         toolbar = bars.Item("Standard")
+         # Add our "Delete as ..." and "Recover as" buttons
+         self.but_delete_as = button = toolbar.Controls.Add(
+                                 Type=constants.msoControlButton,
+                                 Temporary=True)
+         # Hook events for the item
+         button.BeginGroup = True
+         button = DispatchWithEvents(button, ButtonDeleteAsSpamEvent)
+         button.Init(self.manager, self)
+         self.buttons.append(button)
+         # And again for "Recover as"
+         self.but_recover_as = button = toolbar.Controls.Add(
+                                 Type=constants.msoControlButton,
+                                 Temporary=True)
+         button = DispatchWithEvents(button, ButtonRecoverFromSpamEvent)
+         self.buttons.append(button)
+         # Hook our explorer events, and pass the buttons.
+         button.Init(self.manager, self)
+ 
+         # And prime our event handler.
+         self.OnFolderSwitch()
+ 
+         # The main tool-bar dropdown with all our entries.
+         # Add a pop-up menu to the toolbar
+         popup = toolbar.Controls.Add(
+                             Type=constants.msoControlPopup,
+                             Temporary=True)
+         popup.Caption="Anti-Spam"
+         popup.TooltipText = "Anti-Spam filters and functions"
+         popup.Enabled = True
+         # Convert from "CommandBarItem" to derived
+         # "CommandBarPopup" Not sure if we should be able to work
+         # this out ourselves, but no introspection I tried seemed
+         # to indicate we can.  VB does it via strongly-typed
+         # declarations.
+         popup = CastTo(popup, "CommandBarPopup")
+         # And add our children.
+         self._AddPopup(popup, manager.ShowManager, (),
+                        Caption="Anti-Spam Manager...",
+                        TooltipText = "Show the Anti-Spam manager dialog.",
+                        Enabled = True)
+         self._AddPopup(popup, ShowClues, (self.manager, self),
+                        Caption="Show spam clues for current message",
+                        Enabled=True)
+         self.have_setup_ui = True
+ 
+     def _AddPopup(self, parent, target, target_args, **item_attrs):
+         item = parent.Controls.Add(Type=constants.msoControlButton, Temporary=True)
+         # Hook events for the item
+         item = DispatchWithEvents(item, ButtonEvent)
+         item.Init(target, target_args)
+         for attr, val in item_attrs.items():
+             setattr(item, attr, val)
+         self.buttons.append(item)
+ 
+     def GetSelectedMessages(self, allow_multi = True, explorer = None):
+         if explorer is None:
+             explorer = self.Application.ActiveExplorer()
+         sel = explorer.Selection
+         if sel.Count > 1 and not allow_multi:
+             win32ui.MessageBox("Please select a single item", "Large selection")
+             return None
+ 
+         ret = []
+         for i in range(sel.Count):
+             item = sel.Item(i+1)
+             if item.Class == constants.olMail:
+                 msgstore_message = self.manager.message_store.GetMessage(item)
+                 ret.append(msgstore_message)
+ 
+         if len(ret) == 0:
+             win32ui.MessageBox("No mail items are selected", "No selection")
+             return None
+         if allow_multi:
+             return ret
+         return ret[0]
+ 
+     # The Outlook event handlers
+     def OnActivate(self):
+         if not self.have_setup_ui:
+             self.SetupUI()
+ 
+     def OnClose(self):
+         self.explorer_list.remove(self)
+         self.explorer_list = None
+         for button in self.buttons:
+             button.Close()
+         self.buttons = []
+         self.close() # disconnect events.
+ 
+     def OnFolderSwitch(self):
+         # Work out what folder we are in.
+         outlook_folder = self.CurrentFolder
+         show_delete_as = True
+         show_recover_as = False
+         try:
+             if outlook_folder is not None:
+                 mapi_folder = self.manager.message_store.GetFolder(outlook_folder)
+                 look_id = self.manager.config.filter.spam_folder_id
+                 if look_id:
+                     look_folder = self.manager.message_store.GetFolder(look_id)
+                     if mapi_folder == look_folder:
+                         # This is the Spam folder - only show "recover"
+                         show_recover_as = True
+                         show_delete_as = False
+                 # Check if uncertain
+                 look_id = self.manager.config.filter.unsure_folder_id
+                 if look_id:
+                     look_folder = self.manager.message_store.GetFolder(look_id)
+                     if mapi_folder == look_folder:
+                         show_recover_as = True
+                         show_delete_as = True
+         except:
+             print "Error finding the MAPI folders for a folder switch event"
+             import traceback
+             traceback.print_exc()
+         self.but_recover_as.Visible = show_recover_as
+         self.but_delete_as.Visible = show_delete_as
+ 
+ # Events from our "Explorers" collection (not an Explorer instance)
+ class ExplorersEvent:
+     def Init(self, manager):
+         self.manager = manager
+         self.explorers = []
+ 
+     def Close(self):
+         self.explorers = None
+ 
+     def _DoNewExplorer(self, explorer, do_activate):
+         explorer = DispatchWithEvents(explorer, ExplorerWithEvents)
+         explorer.Init(self.manager, self.explorers)
+         if do_activate:
+             explorer.OnActivate()
+         self.explorers.append(explorer)
+ 
+     def OnNewExplorer(self, explorer):
+         self._DoNewExplorer(explorer, False)
+ 
  # The outlook Plugin COM object itself.
  class OutlookAddin:
***************
*** 420,424 ****
          self.folder_hooks = {}
          self.application = None
-         self.buttons = []
  
      def OnConnection(self, application, connectMode, addin, custom):
--- 524,527 ----
***************
*** 431,488 ****
          assert self.manager.addin is None, "Should not already have an addin"
          self.manager.addin = self
-         self.explorer_events = None
- 
-         # ActiveExplorer may be none when started without a UI (eg, WinCE synchronisation)
-         activeExplorer = application.ActiveExplorer()
-         if activeExplorer is not None:
-             bars = activeExplorer.CommandBars
-             toolbar = bars.Item("Standard")
-             # Add our "Delete as ..." and "Recover as" buttons
-             but_delete_as = button = toolbar.Controls.Add(
-                                     Type=constants.msoControlButton,
-                                     Temporary=True)
-             # Hook events for the item
-             button.BeginGroup = True
-             button = DispatchWithEvents(button, ButtonDeleteAsSpamEvent)
-             button.Init(self.manager, application)
-             self.buttons.append(button)
-             # And again for "Recover as"
-             but_recover_as = button = toolbar.Controls.Add(
-                                     Type=constants.msoControlButton,
-                                     Temporary=True)
-             button = DispatchWithEvents(button, ButtonRecoverFromSpamEvent)
-             self.buttons.append(button)
-             # Hook our explorer events, and pass the buttons.
-             button.Init(self.manager, application)
  
!             self.explorer_events = WithEvents(activeExplorer,
!                                                ExplorerEvent)
! 
!             self.explorer_events.Init(self.manager, application, but_delete_as, but_recover_as)
!             # And prime the event handler.
!             self.explorer_events.OnFolderSwitch()
! 
!             # The main tool-bar dropdown with all our entries.
!             # Add a pop-up menu to the toolbar
!             popup = toolbar.Controls.Add(
!                                 Type=constants.msoControlPopup,
!                                 Temporary=True)
!             popup.Caption="Anti-Spam"
!             popup.TooltipText = "Anti-Spam filters and functions"
!             popup.Enabled = True
!             # Convert from "CommandBarItem" to derived
!             # "CommandBarPopup" Not sure if we should be able to work
!             # this out ourselves, but no introspection I tried seemed
!             # to indicate we can.  VB does it via strongly-typed
!             # declarations.
!             popup = CastTo(popup, "CommandBarPopup")
!             # And add our children.
!             self._AddPopup(popup, manager.ShowManager, (self.manager,),
!                            Caption="Anti-Spam Manager...",
!                            TooltipText = "Show the Anti-Spam manager dialog.",
!                            Enabled = True)
!             self._AddPopup(popup, ShowClues, (self.manager, application),
!                            Caption="Show spam clues for current message",
!                            Enabled=True)
  
          self.FiltersChanged()
--- 534,546 ----
          assert self.manager.addin is None, "Should not already have an addin"
          self.manager.addin = self
  
!         explorers = application.Explorers
!         # and Explorers events so we know when new explorers spring into life.
!         self.explorers_events = WithEvents(explorers, ExplorersEvent)
!         self.explorers_events.Init(self.manager)
!         # And hook our UI elements to all existing explorers
!         for i in range(explorers.Count):
!             explorer = explorers.Item(i+1)
!             self.explorers_events._DoNewExplorer(explorer, True)
  
          self.FiltersChanged()
***************
*** 495,507 ****
                  traceback.print_exc()
  
-     def _AddPopup(self, parent, target, target_args, **item_attrs):
-         item = parent.Controls.Add(Type=constants.msoControlButton, Temporary=True)
-         # Hook events for the item
-         item = DispatchWithEvents(item, ButtonEvent)
-         item.Init(target, target_args)
-         for attr, val in item_attrs.items():
-             setattr(item, attr, val)
-         self.buttons.append(item)
- 
      def ProcessMissedMessages(self):
          # This could possibly spawn threads if it was too slow!
--- 553,556 ----
***************
*** 568,608 ****
          return new_hooks
  
-     def GetSelectedMessages(self, allow_multi = True, explorer = None):
-         if explorer is None:
-             explorer = self.application.ActiveExplorer()
-         sel = explorer.Selection
-         if sel.Count > 1 and not allow_multi:
-             win32ui.MessageBox("Please select a single item", "Large selection")
-             return None
- 
-         ret = []
-         for i in range(sel.Count):
-             item = sel.Item(i+1)
-             if item.Class == constants.olMail:
-                 msgstore_message = self.manager.message_store.GetMessage(item)
-                 ret.append(msgstore_message)
- 
-         if len(ret) == 0:
-             win32ui.MessageBox("No mail items are selected", "No selection")
-             return None
-         if allow_multi:
-             return ret
-         return ret[0]
- 
      def OnDisconnection(self, mode, custom):
          print "SpamAddin - Disconnecting from Outlook"
          self.folder_hooks = None
          self.application = None
          if self.manager is not None:
              self.manager.Save()
              self.manager.Close()
              self.manager = None
- 
-         if self.explorer_events is not None:
-             self.explorer_events = None
-         if self.buttons:
-             for button in self.buttons:
-                 button.Close()
-             self.buttons = None
  
          print "Addin terminating: %d COM client and %d COM servers exist." \
--- 617,629 ----
          return new_hooks
  
      def OnDisconnection(self, mode, custom):
          print "SpamAddin - Disconnecting from Outlook"
          self.folder_hooks = None
          self.application = None
+         self.explorers_events = None
          if self.manager is not None:
              self.manager.Save()
              self.manager.Close()
              self.manager = None
  
          print "Addin terminating: %d COM client and %d COM servers exist." \





More information about the Spambayes-checkins mailing list