[Spambayes-checkins] spambayes/Outlook2000/dialogs AsyncDialog.py,NONE,1.1 ClassifyDialog.py,NONE,1.1 DialogGlobals.py,NONE,1.1 FilterDialog.py,NONE,1.1 FolderSelector.py,NONE,1.1 RuleDialog.py,NONE,1.1 TrainingDialog.py,NONE,1.1__init__.py,NONE,1.1

Mark Hammond mhammond@users.sourceforge.net
Sat, 19 Oct 2002 09:24:15 -0700


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

Added Files:
	AsyncDialog.py ClassifyDialog.py DialogGlobals.py 
	FilterDialog.py FolderSelector.py RuleDialog.py 
	TrainingDialog.py __init__.py 
Log Message:
First cut of the GUI itself.


--- NEW FILE: AsyncDialog.py ---
# Base class for an "async" dialog.
from pywin.mfc import dialog
import win32con
import commctrl
import win32ui
import win32api


IDC_START = 1100
IDC_PROGRESS = 1101
IDC_PROGRESS_TEXT = 1102

def MAKELPARAM(low, high):
    return ((0x0000FFFF & high) << 16) | (0x0000FFFF & low)

MYWM_SETSTATUS = win32con.WM_USER+11
MYWM_SETWARNING = win32con.WM_USER+12
MYWM_SETERROR = win32con.WM_USER+13
MYWM_FINISHED = win32con.WM_USER+14

# This is called from another thread - hence we need to jump through hoops!
class _Progress:
    def __init__(self, dlg):
        self.hprogress = dlg.GetDlgItem(IDC_PROGRESS).GetSafeHwnd()
        self.hdlg = dlg.GetSafeHwnd()
        self.dlg = dlg
        self.stopping = False
    def set_max_ticks(self, m):
        win32api.PostMessage(self.hprogress, commctrl.PBM_SETRANGE, 0, MAKELPARAM(0,m))
        win32api.PostMessage(self.hprogress, commctrl.PBM_SETSTEP, 1, 0)
        win32api.PostMessage(self.hprogress, commctrl.PBM_SETPOS, 0, 0)
    def tick(self):
        win32api.PostMessage(self.hprogress, commctrl.PBM_STEPIT, 0, 0)
        #self.p.StepIt()
    def set_status(self, text):
        self.dlg.progress_status = text
        win32api.PostMessage(self.hdlg, MYWM_SETSTATUS)
    def warning(self, text):
        self.dlg.progress_warning = text
        win32api.PostMessage(self.hdlg, MYWM_SETWARNING)
    def error(self, text):
        self.dlg.progress_error = text
        win32api.PostMessage(self.hdlg, MYWM_SETERROR)
    def request_stop(self):
        self.stopping = True
    def stop_requested(self):
        return self.stopping


class AsyncDialogBase(dialog.Dialog):
    def __init__ (self, dt):
        dialog.Dialog.__init__ (self, dt)
        self.progress_status = ""
        self.progress_error = ""
        self.progress_warning = ""
        self.running = False

    def OnInitDialog(self):
        self.GetDlgItem(IDC_PROGRESS).ShowWindow(win32con.SW_HIDE)
        self.HookMessage(self.OnProgressStatus, MYWM_SETSTATUS)
        self.HookMessage(self.OnProgressError, MYWM_SETERROR)
        self.HookMessage(self.OnProgressWarning, MYWM_SETWARNING)
        self.HookMessage(self.OnFinished, MYWM_FINISHED)
        self.HookCommand(self.OnStart, IDC_START)
        return dialog.Dialog.OnInitDialog (self)

    def OnFinished(self, msg):
        self.seen_finished = True
        wasCancelled = msg[2]
        for id in self.disable_while_running_ids:
            self.GetDlgItem(id).EnableWindow(1)

        self.SetDlgItemText(IDC_START, self.process_start_text)
        self.GetDlgItem(IDC_PROGRESS).ShowWindow(win32con.SW_HIDE)
        if wasCancelled:
            self.SetDlgItemText(IDC_PROGRESS_TEXT, "Cancelled")

    def OnProgressStatus(self, msg):
        self.SetDlgItemText(IDC_PROGRESS_TEXT, self.progress_status)

    def OnProgressError(self, msg):
        self.SetDlgItemText(IDC_PROGRESS_TEXT, self.progress_error)
        self.MessageBox(self.progress_error)
        if not self.running and not self.seen_finished:
            self.OnFinished( (0,0,0) )

    def OnProgressWarning(self, msg):
        pass

    def OnStart(self, id, code):
        if id == IDC_START:
            self.StartProcess()

    def StartProcess(self):
            if self.running:
                self.progress.request_stop()
            else:
                for id in self.disable_while_running_ids:
                    self.GetDlgItem(id).EnableWindow(0)
                self.SetDlgItemText(IDC_START, self.process_stop_text)
                self.SetDlgItemText(IDC_PROGRESS_TEXT, "")
                self.GetDlgItem(IDC_PROGRESS).ShowWindow(win32con.SW_SHOW)
                # Local function for the thread target that notifies us when finished.
                def thread_target(h, progress):
                    try:
                        self.progress = progress
                        self.seen_finished = False
                        self.running = True
                        self._DoProcess()
                    finally:
                        win32api.PostMessage(h, MYWM_FINISHED, self.progress.stop_requested())
                        self.running = False
                        self.progress = None

                # back to the program :)
                import threading
                t = threading.Thread(target=thread_target, args =(self.GetSafeHwnd(), _Progress(self)))
                t.start()

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

#these are the atom numbers defined by Windows for basic dialog controls
BUTTON    = 0x80
EDIT      = 0x81
STATIC    = 0x82
LISTBOX   = 0x83
SCROLLBAR = 0x84
COMBOBOX  = 0x85

IDC_STATIC_FOLDERS = 1001
IDC_BROWSE = 1002
IDC_FIELDNAME = 1003
from AsyncDialog import IDC_START, IDC_PROGRESS, IDC_PROGRESS_TEXT, AsyncDialogBase


class ClassifyDialog(AsyncDialogBase):
    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
    info_text = "For every message in the selected folders, a new field will be created with the spam rating.  The Outlook 'Field Chooser' can show the field"
    classify_text = "Classify messages in the following folder"
    process_start_text = "&Classify now"
    process_stop_text = "Stop &classification"
    dt = [
        # Dialog itself.
        ["Classification", (0, 0, 241, 130), style, None, (8, "MS Sans Serif")],
        # Children
        [STATIC,          info_text,            -1,                   (  7,  6, 227,  16), cs ],
        [STATIC,          classify_text,        -1,                   (  7, 29, 131,  11), cs ],
        
        [STATIC,          "",                   IDC_STATIC_FOLDERS,   (  7,  40, 167,  12), cs | win32con.SS_SUNKEN | win32con.SS_LEFTNOWORDWRAP | win32con.SS_CENTERIMAGE],
        [BUTTON,          '&Browse',            IDC_BROWSE,           (184,  40,  50,  14), cs | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP],

        [STATIC,          "Field name to create",-1,                  (  7,  60,  67,  11), cs],
        [EDIT,            "",                    IDC_FIELDNAME,       ( 80,  57,  93,  14), cs | win32con.WS_BORDER | win32con.ES_AUTOHSCROLL],

        [BUTTON,         process_start_text,    IDC_START,            (  7, 109,  70,  14), cs | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP],
        ["msctls_progress32", '',               IDC_PROGRESS,         (  7,  80, 166,  11), cs | win32con.WS_BORDER],
        [STATIC,          '',                   IDC_PROGRESS_TEXT,    (  7,  96, 227,  10), cs ],

        [BUTTON,          'Close',              win32con.IDOK,        (184, 109,  50,  14), cs | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP],
        
    ]
    disable_while_running_ids = [IDC_FIELDNAME, IDC_BROWSE, win32con.IDOK]

    def __init__ (self, mgr, classifier):
        self.classifier = classifier
        self.config = mgr.config.classify
        self.mapi = mgr.mapi
        self.mgr = mgr
        AsyncDialogBase.__init__ (self, self.dt)

    def OnInitDialog(self):
        self.HookCommand(self.OnBrowse, IDC_BROWSE)
        self.SetDlgItemText(IDC_FIELDNAME, self.config.field_name)
        self.UpdateStatus()
        return AsyncDialogBase.OnInitDialog (self)

    def UpdateStatus(self):
        names = []
        for eid in self.config.folder_ids:
            try:
                name = self.mapi.GetFolder(eid).Name.encode("ascii", "replace")
            except pythoncom.com_error:
                name = "<unknown folder>"
            names.append(name)
        self.SetDlgItemText(IDC_STATIC_FOLDERS, "; ".join(names))

    def OnBrowse(self, id, code):
        if code == win32con.BN_CLICKED:
            import FolderSelector
            l = self.config.folder_ids
            d = FolderSelector.FolderSelector(self.mapi, l,checkbox_state=self.config.include_sub)
            if d.DoModal()==win32con.IDOK:
                l[:], self.config.include_sub = d.GetSelectedIDs()[:]
                self.UpdateStatus()

    def _DoProcess(self):
        fieldName = self.GetDlgItemText(IDC_FIELDNAME)
        if not fieldName:
            self.progress.error("You must specify a field name")
            return
        self.config.field_name = fieldName
        self.mgr.WorkerThreadStarting()
        try:
            self.classifier(self.mgr, self.progress)
        finally:
            self.mgr.WorkerThreadEnding()

--- NEW FILE: DialogGlobals.py ---
# General helpers for out dialogs
def INDEXTOSTATEIMAGEMASK(i): # from new commctrl.h
    return i << 12

IIL_UNCHECKED = 1
IIL_CHECKED = 2

#these are the atom numbers defined by Windows for basic dialog controls
BUTTON    = 0x80
EDIT      = 0x81
STATIC    = 0x82
LISTBOX   = 0x83
SCROLLBAR = 0x84
COMBOBOX  = 0x85

--- NEW FILE: FilterDialog.py ---
from __future__ import generators
import copy

from pywin.mfc import dialog
import win32con
import commctrl
import win32ui
import win32api
import pythoncom

from DialogGlobals import *
import RuleDialog

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)
        self.rules = rules
        self.rule_factory = rule_factory

        bitmapID = win32ui.IDB_HIERFOLDERS
        bitmapMask = win32api.RGB(0,0,255)
        self.imageList = win32ui.CreateImageList(bitmapID, 16, 0, bitmapMask)
        self.list.SetImageList(self.imageList, commctrl.LVSIL_NORMAL)

        parent.HookNotify(self.OnTreeItemSelChanged, commctrl.TVN_SELCHANGED)
        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):
        self.pushed_state = {}
        for rule in self.rules:
            self.pushed_state[rule] = rule.enabled

    def PopEnabledStates(self):
        for rule in self.rules:
            old_state = self.pushed_state.get(rule)
            if old_state is not None:
                rule.enabled = old_state

    def Refresh(self, selIndex = None):
        if selIndex is None:
            selIndex = self.GetSelectedRuleIndex()
        self.SyncEnabledStates()
        self.list.DeleteAllItems()
        index = 0
        for rule in self.rules:
            if rule.enabled:
                state = INDEXTOSTATEIMAGEMASK(IIL_CHECKED)
            else:
                state = INDEXTOSTATEIMAGEMASK(IIL_UNCHECKED)
            mask = commctrl.TVIS_STATEIMAGEMASK
            bitmapCol = bitmapSel = 5
            hItem = self.list.InsertItem(commctrl.TVI_ROOT, 0, (None, state, mask, rule.name, bitmapCol, bitmapSel, 0, index))
            if index == selIndex:
                self.list.SelectItem(hItem)
            index += 1

    def _YieldItems(self):
        try:
            h = self.list.GetNextItem(commctrl.TVI_ROOT, commctrl.TVGN_CHILD)
        except win32ui.error:
            h = None
        index = 0
        while h is not None:
            yield h, index, self.rules[index]
            index += 1
            try:
                h = self.list.GetNextItem(h, commctrl.TVGN_NEXT)
            except win32ui.error:
                h = None

    # No reliable way to get notified of checkbox state - so
    # when we need to know, this will set rule.enabled to the
    # current state of the checkbox.
    def SyncEnabledStates(self):
        mask = INDEXTOSTATEIMAGEMASK(IIL_UNCHECKED) | INDEXTOSTATEIMAGEMASK(IIL_CHECKED)
        for h, index, rule in self._YieldItems():
            state = self.list.GetItemState(h, mask)
            checked = (state >> 12) - 1
            rule.enabled = checked

    def GetSelectedRuleIndex(self):
        try:
            hitem = self.list.GetSelectedItem()
        except win32ui.error:
            return None

        for h, index, rule in self._YieldItems():
            if hitem == h:
                return index

    def OnTreeItemSelChanged(self,(hwndFrom, idFrom, code), extra):
        #if idFrom != IDC_LIST_FOLDERS: return None
        action, itemOld, itemNew, pt = extra

        if self.butRemove is not None: self.butRemove.EnableWindow(itemNew != 0)
        if self.butEdit is not None: self.butEdit.EnableWindow(itemNew != 0)
        return 1

    def OnTreeItemDoubleClick(self,(hwndFrom, idFrom, code), extra):
        if self.butEdit is not None:
            self.OnButEdit(idFrom, win32con.BN_CLICKED)

    def OnButRemove(self, id, code):
        if code == win32con.BN_CLICKED:
            self.SyncEnabledStates()
            index = self.GetSelectedRuleIndex()
            hitem = self.list.GetSelectedItem()
            name = self.rules[index].name
            result = self.parent.MessageBox("Are you sure you wish to delete rule '%s'?" % (name,), "Delete confirmation", win32con.MB_YESNO)
            if result==win32con.IDYES:
                self.list.DeleteItem(hitem)
                del self.rules[index]
                self.Refresh()

    def OnButAdd(self, id, code):
        if code == win32con.BN_CLICKED:
            new_rule = self.rule_factory()
            d = RuleDialog.RuleDialog(new_rule, self.parent.mgr)
            if d.DoModal()==win32con.IDOK:
                self.rules.append(new_rule)
                self.Refresh(len(self.rules)-1)

    def OnButEdit(self, id, code):
        if code == win32con.BN_CLICKED:
            self.SyncEnabledStates()
            index = self.GetSelectedRuleIndex()
            
            rule = copy.copy(self.rules[index])
            d = RuleDialog.RuleDialog(rule, self.parent.mgr)
            if d.DoModal()==win32con.IDOK:
                self.rules[index] = rule
                self.Refresh()

IDC_FOLDER_NAMES=1024
IDC_BROWSE=1025
IDC_BUT_DELETE=1026
IDC_BUT_NEW=1027
IDC_BUT_EDIT=1028
IDC_LIST_RULES=1029
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],
    ]

    def __init__(self, mgr, rule_factory, filterer):
        self.mgr = mgr
        self.rule_factory = rule_factory
        self.filterer = filterer
        dialog.Dialog.__init__(self, self.dt)
        
    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)
        self.UpdateFolderNames()
        return dialog.Dialog.OnInitDialog(self)

    def OnOK(self):
        return dialog.Dialog.OnOK(self)

    def OnDestroy(self,msg):
        dialog.Dialog.OnDestroy(self, msg)
        self.list = None
        self.mgr = None

    def UpdateFolderNames(self):
        names = []
        folder_ids = self.mgr.config.filter.folder_ids
        for eid in folder_ids:
            try:
                name = self.mgr.mapi.GetFolder(eid).Name.encode("ascii", "replace")
            except pythoncom.com_error:
                name = "<unknown folder>"
            names.append(name)
        self.SetDlgItemText(IDC_FOLDER_NAMES, "; ".join(names))

    def OnButBrowse(self, id, code):
        if code == win32con.BN_CLICKED:
            import FolderSelector
            filter = self.mgr.config.filter
            d = FolderSelector.FolderSelector(self.mgr.mapi, filter.folder_ids,checkbox_state=filter.include_sub)
            if d.DoModal()==win32con.IDOK:
                filter.folder_ids, filter.include_sub = d.GetSelectedIDs()
                self.UpdateFolderNames()

    def OnButFilterNow(self, id, code):
        if code == win32con.BN_CLICKED:
            self.list.SyncEnabledStates()
            self.list.PushEnabledStates()
            d = FilterNowDialog(self.mgr, self.rule_factory, self.filterer)
            d.DoModal()
            self.list.PopEnabledStates()
            self.list.Refresh()

from AsyncDialog import *

class FilterNowDialog(AsyncDialogBase):
    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
    only_unread = "Only apply the filter to unread mail"
    process_start_text = "&Start filtering"
    process_stop_text = "&Stop filtering"
    dt = [
        # Dialog itself.
        ["Filter Now", (0, 0, 244, 221), style, None, (8, "MS Sans Serif")],
        # Children
        [STATIC,          "Filter the following folders", -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,          "Run the following rules", -1,             (  7,  40, 230, 113), cs | win32con.BS_GROUPBOX],
        ["SysTreeView32", None,                 IDC_LIST_RULES,      ( 14,  52, 216,  95), treestyle | win32con.WS_TABSTOP],
        [BUTTON,          only_unread,          IDC_BUT_UNREAD,      ( 15, 157, 149,   9), cs | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],

        ["msctls_progress32", '',               IDC_PROGRESS,        ( 10, 170, 227,  11), cs | win32con.WS_BORDER],
        [STATIC,          '',                   IDC_PROGRESS_TEXT,   ( 10, 186, 227,  10), cs ],
        
        [BUTTON,         process_start_text,    IDC_START,           (  7, 200,  60,  14), cs | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP],
        [BUTTON,         'Close',               win32con.IDOK,       (187, 200,  50,  14), cs | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP],
    ]
    disable_while_running_ids = [IDC_LIST_RULES, IDC_BUT_UNREAD, IDC_BROWSE, win32con.IDOK]

    def __init__(self, mgr, rule_factory, filterer):
        self.mgr = mgr
        self.filterer = filterer
        self.rule_factory = rule_factory
        AsyncDialogBase.__init__ (self, self.dt)
        
    def OnInitDialog(self):
        self.list = RuleList(self, IDC_LIST_RULES, self.mgr.config.rules, self.rule_factory)
        self.HookCommand(self.OnButBrowse, IDC_BROWSE)
        self.HookCommand(self.OnButUnread, IDC_BUT_UNREAD)
        if self.mgr.config.filter_now.only_unread:
            self.GetDlgItem(IDC_BUT_UNREAD).SetCheck(1)
        else:
            self.GetDlgItem(IDC_BUT_UNREAD).SetCheck(0)
        self.UpdateFolderNames()
        return AsyncDialogBase.OnInitDialog(self)

    def UpdateFolderNames(self):
        names = []
        for eid in self.mgr.config.filter_now.folder_ids:
            try:
                name = self.mgr.mapi.GetFolder(eid).Name.encode("ascii", "replace")
            except pythoncom.com_error:
                name = "<unknown folder>"
            names.append(name)
        self.SetDlgItemText(IDC_FOLDER_NAMES, "; ".join(names))

    def OnButBrowse(self, id, code):
        if code == win32con.BN_CLICKED:
            import FolderSelector
            filter = self.mgr.config.filter_now
            d = FolderSelector.FolderSelector(self.mgr.mapi, filter.folder_ids,checkbox_state=filter.include_sub)
            if d.DoModal()==win32con.IDOK:
                filter.folder_ids, filter.include_sub = d.GetSelectedIDs()
                self.UpdateFolderNames()

    def OnButUnread(self, id, code):
        if code == win32con.BN_CLICKED:
            self.mgr.config.filter_now.only_unread = self.GetDlgItem(IDC_BUT_UNREAD).GetCheck() != 0

    def StartProcess(self):
        return AsyncDialogBase.StartProcess(self)

    def _DoProcess(self):
        if self.filterer is None:
            print "Testing, testing, 1...2...3..."
        else:
            self.mgr.WorkerThreadStarting()
            try:
                self.filterer(self.mgr, self.progress, self.mgr.config.filter_now)
            finally:
                self.mgr.WorkerThreadEnding()

if __name__=='__main__':
    from win32com.client import Dispatch
    import pythoncom
    mapi = Dispatch("MAPI.Session")
    mapi.Logon()

    class Config: pass
    class Manager: pass
    mgr = Manager()
    mgr.mapi = mapi
    mgr.config = config = Config()
    config.filter = Config()
    config.filter.folder_ids = [mapi.Inbox.ID]
    config.filter.include_sub = True
    config.filter_now=Config()
    config.filter_now.folder_ids = [mapi.Inbox.ID]
    config.filter_now.include_sub = True
    config.filter_now.only_unread= True

    class Rule:
        def __init__(self):
            self.enabled = True
            self.name = "My Rule"
            self.min = 0.1
            self.max = 0.9
            self.action = "Move"
            self.flag_message = True
            self.write_field = True
            self.write_field_name = "SpamProb"
            self.folder_id = ""
        def GetProblem(self, mgr):
            if self.min > self.max:
                return "max must be > min"

    config.rules = [Rule()]

    tester = FilterArrivalsDialog
    #tester = FilterNowDialog
    d = tester(mgr, Rule, None)
    d.DoModal()

--- NEW FILE: FolderSelector.py ---
from __future__ import generators

from pywin.mfc import dialog
import win32con
import commctrl
import win32ui
import win32api

from DialogGlobals import *

# Helpers for building the folder list
class FolderSpec:
    def __init__(self, folder, name = None):
        if name is None:
            self.name = folder.Name
        else:
            self.name = name
        self.name = self.name.encode("ascii", "replace")
        self.children = []
        self.folder = folder

    def dump(self, level=0):
        prefix = "  " * level
        print prefix + self.name
        for c in self.children:
            c.dump(level+1)

def _BuildFolders(folders):
    children = []
    folder = folders.GetFirst()
    while folder:
        spec = FolderSpec(folder)
        spec.children = _BuildFolders(folder.Folders)
        children.append(spec)
        folder = folders.GetNext()
    return children

def BuildFolderTree(session):
    infostores = session.InfoStores
    root = FolderSpec(None, "root")
    for i in range(infostores.Count):
        infostore = infostores[i+1]
        rootFolder = infostore.RootFolder
        folders = rootFolder.Folders
        spec = FolderSpec(rootFolder, infostore.Name)
        spec.children = _BuildFolders(folders)
        root.children.append(spec)
    return root

#
# The dialog itself

# IDs for controls we use.
IDC_STATUS1 = win32ui.IDC_PROMPT1
IDC_STATUS2 = win32ui.IDC_PROMPT2
IDC_BUTTON_SEARCHSUB = win32ui.IDC_BUTTON1
IDC_BUTTON_CLEARALL = win32ui.IDC_BUTTON2
IDC_LIST_FOLDERS = win32ui.IDC_LIST1

class FolderSelector(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_HASLINES | commctrl.TVS_LINESATROOT | \
                commctrl.TVS_CHECKBOXES | commctrl.TVS_HASBUTTONS | \
                commctrl.TVS_DISABLEDRAGDROP | commctrl.TVS_SHOWSELALWAYS
    dt = [
        # Dialog itself.
        ["", (0, 0, 247, 215), style, None, (8, "MS Sans Serif")],
        # Children
        [STATIC,          "&Folders:",          -1,                   (7,   7,  47,  9), cs ],
        ["SysTreeView32", None,                 IDC_LIST_FOLDERS,     (7,  21, 172, 140), treestyle | win32con.WS_TABSTOP],
        [BUTTON,          '',                   IDC_BUTTON_SEARCHSUB, (7,  167, 126,  9), cs | win32con.BS_AUTOCHECKBOX | win32con.WS_TABSTOP],
        [STATIC,          "",                   IDC_STATUS1,          (7,  180, 220,  9), cs ],
        [STATIC,          "",                   IDC_STATUS2,          (7,  194, 220,  9), cs ],
        [BUTTON,         'OK',                  win32con.IDOK,        (190, 21,  50, 14), cs | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP],
        [BUTTON,         'Cancel',              win32con.IDCANCEL,    (190, 39,  50, 14), cs | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP],
        [BUTTON,         'C&lear All',          IDC_BUTTON_CLEARALL,  (190, 58,  50, 14), cs | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP],
    ]

    def __init__ (self, mapi, selected_ids = None, single_select = False, checkbox_state = False, checkbox_text = None, desc_noun = "Select", desc_noun_suffix = "ed"):
        assert single_select == False or selected_ids is None or len(selected_ids)<=1
        dialog.Dialog.__init__ (self, self.dt)
        self.single_select = single_select
        self.next_item_id = 1
        self.item_map = {}
        
        self.select_desc_noun = desc_noun
        self.select_desc_noun_suffix = desc_noun_suffix
        self.selected_ids = selected_ids
        self.mapi = mapi
        self.checkbox_state = checkbox_state
        self.checkbox_text = checkbox_text or "Include &subfolders"

    def _MakeItemParam(self, item):
        item_id = self.next_item_id
        self.next_item_id += 1
        self.item_map[item_id] = item
        return item_id

    def _InsertSubFolders(self, hParent, folderSpec):
        num_children_selected = 0
        for child in folderSpec.children:
            text = child.name
            cItems = len(child.children)
            if cItems==0:
                bitmapCol = bitmapSel = 5 # blank doc
            else:
                bitmapCol = bitmapSel = 0 # folder
            if self.single_select:
                mask = state = 0
            else:
                if self.selected_ids and child.folder.ID in self.selected_ids:
                    state = INDEXTOSTATEIMAGEMASK(IIL_CHECKED)
                    num_children_selected += 1
                else:
                    state = INDEXTOSTATEIMAGEMASK(IIL_UNCHECKED)
                mask = commctrl.TVIS_STATEIMAGEMASK
            item_id = self._MakeItemParam(child)
            hitem = self.list.InsertItem(hParent, 0, (None, state, mask, text, bitmapCol, bitmapSel, cItems, item_id))
            if self.single_select and self.selected_ids and child.folder.ID in self.selected_ids:
                self.list.SelectItem(hitem)

            num_children_selected += self._InsertSubFolders(hitem, child)
        if num_children_selected and hParent:
            self.list.Expand(hParent, commctrl.TVE_EXPAND)
        return num_children_selected

    def _YieldChildren(self, h):
        try:
            h = self.list.GetNextItem(h, commctrl.TVGN_CHILD)
        except win32ui.error:
            h = None
        while h is not None:
            info = self.list.GetItem(h)
            spec = self.item_map[info[7]]
            yield info, spec
            # Check children
            for info, spec in self._YieldChildren(h):
                yield info, spec
            try:
                h = self.list.GetNextItem(h, commctrl.TVGN_NEXT)
            except win32ui.error:
                h = None

    def _YieldAllChildren(self):
        return self._YieldChildren(commctrl.TVI_ROOT)

    def _YieldCheckedChildren(self):
        if self.single_select:
            # If single-select, the checked state is not used, just the selected state.
            try:
                h = self.list.GetSelectedItem()
            except win32ui.error:
                return
            info = self.list.GetItem(h)
            spec = self.item_map[info[7]]
            yield info, spec
            return # single-hit yield.
            
        for info, spec in self._YieldAllChildren():
                checked = (info[1] >> 12) - 1
                if checked:
                    yield info, spec

    def OnInitDialog (self):
        caption = "%s folder" % (self.select_desc_noun,)
        if not self.single_select:
            caption += "(s)"
        self.SetWindowText(caption)
        self.SetDlgItemText(IDC_BUTTON_SEARCHSUB, self.checkbox_text)
        if self.checkbox_state is None:
            self.GetDlgItem(IDC_BUTTON_SEARCHSUB).ShowWindow(win32con.SW_HIDE)
        else:
            self.GetDlgItem(IDC_BUTTON_SEARCHSUB).SetCheck(self.checkbox_state)
        self.list = self.GetDlgItem(win32ui.IDC_LIST1)

        self.HookNotify(self.OnTreeItemExpanding, commctrl.TVN_ITEMEXPANDING)
        self.HookNotify(self.OnTreeItemSelChanged, commctrl.TVN_SELCHANGED)
        self.HookNotify(self.OnTreeItemClick, commctrl.NM_CLICK)
        self.HookNotify(self.OnTreeItemDoubleClick, commctrl.NM_DBLCLK)
        self.HookCommand(self.OnClearAll, IDC_BUTTON_CLEARALL)

        bitmapID = win32ui.IDB_HIERFOLDERS
        bitmapMask = win32api.RGB(0,0,255)
        self.imageList = win32ui.CreateImageList(bitmapID, 16, 0, bitmapMask)
        self.list.SetImageList(self.imageList, commctrl.LVSIL_NORMAL)
        if self.single_select:
            # Remove the checkbox style from the list for single-selection
            style = win32api.GetWindowLong(self.list.GetSafeHwnd(), win32con.GWL_STYLE)
            style = style & ~commctrl.TVS_CHECKBOXES
            win32api.SetWindowLong(self.list.GetSafeHwnd(), win32con.GWL_STYLE, style)
            # Hide "clear all"
            self.GetDlgItem(IDC_BUTTON_CLEARALL).ShowWindow(win32con.SW_HIDE)

        tree = BuildFolderTree(self.mapi)
        self._InsertSubFolders(0, tree)
        self.selected_ids = [] # wipe this out while we are alive.
        self._UpdateStatus()

        return dialog.Dialog.OnInitDialog (self)

    def OnDestroy(self, msg):
        self.item_map = None
        return dialog.Dialog.OnDestroy(self, msg)

    def OnClearAll(self, id, code):
        if code == win32con.BN_CLICKED:
            for info, spec in self._YieldCheckedChildren():
                state = INDEXTOSTATEIMAGEMASK(IIL_UNCHECKED)
                mask = commctrl.TVIS_STATEIMAGEMASK
                self.list.SetItemState(info[0], state, mask)
            self._UpdateStatus()

    def _DoUpdateStatus(self, id, timeval):
        try:
            names = []
            num_checked = 0
            for info, spec in self._YieldCheckedChildren():
                num_checked += 1
                if len(names) < 20:
                    names.append(info[3])

            status_string = "%s%s %d folder" % (self.select_desc_noun, self.select_desc_noun_suffix, num_checked)
            if num_checked != 1:
                status_string += "s"
            self.SetDlgItemText(IDC_STATUS1, status_string)
            self.SetDlgItemText(IDC_STATUS2, "; ".join(names))
        finally:
            import timer
            timer.kill_timer(id)

    def _UpdateStatus(self):
        import timer
        timer.set_timer (0, self._DoUpdateStatus)

    def OnOK(self):
        self.selected_ids, self.checkbox_state = self.GetSelectedIDs()
        return self._obj_.OnOK()
    def OnCancel(self):
        return self._obj_.OnCancel()

    def OnTreeItemDoubleClick(self,(hwndFrom, idFrom, code), extra):
        if idFrom != IDC_LIST_FOLDERS: return None
        if self.single_select: # Only close on double-click for single-select
            self.OnOK()
        return 0

    def OnTreeItemClick(self,(hwndFrom, idFrom, code), extra):
        if idFrom != IDC_LIST_FOLDERS: return None
        self._UpdateStatus()
        return 0

    def OnTreeItemExpanding(self,(hwndFrom, idFrom, code), extra):
        if idFrom != IDC_LIST_FOLDERS: return None
        action, itemOld, itemNew, pt = extra
        return 0

    def OnTreeItemSelChanged(self,(hwndFrom, idFrom, code), extra):
        if idFrom != IDC_LIST_FOLDERS: return None
        action, itemOld, itemNew, pt = extra
        self._UpdateStatus()
        return 1

    def GetSelectedIDs(self):
        try:
            self.GetDlgItem(IDC_LIST_FOLDERS)
        except win32ui.error: # dialog dead!
            return self.selected_ids, self.checkbox_state
        ret = []
        for info, spec in self._YieldCheckedChildren():
            ret.append(spec.folder.ID)
        return ret, self.GetDlgItem(IDC_BUTTON_SEARCHSUB).GetCheck() != 0

def TestWithMAPI():
    from win32com.client import Dispatch
    mapi = Dispatch("MAPI.Session")
    mapi.Logon("", "", False, False)
    ids = [u'0000000071C4408983B0B24F8863EE66A8F79AFF82800000']
    d=FolderSelector(mapi, ids, single_select = True)
    d.DoModal()
    print d.GetSelectedIDs()

if __name__=='__main__':
    TestWithMAPI()

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

from DialogGlobals import *

IDC_RULE_NAME = 1024
IDC_SLIDER_LOW = 1025
IDC_EDIT_LOW = 1026
IDC_SLIDER_HIGH = 1027
IDC_EDIT_HIGH = 1028
IDC_ACTION = 1029
IDC_FOLDER_NAME = 1030
IDC_BROWSE = 1031
IDC_FLAG = 1032
IDC_FIELD_NAME = 1033
IDC_WRITE_FIELD = 1034

class RuleDialog(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 = 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.
        ["Define Rule", (0, 0, 249, 199), style, None, (8, "MS Sans Serif")],
        # Children
        [STATIC,          "Enter a name for the filter", -1,         (  7,   6,  94,  11), cs],
        [EDIT,            "",                   IDC_RULE_NAME,       (120,   6, 118,  14), csts | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER],
        [STATIC,          "When the spam rating is between", -1,     (  7,  23, 107,  10), cs],
        ["msctls_trackbar32", "",               IDC_SLIDER_LOW,      (  7,  38, 112,   8), cs   | commctrl.TBS_BOTH | commctrl.TBS_NOTICKS],
        [EDIT,            "",                   IDC_EDIT_LOW,        (120,  34,  59,  14), csts | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER],
        [STATIC,          "and",                -1,                  (  7,  46, 107,  10), cs],
        ["msctls_trackbar32", "",               IDC_SLIDER_HIGH,     (  7,  57, 112,   8), cs   | commctrl.TBS_BOTH | commctrl.TBS_NOTICKS],
        [EDIT,            "",                   IDC_EDIT_HIGH,       (120,  54,  59,  14), csts | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER],

        [STATIC,          "Take the following actions", -1,          (  7,  72, 107,  10), cs],

        [BUTTON,          "Copy/Move message",  -1,                  (  7,  86, 235,  35), cs   | win32con.BS_GROUPBOX],
        [COMBOBOX,        "",                   IDC_ACTION,          ( 14,  97,  55,  40), csts | win32con.CBS_DROPDOWNLIST | win32con.WS_VSCROLL],
        [STATIC,          "to folder",          -1,                  ( 79,  99,  31,  10), cs],
        [STATIC,          "",                   IDC_FOLDER_NAME,     ( 120, 97,  59,  14), cs   | win32con.SS_LEFTNOWORDWRAP | win32con.SS_CENTERIMAGE | win32con.SS_SUNKEN],
        [BUTTON,          '&Browse',            IDC_BROWSE,          (186,  97,  50,  14), csts | win32con.BS_PUSHBUTTON],

        [BUTTON,          "Modify message",     -1,                  (  7, 129, 235,  45), cs   | win32con.BS_GROUPBOX],
        [BUTTON,          "Create a flag on the message", IDC_FLAG,  ( 11, 137, 109,  16), csts | win32con.BS_AUTOCHECKBOX],
        [BUTTON,          "Write spam score to field", IDC_WRITE_FIELD, (11,151,108,  15), csts | win32con.BS_AUTOCHECKBOX],
        [EDIT,            "",                   IDC_FIELD_NAME,      (120, 152,  59,  14), csts | win32con.ES_AUTOHSCROLL | win32con.WS_BORDER],
        
        [BUTTON,         'OK',                  win32con.IDOK,       (129, 178,  50,  14), csts | win32con.BS_DEFPUSHBUTTON],
        [BUTTON,         'Cancel',              win32con.IDCANCEL,   (192, 178,  50,  14), csts | win32con.BS_PUSHBUTTON],
    ]

    def __init__(self, rule, mgr = None):
        self.rule = rule
        self.mgr = mgr
        self.folder_id = rule.folder_id
        dialog.Dialog.__init__ (self, self.dt)
        
    def OnInitDialog(self):
        rule = self.rule
        self.SetDlgItemText(IDC_RULE_NAME, rule.name)
        self.SetDlgItemText(IDC_EDIT_LOW, "%.2f" % rule.min)
        self.SetDlgItemText(IDC_EDIT_HIGH, "%.2f" % rule.max)
        self.GetDlgItem(IDC_FLAG).SetCheck(rule.flag_message)
        self.GetDlgItem(IDC_WRITE_FIELD).SetCheck(rule.write_field)
        edit = self.GetDlgItem(IDC_FIELD_NAME)
        edit.SetWindowText(rule.write_field_name)
        edit.EnableWindow(rule.write_field)
        
        self._InitSlider(IDC_SLIDER_HIGH, IDC_EDIT_HIGH)
        self._InitSlider(IDC_SLIDER_LOW, IDC_EDIT_LOW)
        self.HookMessage (self.OnSlider, win32con.WM_HSCROLL)
        self.HookCommand(self.OnEditChange, IDC_EDIT_HIGH)
        self.HookCommand(self.OnEditChange, IDC_EDIT_LOW)
        self.HookCommand(self.OnButWriteField, IDC_WRITE_FIELD)
        self.HookCommand(self.OnButBrowse, IDC_BROWSE)
        self._UpdateFolderName()

        combo = self.GetDlgItem(IDC_ACTION)
        index = sel_index = 0
        for s in ["None", "Move", "Copy"]:
            combo.AddString(s)
            if s == rule.action: sel_index = index
            index+=1
        combo.SetCurSel(sel_index)
        return dialog.Dialog.OnInitDialog(self)

    def _UpdateFolderName(self):
        try:
            if not self.folder_id:
                name = ""
            elif self.mgr.mapi is None:
                name = "<no mapi!>"
            else:
                name = self.mgr.mapi.GetFolder(self.folder_id).Name.encode("ascii", "replace")
        except pythoncom.com_error:
            name = "<unknown folder>"
        self.SetDlgItemText(IDC_FOLDER_NAME, name)

    def OnEditChange(self, controlid, code):
        if code==win32con.EN_CHANGE:
            if controlid == IDC_EDIT_HIGH:
                sliderid = IDC_SLIDER_HIGH
            else:
                sliderid = IDC_SLIDER_LOW
            self._AdjustSliderToEdit(sliderid, controlid)
        return 1 # I handled this, so no need to call defaults!

    def OnButWriteField(self, id, code):
        if code == win32con.BN_CLICKED:
            edit = self.GetDlgItem(IDC_FIELD_NAME)
            edit.EnableWindow( self.GetDlgItem(IDC_WRITE_FIELD).GetCheck() )
        return 1

    def OnButBrowse(self, id, code):
        if code == win32con.BN_CLICKED:
            import FolderSelector
            ids = [self.folder_id]
            d = FolderSelector.FolderSelector(self.mgr.mapi, ids,single_select=True,checkbox_state=None)#, allow_multi=False)
            if d.DoModal()==win32con.IDOK:
                new_ids, cb_state = d.GetSelectedIDs()
                if new_ids:
                    self.folder_id = new_ids[0]
                    self._UpdateFolderName()
        return 1

    def OnSlider(self, params):
        lParam = params[3]
        slider = self.GetDlgItem(IDC_SLIDER_HIGH)
        if slider.GetSafeHwnd() == lParam:
            idc_edit = IDC_EDIT_HIGH
        else:
            slider = self.GetDlgItem(IDC_SLIDER_LOW)
            assert slider.GetSafeHwnd() == lParam
            idc_edit = IDC_EDIT_LOW
        self.SetDlgItemText(idc_edit, "%.2f" % (slider.GetPos() / 100.0))
        
    def _InitSlider(self, idc_slider, idc_edit):
        slider = self.GetDlgItem(idc_slider)
        slider.SetRange(0, 100, 0)
        slider.SetLineSize(1)
        slider.SetPageSize(5)
        self._AdjustSliderToEdit(idc_slider, idc_edit)

    def _AdjustSliderToEdit(self, idc_slider, idc_edit):
        slider = self.GetDlgItem(idc_slider)
        edit = self.GetDlgItem(idc_edit)
        try:
            fval = float(edit.GetWindowText())
        except ValueError:
            return
        slider.SetPos(int(fval*100))

    def _CheckEdit(self, idc, rule, attr):
        try:
            val = float(self.GetDlgItemText(idc))
            if val < 0 or val > 1.0:
                raise ValueError
        except ValueError:
            self.MessageBox("Please enter a number between 0 and 1")
            self.GetDlgItem(idc).SetFocus()
            return False
        setattr(rule, attr, val)
        return True
        
    def OnOK(self):
        rule = self.rule
        if not self._CheckEdit(IDC_EDIT_HIGH, rule, "max") or \
           not self._CheckEdit(IDC_EDIT_LOW, rule, "min"):
            return 1
        combo = self.GetDlgItem(IDC_ACTION)
        rule.name = self.GetDlgItemText(IDC_RULE_NAME)
        rule.action = combo.GetLBText(combo.GetCurSel())
        rule.flag_message = self.GetDlgItem(IDC_FLAG).GetCheck()
        rule.write_field = self.GetDlgItem(IDC_WRITE_FIELD).GetCheck()
        rule.write_field_name = self.GetDlgItemText(IDC_FIELD_NAME)
        rule.folder_id = self.folder_id
        problem = rule.GetProblem(self.mgr)
        if problem is not None:
            self.MessageBox(problem)
            return 1
        return self._obj_.OnOK()
    def OnCancel(self):
        return self._obj_.OnCancel()

if __name__=='__main__':
    from win32com.client import Dispatch
    try:
        mapi = Dispatch("MAPI.Session")
        mapi.Logon()
    except pythoncom.com_error:
        mapi = None
    class Rule:
        def __init__(self):
            self.name = "My Rule"
            self.min = 0.1
            self.max = 0.9
            self.action = "Move"
            self.flag_message = True
            self.write_field = True
            self.write_field_name = "SpamProb"
            self.folder_id = ""
        def GetProblem(self, mgr):
            if self.min > self.max:
                return "max must be > min"

    class Manager: pass
    mgr = Manager()
    mgr.mapi = mapi
            

    rule = Rule()
    d = RuleDialog(rule, mgr)
    if d.DoModal() == win32con.IDOK:
        print "Name:", rule.name
        print "min,max:", rule.min, rule.max
        print "Action:", rule.action
        print "Write Field:", rule.write_field, ", to:", rule.write_field_name
        print "Flag message:", rule.flag_message

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

#these are the atom numbers defined by Windows for basic dialog controls
BUTTON    = 0x80
EDIT      = 0x81
STATIC    = 0x82
LISTBOX   = 0x83
SCROLLBAR = 0x84
COMBOBOX  = 0x85

IDC_STATIC_HAM = 1001
IDC_BROWSE_HAM = 1002
IDC_STATIC_SPAM = 1003
IDC_BROWSE_SPAM = 1004
from AsyncDialog import IDC_START, IDC_PROGRESS, IDC_PROGRESS_TEXT, AsyncDialogBase


class TrainingDialog(AsyncDialogBase):
    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
    ham_title = "Folders with known good messages"
    spam_title = "Folders with known spam or other junk messages"
    process_start_text = "&Train now"
    process_stop_text = "Stop &training"
    dt = [
        # Dialog itself.
        ["Training", (0, 0, 241, 118), style, None, (8, "MS Sans Serif")],
        # Children
        [STATIC,          ham_title,            -1,                   (  7,   6, 131,  11), cs ],
        [STATIC,          "",                   IDC_STATIC_HAM,       (  7,  17, 167,  12), cs | win32con.SS_SUNKEN | win32con.SS_LEFTNOWORDWRAP | win32con.SS_CENTERIMAGE],
        [BUTTON,          '&Browse',            IDC_BROWSE_HAM,       (184,  17,  50,  14), cs | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP],

        [STATIC,          spam_title,           -1,                   (  7,  36, 171,   9), cs ],
        [STATIC,          "",                   IDC_STATIC_SPAM,      (  7,  47, 167,  12), cs | win32con.SS_SUNKEN | win32con.SS_LEFTNOWORDWRAP | win32con.SS_CENTERIMAGE],
        [BUTTON,          'Brow&se',            IDC_BROWSE_SPAM,      (184,  47,  50,  14), cs | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP],

        [BUTTON,         process_start_text,    IDC_START,            (  7,  97,  50,  14), cs | win32con.BS_PUSHBUTTON | win32con.WS_TABSTOP],
        ["msctls_progress32", '',               IDC_PROGRESS,         (  7,  68, 166,  11), cs | win32con.WS_BORDER],
        [STATIC,          '',                   IDC_PROGRESS_TEXT,    (  7,  84, 227,  10), cs ],

        [BUTTON,          'Close',              win32con.IDOK,        (184,  97,  50,  14), cs | win32con.BS_DEFPUSHBUTTON | win32con.WS_TABSTOP],
        
    ]
    disable_while_running_ids = [IDC_BROWSE_HAM, IDC_BROWSE_SPAM, win32con.IDOK]

    def __init__ (self, mgr, trainer):
        self.mgr = mgr
        self.trainer = trainer
        self.config = mgr.config.training
        self.mapi = mgr.mapi
        AsyncDialogBase.__init__ (self, self.dt)

    def OnInitDialog(self):
        self.HookCommand(self.OnBrowse, IDC_BROWSE_SPAM)
        self.HookCommand(self.OnBrowse, IDC_BROWSE_HAM)
        self.UpdateStatus()
        return AsyncDialogBase.OnInitDialog (self)

    def UpdateStatus(self):
        names = []
        for eid in self.config.ham_folder_ids:
            try:
                name = self.mapi.GetFolder(eid).Name.encode("ascii", "replace")
            except pythoncom.com_error:
                name = "<unknown folder>"
            names.append(name)
        self.SetDlgItemText(IDC_STATIC_HAM, "; ".join(names))

        names = []
        for eid in self.config.spam_folder_ids:
            try:
                name = self.mapi.GetFolder(eid).Name.encode("ascii", "replace")
            except pythoncom.com_error:
                name = "<unknown folder>"
            names.append(name)
        self.SetDlgItemText(IDC_STATIC_SPAM, "; ".join(names))

    def OnBrowse(self, id, code):
        if code == win32con.BN_CLICKED:
            import FolderSelector
            if id==IDC_BROWSE_SPAM:
                l = self.config.spam_folder_ids
                sub_attr = "spam_include_sub"
            else:
                l = self.config.ham_folder_ids
                sub_attr = "ham_include_sub"
            include_sub = getattr(self.config, sub_attr)
            d = FolderSelector.FolderSelector(self.mapi, l, checkbox_state=include_sub)
            if d.DoModal()==win32con.IDOK:
                l[:], include_sub = d.GetSelectedIDs()[:]
                setattr(self.config, sub_attr, include_sub)
                self.UpdateStatus()

    def _DoProcess(self):
        self.mgr.WorkerThreadStarting()
        try:
            self.trainer(self.mgr, self.progress)
        finally:
            self.mgr.WorkerThreadEnding()
            
##if __name__=='__main__':
##    d=TrainingDialog(None)
##    d.DoModal()

--- NEW FILE: __init__.py ---
# This package defines dialog boxes used by the main 
# SpamBayes Outlook 2k integration code.