[Spambayes-checkins] spambayes/Outlook2000/dialogs ManagerDialog.py,NONE,1.1 FilterDialog.py,1.2,1.3

Mark Hammond mhammond@users.sourceforge.net
Sun, 20 Oct 2002 00:47:03 -0700


Update of /cvsroot/spambayes/spambayes/Outlook2000/dialogs
In directory usw-pr-cvs1:/tmp/cvs-serv30441/dialogs

Modified Files:
	FilterDialog.py 
Added Files:
	ManagerDialog.py 
Log Message:
Brand spanking new version that actually filters mail as they
arrive (woo hooo)


--- NEW FILE: ManagerDialog.py ---
from pywin.mfc import dialog
import win32con
import commctrl
import win32ui
import win32api
import pythoncom

from DialogGlobals import *

IDC_BUT_MOREINFO = 1024
IDC_BUT_DB = 1025
IDC_BUT_TRAIN = 1026
IDC_DB_STATUS = 1027
IDC_BUT_ENABLE_FILTER = 1028
IDC_BUT_FILTER = 1029
IDC_FILTER_STATUS = 1030
IDC_BUT_CLASSIFY = 1031

class ManagerDialog(dialog.Dialog):
    style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
    cs = win32con.WS_CHILD | win32con.WS_VISIBLE
    csts = cs | win32con.WS_TABSTOP
    filter_msg = "Filter the following folders as messages arrive"
    intro_msg = "This application filters out spam by continually learning the characteristics of email you recieve and filtering spam from your regular email.  The system must be trained before it will be effective."
    training_intro = "Training is the process of giving examples of both good and bad email to the system so it can classify future email"
    filtering_intro = "Filtering is the process of deleting, moving or otherwise modifying messages based on their spam probability"
    classify_intro = "Classification is the process of adding properties to messages based on their Spam probability.  Creating a property with the spam rating allows you to select the field using the Outlook Field Chooser."
    
    dt = [
        # Dialog itself.
        ["Anti-Spam", (0, 0, 242, 277), style, None, (8, "MS Sans Serif")],
        # Children
        [STATIC,          intro_msg,            -1,                  (  7,   7, 228,  25), cs],
        [BUTTON,          'Details...',         IDC_BUT_MOREINFO,    (168,  33,  62,  14), csts | win32con.BS_PUSHBUTTON],

        [BUTTON,          "Database and Training", -1,               (  7,  49, 228,  62), cs   | win32con.BS_GROUPBOX],
        [STATIC,          training_intro,       -1,                  ( 15,  57, 215,  17), cs],
        [BUTTON,          'Database Options',   IDC_BUT_DB,          ( 15,  77,  62,  14), csts | win32con.BS_PUSHBUTTON | win32con.WS_DISABLED],
        [BUTTON,          '&Training',          IDC_BUT_TRAIN,       (168,  77,  62,  14), csts | win32con.BS_PUSHBUTTON],
        [STATIC,          "",                   IDC_DB_STATUS,       ( 15,  95, 215,  12), cs   | win32con.SS_LEFTNOWORDWRAP | win32con.SS_CENTERIMAGE | win32con.SS_SUNKEN],

        [BUTTON,          "Filtering",          -1,                  (  7, 116, 228,  68), cs   | win32con.BS_GROUPBOX],
        [STATIC,          filtering_intro,      -1,                  ( 15, 127, 215,  17), cs],
        [BUTTON,          'Enable &filtering',  IDC_BUT_ENABLE_FILTER,(24, 147, 131,  11), csts | win32con.BS_AUTOCHECKBOX],
        [BUTTON,          'Define filters...',  IDC_BUT_FILTER,      (168, 144,  62,  14), csts | win32con.BS_PUSHBUTTON],
        [STATIC,          "",                   IDC_FILTER_STATUS,   ( 15, 162, 215,  12), cs   | win32con.SS_LEFTNOWORDWRAP | win32con.SS_CENTERIMAGE | win32con.SS_SUNKEN],
         
        [BUTTON,          "Classification",     -1,                  (  7, 188, 228,  61), cs   | win32con.BS_GROUPBOX],
        [STATIC,          classify_intro,       -1,                  ( 15, 201, 215,  26), cs],
        [BUTTON,          'Classify...',        IDC_BUT_CLASSIFY,    (168, 228,  62,  14), csts | win32con.BS_PUSHBUTTON],

        [BUTTON,         'Close',               win32con.IDOK,       (168, 256,  62,  14), csts | win32con.BS_DEFPUSHBUTTON],
    ]

    def __init__(self, mgr, do_train, do_filter, do_classify):
        self.mgr = mgr
        self.do_train = do_train
        self.do_filter = do_filter
        self.do_classify = do_classify
        dialog.Dialog.__init__(self, self.dt)

    def OnInitDialog(self):
        self.HookCommand(self.OnButMoreInfo, IDC_BUT_MOREINFO)
        self.HookCommand(self.OnButDoSomething, IDC_BUT_TRAIN)
        self.HookCommand(self.OnButDoSomething, IDC_BUT_FILTER)
        self.HookCommand(self.OnButDoSomething, IDC_BUT_CLASSIFY)
        self.HookCommand(self.OnButEnableFilter, IDC_BUT_ENABLE_FILTER)
        self.UpdateControlStatus()
        return dialog.Dialog.OnInitDialog(self)

    def UpdateControlStatus(self):
        nspam = self.mgr.bayes.nspam
        nham = self.mgr.bayes.nham
        enable_buttons = nspam > 0 and nham > 0
        if enable_buttons:
            db_status = "Database has %d good and %d spam messages" % (nham, nspam)
        else:
            db_status = "Database must be trained before use"
        for id in [IDC_BUT_FILTER, IDC_BUT_CLASSIFY, IDC_BUT_ENABLE_FILTER]:
            self.GetDlgItem(id).EnableWindow(enable_buttons)
        self.SetDlgItemText(IDC_DB_STATUS, db_status)
        if not enable_buttons:
            self.mgr.config.filter.enabled = False
            self.GetDlgItem(IDC_BUT_ENABLE_FILTER).SetCheck(0)
            return

        # Build a filter-status string
        self.GetDlgItem(IDC_BUT_ENABLE_FILTER).SetCheck(self.mgr.config.filter.enabled)
        names = []
        for eid in self.mgr.config.filter.folder_ids:
            names.append(self.mgr.mapi.GetFolder(eid).Name.encode("ascii", "replace"))
        # count enabled rules
        num = len([r for r in self.mgr.config.rules if r.enabled ])
        if num == 0:
            num_rules_text = " with no active rules"
        elif num == 1:
            num_rules_text = " with 1 active rule"
        else:
            num_rules_text = " with %d active rules" % (num,)

        if not names:
            status = "No folders are being filtered"
        elif len(names) == 1:
            status = "Filtering %s%s." % (names[0], num_rules_text)
        elif len(names) == 2:
            status = "Filtering %s;%s%s." % (names[0], names[1], num_rules_text)
        else:
            status = "Filtering %d folders%s." % (len(names), num_rules_text)
        self.SetDlgItemText(IDC_FILTER_STATUS, status)

    def OnButMoreInfo(self, id, code):
        if code == win32con.BN_CLICKED:
            self.MessageBox("Contributions of HTML code to display here would be welcome :)")

    def OnButDoSomething(self, id, code):
        if code == win32con.BN_CLICKED:
            if id == IDC_BUT_TRAIN:
                doer = self.do_train
            elif id == IDC_BUT_CLASSIFY:
                doer = self.do_classify
            elif id == IDC_BUT_FILTER:
                doer = self.do_filter
            else:
                raise RuntimeError, "Unknown button ID!"
            doer(self)
            self.UpdateControlStatus()

    def OnButEnableFilter(self, id, code):
        if code == win32con.BN_CLICKED:
            self.mgr.config.filter.enabled = self.GetDlgItem(IDC_BUT_ENABLE_FILTER).GetCheck()==1
        
    def OnOK(self):
        return dialog.Dialog.OnOK(self)

if __name__=='__main__':
    def doer(dlg): print "doing something"
    class Generic: pass
    mgr = Generic()
    mgr.bayes = Generic()
    mgr.bayes.nham = 20
    mgr.bayes.nspam = 7
    d = ManagerDialog(mgr, doer, doer, doer)
    d.DoModal()

Index: FilterDialog.py
===================================================================
RCS file: /cvsroot/spambayes/spambayes/Outlook2000/dialogs/FilterDialog.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** FilterDialog.py	19 Oct 2002 18:14:01 -0000	1.2
--- FilterDialog.py	20 Oct 2002 07:47:01 -0000	1.3
***************
*** 13,17 ****
  
  class RuleList:
!     def __init__(self, parent, idc, rules, rule_factory, idc_add = None, idc_remove = None, idc_edit = None):
          self.parent = parent
          self.list = parent.GetDlgItem(idc)
--- 13,19 ----
  
  class RuleList:
!     def __init__(self, parent, idc, rules, rule_factory,
!                  idc_add = None, idc_copy = None, idc_edit = None, idc_remove = None,
!                  idc_moveup = None, idc_movedown = None):
          self.parent = parent
          self.list = parent.GetDlgItem(idc)
***************
*** 27,45 ****
          parent.HookNotify(self.OnTreeItemDoubleClick, commctrl.NM_DBLCLK)
  
!         if idc_add is None: self.butAdd = None
!         else:
!             parent.HookCommand(self.OnButAdd, idc_add)
!             self.butAdd = parent.GetDlgItem(idc_add)
  
!         if idc_remove is None: self.butRemove = None
!         else:
!             parent.HookCommand(self.OnButRemove, idc_remove)
!             self.butRemove = parent.GetDlgItem(idc_remove)
!         if idc_edit is None: self.butEdit = None
          else:
!             parent.HookCommand(self.OnButEdit, idc_edit)
!             self.butEdit = parent.GetDlgItem(idc_edit)
! 
!         self.Refresh()
  
      def PushEnabledStates(self):
--- 29,46 ----
          parent.HookNotify(self.OnTreeItemDoubleClick, commctrl.NM_DBLCLK)
  
!         self._HookButton(idc_add, "butAdd", self.OnButAdd)
!         self._HookButton(idc_copy, "butCopy", self.OnButCopy)
!         self._HookButton(idc_edit, "butEdit", self.OnButEdit)
!         self._HookButton(idc_remove, "butRemove", self.OnButRemove)
!         self._HookButton(idc_moveup, "butMoveUp", self.OnButMoveUp)
!         self._HookButton(idc_movedown, "butMoveDown", self.OnButMoveDown)
!         self.Refresh()
  
!     def _HookButton(self, idc, attr, func):
!         if idc is None:
!             setattr(self, attr, None)
          else:
!             self.parent.HookCommand(func, idc)
!             setattr(self, attr, self.parent.GetDlgItem(idc))
  
      def PushEnabledStates(self):
***************
*** 112,115 ****
--- 113,126 ----
          if self.butRemove is not None: self.butRemove.EnableWindow(itemNew != 0)
          if self.butEdit is not None: self.butEdit.EnableWindow(itemNew != 0)
+         if self.butCopy is not None: self.butCopy.EnableWindow(itemNew != 0)
+         if itemNew:
+             index = self.GetSelectedRuleIndex()
+             if self.butMoveUp is not None:
+                 self.butMoveUp.EnableWindow(index > 0)
+             if self.butMoveDown is not None:
+                 self.butMoveDown.EnableWindow(index < len(self.rules)-1)
+         else:
+             self.butMoveUp.EnableWindow(False)
+             self.butMoveDown.EnableWindow(False)
          return 1
  
***************
*** 149,152 ****
--- 160,196 ----
                  self.Refresh()
  
+     def OnButCopy(self, id, code):
+         if code == win32con.BN_CLICKED:
+             self.SyncEnabledStates()
+             index = self.GetSelectedRuleIndex()
+             
+             rule = copy.copy(self.rules[index])
+             rule.name = "Copy of " + rule.name
+             d = RuleDialog.RuleDialog(rule, self.parent.mgr)
+             if d.DoModal()==win32con.IDOK:
+                 self.rules.append(rule)
+                 self.Refresh(len(self.rules)-1)
+ 
+     def OnButMoveUp(self, id, code):
+         if code == win32con.BN_CLICKED:
+             self.SyncEnabledStates()
+             index = self.GetSelectedRuleIndex()
+             assert index > 0, "Can't move index zero up!"
+             old = self.rules[index]
+             self.rules[index] = self.rules[index-1]
+             self.rules[index-1] = old
+             self.Refresh(index-1)
+ 
+     def OnButMoveDown(self, id, code):
+         if code == win32con.BN_CLICKED:
+             self.SyncEnabledStates()
+             index = self.GetSelectedRuleIndex()
+             num = len(self.rules)
+             assert index < num-1, "Can't move last index down!"
+             old = self.rules[index]
+             self.rules[index] = self.rules[index+1]
+             self.rules[index+1] = old
+             self.Refresh(index+1)
+ 
  IDC_FOLDER_NAMES=1024
  IDC_BROWSE=1025
***************
*** 157,181 ****
  IDC_BUT_FILTERNOW=1030
  IDC_BUT_UNREAD=1031
  
  class FilterArrivalsDialog(dialog.Dialog):
      style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
      cs = win32con.WS_CHILD | win32con.WS_VISIBLE
!     treestyle = cs | win32con.WS_BORDER | commctrl.TVS_CHECKBOXES | commctrl.TVS_DISABLEDRAGDROP | commctrl.TVS_SHOWSELALWAYS
      filter_msg = "Filter the following folders as messages arrive"
      dt = [
          # Dialog itself.
!         ["Filters", (0, 0, 244, 198), style, None, (8, "MS Sans Serif")],
          # Children
          [STATIC,          filter_msg,           -1,                  (  8,   9, 168,  11), cs],
!         [STATIC,          "",                   IDC_FOLDER_NAMES,    (  7,  20, 172,  12), cs | win32con.SS_LEFTNOWORDWRAP | win32con.SS_CENTERIMAGE | win32con.SS_SUNKEN],
!         [BUTTON,          '&Browse',            IDC_BROWSE,          (187,  19,  50,  14), cs | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP],
!         [BUTTON,          "Enabled Rules",      -1,                  (  7,  40, 230, 130), cs | win32con.BS_GROUPBOX],
!         [BUTTON,          "&New...",            IDC_BUT_NEW,         ( 60, 151,  50,  14), cs | win32con.WS_TABSTOP],
!         [BUTTON,          "&Delete",            IDC_BUT_DELETE,      ( 119,151,  50,  14), cs | win32con.WS_TABSTOP | win32con.WS_DISABLED],
!         [BUTTON,          "&Edit...",           IDC_BUT_EDIT,        ( 179,151,  50,  14), cs | win32con.WS_TABSTOP | win32con.WS_DISABLED],
!         ["SysTreeView32", None,                 IDC_LIST_RULES,      ( 14,  52, 216,  95), treestyle | win32con.WS_TABSTOP],
  
!         [BUTTON,         '&Filter Now...',      IDC_BUT_FILTERNOW,   (  7, 177,  50,  14), cs | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP],
!         [BUTTON,         'Close',               win32con.IDOK,       (179, 177,  50,  14), cs | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP],
      ]
  
--- 201,235 ----
  IDC_BUT_FILTERNOW=1030
  IDC_BUT_UNREAD=1031
+ IDC_BUT_COPY=1032
+ IDC_BUT_MOVEUP=1033
+ IDC_BUT_MOVEDOWN=1034
+ 
  
  class FilterArrivalsDialog(dialog.Dialog):
      style = win32con.DS_MODALFRAME | win32con.WS_POPUP | win32con.WS_VISIBLE | win32con.WS_CAPTION | win32con.WS_SYSMENU | win32con.DS_SETFONT
      cs = win32con.WS_CHILD | win32con.WS_VISIBLE
!     csts = cs | win32con.WS_TABSTOP
!     treestyle = csts | win32con.WS_BORDER | commctrl.TVS_CHECKBOXES | commctrl.TVS_DISABLEDRAGDROP | commctrl.TVS_SHOWSELALWAYS
      filter_msg = "Filter the following folders as messages arrive"
      dt = [
          # Dialog itself.
!         ["Filters", (0, 0, 249, 195), style, None, (8, "MS Sans Serif")],
          # Children
          [STATIC,          filter_msg,           -1,                  (  8,   9, 168,  11), cs],
!         [STATIC,          "",                   IDC_FOLDER_NAMES,    (  7,  20, 175,  12), cs   | win32con.SS_LEFTNOWORDWRAP | win32con.SS_CENTERIMAGE | win32con.SS_SUNKEN],
!         [BUTTON,          '&Browse',            IDC_BROWSE,          (190,  19,  50,  14), csts | win32con.BS_PUSHBUTTON],
!         [BUTTON,          "Enabled Rules",      -1,                  (  7,  40, 237, 130), cs   | win32con.BS_GROUPBOX],
!         ["SysTreeView32", None,                 IDC_LIST_RULES,      ( 18,  52, 164,  95), treestyle],
!         
!         [BUTTON,          "&New...",            IDC_BUT_NEW,         (190,  52,  50,  14), csts ],
!         [BUTTON,          "&Copy..",            IDC_BUT_COPY,        (190,  72,  50,  14), csts ],
!         [BUTTON,          "&Modify...",         IDC_BUT_EDIT,        (190,  92,  50,  14), csts | win32con.WS_DISABLED],
!         [BUTTON,          "&Delete",            IDC_BUT_DELETE,      (190, 112,  50,  14), csts | win32con.WS_DISABLED],
  
!         [BUTTON,          "Move &Up",           IDC_BUT_MOVEUP,      ( 15, 150,  73,  14), csts | win32con.WS_DISABLED],
!         [BUTTON,          "Move &Down",         IDC_BUT_MOVEDOWN,    (109, 150,  73,  14), csts | win32con.WS_DISABLED],
!         
!         [BUTTON,         '&Filter Now...',      IDC_BUT_FILTERNOW,   ( 15, 175,  50,  14), csts | win32con.BS_PUSHBUTTON],
!         [BUTTON,         'Close',               win32con.IDOK,       (190, 175,  50,  14), csts | win32con.BS_DEFPUSHBUTTON],
      ]
  
***************
*** 187,191 ****
  
      def OnInitDialog(self):
!         self.list = RuleList(self, IDC_LIST_RULES, self.mgr.config.rules, self.rule_factory, IDC_BUT_NEW, IDC_BUT_DELETE, IDC_BUT_EDIT)
          self.HookCommand(self.OnButBrowse, IDC_BROWSE)
          self.HookCommand(self.OnButFilterNow, IDC_BUT_FILTERNOW)
--- 241,245 ----
  
      def OnInitDialog(self):
!         self.list = RuleList(self, IDC_LIST_RULES, self.mgr.config.rules, self.rule_factory, IDC_BUT_NEW, IDC_BUT_COPY, IDC_BUT_EDIT, IDC_BUT_DELETE, IDC_BUT_MOVEUP, IDC_BUT_MOVEDOWN)
          self.HookCommand(self.OnButBrowse, IDC_BROWSE)
          self.HookCommand(self.OnButFilterNow, IDC_BUT_FILTERNOW)
***************
*** 194,197 ****
--- 248,252 ----
  
      def OnOK(self):
+         self.list.SyncEnabledStates()
          return dialog.Dialog.OnOK(self)
  
***************
*** 299,302 ****
--- 354,358 ----
  
      def StartProcess(self):
+         self.list.SyncEnabledStates()
          return AsyncDialogBase.StartProcess(self)