'''
 ====================================================================
 Copyright ( c ) 2003-2006 Barry A Scott.  All rights reserved.

 This software is licensed as described in the file LICENSE.txt,
 which you should have received as part of this distribution.

 ====================================================================

    wb_preferences_dialog.py

'''
import wx
import wb_exceptions
import os
import wb_subversion_list_handler_common
import wb_shell_commands

class PreferencesDialog( wx.Dialog ):
    def __init__( self, parent, app ):
        wx.Dialog.__init__( self, parent, -1, 'Preferences', size=(400,200) )
        self.app = app
        self.v_sizer = None

        # useful for debugging new pages
        try:
            self.initControls()
        except:
            app.log.exception('PreferencesDialog')
        self.SetAutoLayout( True )
        self.SetSizer( self.v_sizer )
        self.v_sizer.Fit( self )
        self.Layout()

        self.CentreOnParent()


    def initControls( self ):
        self.v_sizer = wx.BoxSizer( wx.VERTICAL )

        self.notebook = wx.Notebook( self, -1, size = (400, 200) )

        self.v_sizer.Add( self.notebook, 0, wx.EXPAND|wx.ALL, 5 )

        self.pages = []
        self.pages.append( EditorPage( self.notebook, self.app ) )
        self.pages.append( DiffToolPage( self.notebook, self.app ) )
        self.pages.append( ShellPage( self.notebook, self.app ) )
        self.pages.append( ListColumnsPage( self.notebook, self.app ) )
        # may want view page for editing the control file
        #self.pages.append( ViewPage( self.notebook, self.app ) )

        self.notebook.SetAutoLayout( True )
        self.notebook.Layout()

        self.button_ok = wx.Button( self, wx.ID_OK, ' OK ' )
        self.button_ok.SetDefault()
        self.button_cancel = wx.Button( self, wx.ID_CANCEL, ' Cancel ' )

        self.h_sizer = wx.BoxSizer( wx.HORIZONTAL )
        self.h_sizer.Add( (1, 1), 1, wx.EXPAND )
        self.h_sizer.Add( self.button_ok, 0, wx.EXPAND|wx.EAST, 15 )
        self.h_sizer.Add( self.button_cancel, 0, wx.EXPAND|wx.EAST, 2 )

        self.v_sizer.Add( self.h_sizer, 0, wx.EXPAND|wx.ALL, 5 )

        wx.EVT_BUTTON( self, wx.ID_OK, self.OnOk )
        wx.EVT_BUTTON( self, wx.ID_CANCEL, self.OnCancel )

    def OnOk( self, event ):
        for page in self.pages:
            if not page.validate():
                return

        for page in self.pages:
            page.savePreferences()

        self.EndModal( wx.ID_OK )

    def OnCancel( self, event ):
        self.EndModal( wx.ID_CANCEL )
    

class PagePanel(wx.Panel):
    def __init__( self, notebook, title ):
        wx.Panel.__init__( self, notebook, -1, style = wx.NO_BORDER )

        self.page_v_sizer = wx.BoxSizer( wx.VERTICAL )
        self.page_v_sizer.Add( self.initControls(), 0, wx.EXPAND|wx.ALL, 5 )
        self.SetSizer( self.page_v_sizer )
        self.SetAutoLayout( True )
        self.page_v_sizer.Fit( self )
        self.Layout()

        notebook.AddPage( self, title )

    def initControls( self ):
        raise wb_exceptions.InternalError('must override initControls')

class EditorPage(PagePanel):
    def __init__( self, notebook, app ):
        self.app = app
        PagePanel.__init__( self, notebook, 'Editor' )

    def initControls( self ):
        p = self.app.prefs.getEditor()

        self.static_text1 = wx.StaticText( self, -1, 'Editor: ', style=wx.ALIGN_RIGHT)
        self.text_ctrl_editor = wx.TextCtrl( self, -1, p.editor_image, wx.DefaultPosition, wx.Size(415, -1) )

        self.static_text2 = wx.StaticText( self, -1, 'Edit Arguments: ', style=wx.ALIGN_RIGHT)
        self.text_ctrl_edit_arg = wx.TextCtrl( self, -1, p.editor_options, wx.DefaultPosition, wx.Size(315, -1) )

        self.browse_button = wx.Button( self, -1, ' Browse... ')

        self.grid_sizer = wx.FlexGridSizer( 0, 3, 0, 0 )
        self.grid_sizer.AddGrowableCol( 1 )

        self.grid_sizer.Add( self.static_text1, 1, wx.EXPAND|wx.ALL, 3 )
        self.grid_sizer.Add( self.text_ctrl_editor, 0, wx.EXPAND|wx.ALL, 5 )
        self.grid_sizer.Add( self.browse_button, 0, wx.EXPAND )

        self.grid_sizer.Add( self.static_text2, 1, wx.EXPAND|wx.ALL, 3 )
        self.grid_sizer.Add( self.text_ctrl_edit_arg, 0, wx.EXPAND|wx.ALL, 5 )
        self.grid_sizer.Add( (1, 1), 0, wx.EXPAND )

        wx.EVT_BUTTON( self, self.browse_button.GetId(), self.OnBrowseExe )

        return self.grid_sizer

    def savePreferences( self ):
        p = self.app.prefs.getEditor()

        p.editor_image = self.text_ctrl_editor.GetValue()
        p.editor_options = self.text_ctrl_edit_arg.GetValue()


    def OnBrowseExe( self, event ):
        if wx.Platform == '__WXMSW__':
            file_type = 'Executable files (*.exe)|*.exe'
        elif wx.Platform == '__WXMAC__':
            file_type = 'Applications|*.app|Executable files|*'
        else:
            file_type = 'Executable files|*'

        filename = self.text_ctrl_editor.GetValue()
        file_dialog = wx.FileDialog( 
            self,
            'Choose an Executable file',
            os.path.dirname( filename ),
            os.path.basename( filename ),
            file_type,
            wx.OPEN )

        if file_dialog.ShowModal() == wx.ID_OK:
            self.text_ctrl_editor.SetValue( file_dialog.GetPath() )

        file_dialog.Destroy()

    def validate( self ):
        # allow no editor
        if len(self.text_ctrl_editor.GetValue()) == 0:
            return True

        # otherwise it must exist
        valid = False
        if wx.Platform == '__WXMAC__':
            valid = (os.access( self.text_ctrl_editor.GetValue(), os.X_OK )
                or not os.path.isdir( self.text_ctrl_editor.GetValue() ) )
        elif wx.Platform == '__WXMSW__':
            valid = (os.path.exists( self.text_ctrl_editor.GetValue() )
                or not os.path.isdir( self.text_ctrl_editor.GetValue() ) )
        else:
            valid = (os.access( self.text_ctrl_editor.GetValue(), os.X_OK )
                or not os.path.isdir( self.text_ctrl_editor.GetValue() ) )

        if not valid:
            wx.MessageBox(
                'You must enter a valid editor executable',
                'Warning',
                wx.OK | wx.ICON_EXCLAMATION,
                self )
            return False

        return True


class DiffToolPage(PagePanel):
    def __init__( self, notebook, app ):
        self.app = app
        PagePanel.__init__( self, notebook, 'Diff Tool' )

    def initControls( self ):
        p = self.app.prefs.getDiffTool()

        
        self.mode_values = ['built-in', 'external-gui-diff', 'external-shell-diff', 'svn-diff']
        self.diff_tools = {'built-in': '', 'external-gui-diff': p.gui_diff_tool, 'external-shell-diff': p.shell_diff_tool, 'svn-diff': ''}
        self.options = {'built-in': '', 'external-gui-diff': p.gui_diff_tool_options, 'external-shell-diff': p.shell_diff_tool_options, 'svn-diff': ''}
        self.mode_choice_values = ['Work Bench Diff', 'External GUI Diff Command', 'External Text Diff', 'svn diff']
        self.mode_choice = wx.Choice( self, -1, choices = self.mode_choice_values )
        if p.diff_tool_mode not in self.mode_values:
            p.diff_tool_mode = 'built-in'
        self.mode = p.diff_tool_mode
        self.mode_choice.SetSelection( self.mode_values.index( p.diff_tool_mode ) )
        self.text_ctrl_diff_tool = wx.TextCtrl( self, -1, self.diff_tools[self.mode], wx.DefaultPosition, wx.Size(415, -1) )
        self.text_ctrl_options = wx.TextCtrl( self, -1, self.options[self.mode], wx.DefaultPosition, wx.Size(315, -1) )

        self.browse_button = wx.Button( self, -1, ' Browse... ')

        self.grid_sizer = wx.FlexGridSizer( 0, 3, 0, 0 )
        self.grid_sizer.AddGrowableCol( 1 )

        self.grid_sizer.Add( wx.StaticText( self, -1, 'Mode: ', style=wx.ALIGN_RIGHT), 1, wx.EXPAND|wx.ALL, 3 )
        self.grid_sizer.Add( self.mode_choice, 0, wx.ALIGN_LEFT, 5 )
        self.grid_sizer.Add( (1, 1), 0, wx.EXPAND )
        
        self.grid_sizer.Add( wx.StaticText( self, -1, 'Diff Tool: ', style=wx.ALIGN_RIGHT), 1, wx.EXPAND|wx.ALL, 3 )
        self.grid_sizer.Add( self.text_ctrl_diff_tool, 0, wx.EXPAND|wx.ALL, 5 )
        self.grid_sizer.Add( self.browse_button, 0, wx.EXPAND )

        self.grid_sizer.Add( wx.StaticText( self, -1, 'Tool Arguments: ', style=wx.ALIGN_RIGHT), 1, wx.EXPAND|wx.ALL, 3 )
        self.grid_sizer.Add( self.text_ctrl_options, 0, wx.EXPAND|wx.ALL, 5 )
        self.grid_sizer.Add( (1, 1), 0, wx.EXPAND )

        self.grid_sizer.Add( wx.StaticText( self, -1, 'Use', style=wx.ALIGN_RIGHT), 1, wx.EXPAND|wx.ALL, 3 )
        self.grid_sizer.Add( wx.StaticText( self, -1, '%nl for left file name, %nr for right file name,\n%tl for left title, %tr for right title',
                                           style=wx.ALIGN_LEFT), 1, wx.EXPAND|wx.ALL, 3 )
        self.grid_sizer.Add( (1, 1), 0, wx.EXPAND )
        
        self.OnModeChange( None )

        wx.EVT_CHOICE( self, self.mode_choice.GetId(), self.OnModeChange )
        wx.EVT_BUTTON( self, self.browse_button.GetId(), self.OnBrowseExe )

        return self.grid_sizer

    def savePreferences( self ):
        self.OnModeChange( None )
        p = self.app.prefs.getDiffTool()
        p.diff_tool_mode = self.mode
        p.gui_diff_tool = self.diff_tools['external-gui-diff']
        p.shell_diff_tool = self.diff_tools['external-shell-diff']
        p.gui_diff_tool_options = self.options['external-gui-diff']
        p.shell_diff_tool_options = self.options['external-shell-diff']

    def OnModeChange( self, event ):
       self.diff_tools[self.mode] = self.text_ctrl_diff_tool.GetValue()
       self.options[self.mode] = self.text_ctrl_options.GetValue()
       self.mode = self.mode_values[self.mode_choice.GetSelection()]
       self.text_ctrl_diff_tool.SetValue( self.diff_tools[self.mode] )
       self.text_ctrl_options.SetValue( self.options[self.mode] )
       external_command = self.mode in ('external-gui-diff', 'external-shell-diff')
       self.text_ctrl_diff_tool.Enable( external_command )
       self.browse_button.Enable( external_command )
       self.text_ctrl_options.Enable( external_command )

    def OnBrowseExe( self, event ):
        if wx.Platform == '__WXMSW__':
            file_type = 'Executable files (*.exe)|*.exe'
        elif wx.Platform == '__WXMAC__':
            file_type = 'Applications|*.app|Executable files|*'
        else:
            file_type = 'Executable files|*'

        filename = self.text_ctrl_diff_tool.GetValue()
        file_dialog = wx.FileDialog(
            self,
            'Choose an Executable file',
            os.path.dirname( filename ),
            os.path.basename( filename ),
            file_type,
            wx.OPEN )

        if file_dialog.ShowModal() == wx.ID_OK:
            self.text_ctrl_diff_tool.SetValue( file_dialog.GetPath() )

        file_dialog.Destroy()

    def validate( self ):
        return True

class ShellPage(PagePanel):
    def __init__( self, notebook, app ):
        self.app = app
        PagePanel.__init__( self, notebook, 'Shell' )

    def initControls( self ):
        p = self.app.prefs.getShell()

        self.static_text1 = wx.StaticText( self, -1, 'Terminal Init Command: ', style=wx.ALIGN_RIGHT)
        self.text_ctrl_shell_init_command = wx.TextCtrl( self, -1, p.shell_init_command, wx.DefaultPosition, wx.Size(300, -1) )

        self.grid_sizer = wx.FlexGridSizer( 0, 2, 0, 0 )
        self.grid_sizer.AddGrowableCol( 1 )

        terminal_program_list = wb_shell_commands.getTerminalProgramList()
        if len(terminal_program_list) > 0:
            self.static_text2 = wx.StaticText( self, -1, 'Terminal Program: ', style=wx.ALIGN_RIGHT)
            self.terminal_program_list_ctrl = wx.Choice( self, -1, choices=terminal_program_list, size=(150,-1) )
            if p.shell_terminal in terminal_program_list:
                self.terminal_program_list_ctrl.SetStringSelection( p.shell_terminal )
            else:
                self.terminal_program_list_ctrl.SetStringSelection( terminal_program_list[0] )
            self.grid_sizer.Add( self.static_text2, 1, wx.EXPAND|wx.ALL, 3 )
            self.grid_sizer.Add( self.terminal_program_list_ctrl, 0, wx.EXPAND|wx.ALL, 3 )
        else:
            self.terminal_program_list_ctrl = None

        self.grid_sizer.Add( self.static_text1, 1, wx.EXPAND|wx.ALL, 3 )
        self.grid_sizer.Add( self.text_ctrl_shell_init_command, 0, wx.EXPAND|wx.ALL, 3 )

        file_browser_program_list = wb_shell_commands.getFileBrowserProgramList()

        if len(file_browser_program_list) > 0:
            self.static_text3 = wx.StaticText( self, -1, 'File Brower Program: ', style=wx.ALIGN_RIGHT)
            self.file_browser_program_list_ctrl = wx.Choice( self, -1, choices=file_browser_program_list, size=(150,-1) )
            if p.shell_file_browser in file_browser_program_list:
                self.file_browser_program_list_ctrl.SetStringSelection( p.shell_file_browser )
            else:
                self.file_browser_program_list_ctrl.SetStringSelection( file_browser_program_list[0] )
            self.grid_sizer.Add( self.static_text3, 1, wx.EXPAND|wx.ALL, 3 )
            self.grid_sizer.Add( self.file_browser_program_list_ctrl, 0, wx.EXPAND|wx.ALL, 3 )
        else:
            self.file_browser_program_list_ctrl = None

        self.grid_sizer.Add( (1, 1), 0, wx.EXPAND )

        return self.grid_sizer

    def savePreferences( self ):
        p = self.app.prefs.getShell()

        p.shell_init_command = self.text_ctrl_shell_init_command.GetValue().encode('UTF-8')
        if self.file_browser_program_list_ctrl is not None:
            p.shell_file_browser = self.file_browser_program_list_ctrl.GetStringSelection().encode('UTF-8')
        if self.terminal_program_list_ctrl is not None:
            p.shell_terminal = self.terminal_program_list_ctrl.GetStringSelection().encode('UTF-8')

    def validate( self ):
        return True

class ViewPage(PagePanel):
    id_add = wx.NewId()
    id_del = wx.NewId()
    id_filename_list = wx.NewId()
    id_pattern_text = wx.NewId()

    def __init__( self, notebook, app ):
        self.app = app
        PagePanel.__init__( self, notebook, 'View' )
        self.selected_item = None

    def initControls( self ):
        p = self.app.prefs.getView()

        self.filename_list = wx.ListCtrl( self, ViewPage.id_filename_list, wx.DefaultPosition,
                wx.Size( -1, 100 ), wx.LC_REPORT )
        self.filename_list.InsertColumn( 0, 'Exclude filename' )
        self.filename_list.SetColumnWidth( 0, 400 )

        for index, filename in enumerate( p.excluded_filenames_list ):
            self.filename_list.InsertStringItem( index, filename )

        self.button_add = wx.Button( self, ViewPage.id_add, ' Add ' )
        self.button_add.Enable( False )
        self.button_del = wx.Button( self, ViewPage.id_del, ' Delete ' )
        self.button_del.Enable( False )
        self.pattern_text_ctrl = wx.TextCtrl( self, ViewPage.id_pattern_text, '',
                wx.DefaultPosition, wx.Size(200, -1), style=wx.TE_PROCESS_ENTER )

        self.h_sizer = wx.BoxSizer( wx.HORIZONTAL )
        self.h_sizer.Add( self.button_add, 0, wx.EXPAND|wx.EAST, 15 )
        self.h_sizer.Add( self.pattern_text_ctrl, 0, wx.EXPAND|wx.EAST, 5 )
        self.h_sizer.Add( self.button_del, 0, wx.EXPAND|wx.EAST, 5 )

        self.v_sizer = wx.BoxSizer( wx.VERTICAL )
        self.v_sizer.Add( self.filename_list, 0, wx.EXPAND|wx.EAST, 5 )
        self.v_sizer.Add( self.h_sizer, 0, wx.EXPAND|wx.EAST, 5 )

        wx.EVT_TEXT( self, ViewPage.id_pattern_text, self.OnPatternTextChanged )
        wx.EVT_TEXT_ENTER( self, ViewPage.id_pattern_text, self.OnPatternTextEnter )

        wx.EVT_BUTTON( self, ViewPage.id_add, self.OnAdd )
        wx.EVT_BUTTON( self, ViewPage.id_del, self.OnDel )

        wx.EVT_LIST_ITEM_SELECTED( self, ViewPage.id_filename_list, self.OnPatternSelected )
        wx.EVT_LIST_ITEM_DESELECTED( self, ViewPage.id_filename_list, self.OnPatternDeselected )

        return self.v_sizer

    def sortList( self, item1, item2 ):
        return cmp( self.filename_list.GetItemText( item1 ),
                self.filename_list.GetItemText( item2 ) )

    def OnAdd( self, event ):
        pattern = self.pattern_text_ctrl.GetValue()
        if self.selected_item is None:
            self.filename_list.InsertStringItem( 0, pattern )
        else:
            self.filename_list.SetItemText( self.selected_item, pattern )
        
        self.filename_list.SortItems( self.sortList )

        self.button_add.Enable( False )

    def OnDel( self, event ):
        if self.selected_item is not None:
            self.filename_list.DeleteItem(self.selected_item )

        self.selected_item = None
        self.button_del.Enable( False )

    def OnPatternTextEnter( self, event ):
        if self.button_add.IsEnabled():
            self.OnAdd( None )

    def OnPatternTextChanged( self, event ):
        new_pattern = self.pattern_text_ctrl.GetValue()
        if len(new_pattern) == 0:
            self.button_add.Enable( False )
            return

        # enable the add button if the text is not in the list already
        for index in range( self.filename_list.GetItemCount() ):
            pattern = self.filename_list.GetItemText( index )
            if pattern == new_pattern:
                self.button_add.Enable( False )
                return

        self.button_add.Enable( True )

    def OnPatternSelected( self, event ):
        self.selected_item = event.m_itemIndex

        # put the selected text into the pattern ctrl
        pattern = self.filename_list.GetItemText( event.m_itemIndex )
        self.pattern_text_ctrl.SetValue( pattern )
        self.pattern_text_ctrl.SetSelection( -1, -1 )

        # Enable the delete button
        self.button_del.Enable( True )

    def OnPatternDeselected( self, event ):
        self.selected_item = None

        # Disable the delete button
        self.button_del.Enable( False )

    def savePreferences( self ):
        p = self.app.prefs.getView()

        filename_list = []

        for index in range( self.filename_list.GetItemCount() ):
            filename_list.append( self.filename_list.GetItemText( index ).encode('UTF-8') )

        p.excluded_filenames_list = filename_list

    def validate( self ):
        return True


class ListColumnsPage(PagePanel):
    id_exclude = wx.NewId()
    id_include = wx.NewId()
    id_move_up = wx.NewId()
    id_move_down = wx.NewId()
    id_excluded_list = wx.NewId()
    id_included_list = wx.NewId()
    id_width = wx.NewId()

    def __init__( self, notebook, app ):
        self.app = app
        self.selected_name = None
        self.column_info = wb_subversion_list_handler_common.ViewColumnInfo()
        PagePanel.__init__( self, notebook, 'Columns' )

    def initControls( self ):
        p = self.app.prefs.getView()
        self.column_info.setFromPreferenceData( p )

        self.excluded_list = wx.ListCtrl( self, ListColumnsPage.id_excluded_list, wx.DefaultPosition,
                wx.Size( 200, 100 ), wx.LC_REPORT )
        self.excluded_list.InsertColumn( 0, 'Column' )
        self.excluded_list.SetColumnWidth( 0, 100 )
        self.excluded_list.InsertColumn( 1, 'Width', wx.LIST_FORMAT_RIGHT )
        self.excluded_list.SetColumnWidth( 1, 80 )

        self.included_list = wx.ListCtrl( self, ListColumnsPage.id_included_list, wx.DefaultPosition,
                wx.Size( 200, 100 ), wx.LC_REPORT )
        self.included_list.InsertColumn( 0, 'Column' )
        self.included_list.SetColumnWidth( 0, 100 )
        self.included_list.InsertColumn( 1, 'Width', wx.LIST_FORMAT_RIGHT )
        self.included_list.SetColumnWidth( 1, 80 )

        for name in self.column_info.getColumnOrder():
            info = self.column_info.getInfo( name )
            info.included =  True
            index = self.included_list.GetItemCount()

            self.included_list.InsertStringItem( index, info.name )
            self.included_list.SetStringItem( index, 1, str(info.width) )
    
        for info in self.column_info.excludedInfo():
            index = self.excluded_list.GetItemCount()

            self.excluded_list.InsertStringItem( index, info.name )
            self.excluded_list.SetStringItem( index, 1, str(info.width) )


        self.button_include = wx.Button( self, ListColumnsPage.id_include, ' Include --> ' )
        self.button_include.Enable( False )
        self.button_exclude = wx.Button( self, ListColumnsPage.id_exclude, ' <-- Exclude ' )
        self.button_exclude.Enable( False )

        self.button_up = wx.Button( self, ListColumnsPage.id_move_up, ' Move Up ' )
        self.button_up.Enable( False )
        self.button_down = wx.Button( self, ListColumnsPage.id_move_down, ' Move Down ' )
        self.button_down.Enable( False )

        self.width_text_ctrl = wx.TextCtrl( self, ListColumnsPage.id_width, '',
                wx.DefaultPosition, wx.Size(200, -1), style=wx.TE_PROCESS_ENTER|wx.TE_RIGHT  )

        self.v_sizer = wx.BoxSizer( wx.VERTICAL )
        self.v_sizer.Add( self.button_include, 0, wx.EXPAND|wx.EAST, 5 )
        self.v_sizer.Add( self.button_exclude, 0, wx.EXPAND|wx.EAST, 5 )
        self.v_sizer.Add( self.width_text_ctrl, 0, wx.EXPAND|wx.EAST, 5 )
        self.v_sizer.Add( self.button_up, 0, wx.EXPAND|wx.EAST, 5 )
        self.v_sizer.Add( self.button_down, 0, wx.EXPAND|wx.EAST, 5 )

        self.h_sizer = wx.BoxSizer( wx.HORIZONTAL )
        self.h_sizer.Add( self.excluded_list, 0, wx.EXPAND|wx.WEST, 5 )
        self.h_sizer.Add( self.v_sizer, 0, wx.EXPAND|wx.EAST, 5 )
        self.h_sizer.Add( self.included_list, 0, wx.EXPAND|wx.EAST, 5 )

        wx.EVT_BUTTON( self, ListColumnsPage.id_include, self.OnInclude )
        wx.EVT_BUTTON( self, ListColumnsPage.id_exclude, self.OnExclude )
        wx.EVT_BUTTON( self, ListColumnsPage.id_move_up, self.OnMoveUp )
        wx.EVT_BUTTON( self, ListColumnsPage.id_move_down, self.OnMoveDown )

        wx.EVT_TEXT_ENTER( self, ListColumnsPage.id_width, self.OnWidthTextEnter )

        wx.EVT_LIST_ITEM_SELECTED( self, ListColumnsPage.id_excluded_list, self.OnExcludeSelected )
        wx.EVT_LIST_ITEM_DESELECTED( self, ListColumnsPage.id_excluded_list, self.OnExcludeDeselected )

        wx.EVT_LIST_ITEM_SELECTED( self, ListColumnsPage.id_included_list, self.OnIncludeSelected )
        wx.EVT_LIST_ITEM_DESELECTED( self, ListColumnsPage.id_included_list, self.OnIncludeDeselected )

        return self.h_sizer

    def OnInclude( self, event ):
        self.changeInclusionColumn( True, self.excluded_list, self.included_list )

    def OnExclude( self, event ):
        self.changeInclusionColumn( False, self.included_list, self.excluded_list )

    def changeInclusionColumn( self, include, from_list, to_list ):
        info = self.column_info.getInfo( self.selected_name )

        try:
            width = int(self.width_text_ctrl.GetValue())
        except ValueError:
            wx.MessageBox( 'Width for %s must be an number between %d and %d' %
                        (info.name, info.min_width, info.max_width),
                'Warning',
                wx.OK | wx.ICON_EXCLAMATION,
                self )
            return

        if( width >= info.min_width
        and width <= info.max_width ):
            info.width = width
        else:
            wx.MessageBox( 'Width for %s must be between %d and %d' %
                        (info.name, info.min_width, info.max_width),
                'Warning',
                wx.OK | wx.ICON_EXCLAMATION,
                self )
            return

        info.include = include

        # remove from from_list
        from_index = from_list.FindItem( -1, info.name )
        from_list.DeleteItem( from_index )

        # add to end of to_list
        index = to_list.GetItemCount()

        to_list.InsertStringItem( index, info.name )
        to_list.SetStringItem( index, 1, str(info.width) )

    def OnMoveUp( self, event ):
        self.moveColumn( -1 )

    def OnMoveDown( self, event ):
        self.moveColumn( 1 )

    def moveColumn( self, direction ):
        info = self.column_info.getInfo( self.selected_name )

        index = self.included_list.FindItem( -1, self.selected_name )

        self.included_list.DeleteItem( index )
        index += direction
        self.included_list.InsertStringItem( index, info.name )
        self.included_list.SetStringItem( index, 1, str( info.width ) )
        self.included_list.SetItemState( index, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED )

        # enable up and down if not at the ends
        item_count = self.included_list.GetItemCount()
        self.button_up.Enable( item_count > 1 and index != 0 )
        self.button_down.Enable( item_count > 1 and index != (item_count-1) )


    def OnWidthTextEnter( self, event ):
        info = self.column_info.getInfo( self.selected_name )
        try:
            width = int(self.width_text_ctrl.GetValue())
        except ValueError:
            wx.MessageBox( 'Width for %s must be an number between %d and %d' %
                        (info.name, info.min_width, info.max_width),
                'Warning',
                wx.OK | wx.ICON_EXCLAMATION,
                self )
            return

        if( width >= info.min_width
        and width <= info.max_width ):
            info.width = width
            index = self.included_list.FindItem( -1, info.name )
            self.included_list.SetStringItem( index, 1, str(width) )
        else:
            wx.MessageBox( 'Width for %s must be between %d and %d' %
                        (info.name, info.min_width, info.max_width),
                'Warning',
                wx.OK | wx.ICON_EXCLAMATION,
                self )
        

    def OnExcludeSelected( self, event ):
        self.button_up.Enable( False )
        self.button_down.Enable( False )
        self.button_include.Enable( True )

        self.selected_name = self.excluded_list.GetItemText( event.m_itemIndex )
        info = self.column_info.getInfo( self.selected_name )
        self.width_text_ctrl.SetValue( str(info.width) )
        self.width_text_ctrl.Enable( True )

    def OnExcludeDeselected( self, event ):
        self.button_include.Enable( False )
        self.width_text_ctrl.Enable( False )

    def OnIncludeSelected( self, event ):
        self.button_exclude.Enable( True )
        self.button_include.Enable( False )

        # enable up and down if no at the ends
        item_count = self.included_list.GetItemCount()
        self.button_up.Enable( item_count > 1 and event.m_itemIndex != 0 )
        self.button_down.Enable( item_count > 1 and event.m_itemIndex != (item_count-1) )

        self.selected_name = self.included_list.GetItemText( event.m_itemIndex )
        info = self.column_info.getInfo( self.selected_name )
        self.width_text_ctrl.SetValue( str(info.width) )
        self.width_text_ctrl.Enable( True )

    def OnIncludeDeselected( self, event ):
        self.button_exclude.Enable( False )
        self.width_text_ctrl.Enable( False )

    def savePreferences( self ):
        p = self.app.prefs.getView()
        column_order = []
        for index in range( self.included_list.GetItemCount() ):
            name = self.included_list.GetItemText( index )
            column_order.append( name )

        self.column_info.setColumnOrder( column_order )
        p.column_order = self.column_info.getColumnOrder()
        p.column_widths = self.column_info.getColumnWidths()

    def validate( self ):
        if self.included_list.FindItem( -1, 'Name' ) < 0:
            wx.MessageBox( 'You must include the Name column',
                'Warning',
                wx.OK | wx.ICON_EXCLAMATION,
                self )
            return False

        return True
