###############################################################################
# Name: elistctrl.py                                                          #
# Purpose: Base ListCtrl                                                      #
# Author: Cody Precord <cprecord@editra.org>                                  #
# Copyright: (c) 2010 Cody Precord <staff@editra.org>                         #
# License: wxWindows License                                                  #
###############################################################################

"""
Editra Control Library: EListCtrl

Class EBaseListCtrl:
Base Report mode ListCtrl class that highlights alternate rows

Class ECheckListCtrl:
Child class of L{EBaseListCtrl} that also provides CheckBoxes in the first
column of the control.

"""

__author__ = "Cody Precord <cprecord@editra.org>"
__svnid__ = "$Id: elistctrl.py 72221 2012-07-28 15:28:31Z CJP $"
__revision__ = "$Revision: 72221 $"

__all__ = ["EBaseListCtrl", "ECheckListCtrl", "EEditListCtrl", 
           "EToggleEditListCtrl"]

#--------------------------------------------------------------------------#
# Dependencies
import wx
import wx.lib.mixins.listctrl as listmix

# Local Imports
import elistmix

#--------------------------------------------------------------------------#

class EBaseListCtrl(elistmix.ListRowHighlighter,
                    listmix.ListCtrlAutoWidthMixin,
                    wx.ListCtrl):
    """Base listctrl class that provides automatic row highlighting"""
    def __init__(self, parent, _id=wx.ID_ANY,
                 pos=wx.DefaultPosition, size=wx.DefaultSize,
                 style=wx.LC_REPORT, validator=wx.DefaultValidator,
                 name="EListCtrl"):
        wx.ListCtrl.__init__(self, parent, _id, pos, size,
                             style, validator, name)
        elistmix.ListRowHighlighter.__init__(self)
        listmix.ListCtrlAutoWidthMixin.__init__(self)

    def EnableRow(self, idx, enable=True):
        """Enable/Disable a row in the ListCtrl
        @param idx: row index
        @keyword enable: bool

        """
        state = 0
        txtcolour = wx.SYS_COLOUR_LISTBOXTEXT
        if not enable:
            state = wx.LIST_STATE_DISABLED
            txtcolour = wx.SYS_COLOUR_GRAYTEXT
        self.SetItemState(idx, state, wx.LIST_STATE_DONTCARE)
        colour = wx.SystemSettings.GetColour(txtcolour)
        self.SetItemTextColour(idx, colour)

    def GetRowData(self, idx):
        """Get the values from each cell in the given row
        @param idx: row index
        @return: tuple

        """
        data = list()
        if idx >= 0 and idx < self.GetItemCount():
            for col in range(self.GetColumnCount()):
                item = self.GetItem(idx, col)
                data.append(item.Text)
        return tuple(data)

    def GetSelections(self):
        """Get a list of all the selected items in the list
        @return: list of ints

        """
        items = [ idx for idx in range(self.GetItemCount())
                  if self.IsSelected(idx) ]
        return items

    def HasSelection(self):
        """Are any items selected in the list"""
        return bool(len(self.GetSelections()))

class ECheckListCtrl(listmix.CheckListCtrlMixin,
                     EBaseListCtrl):
     """ListCtrl with CheckBoxes in the first column"""
     def __init__(self, *args, **kwargs):
         EBaseListCtrl.__init__(self, *args, **kwargs)
         listmix.CheckListCtrlMixin.__init__(self)

class EEditListCtrl(listmix.TextEditMixin,
                    EBaseListCtrl):
    """ListCtrl with Editable cells"""
    def __init__(self, *args, **kwargs):
        EBaseListCtrl.__init__(self, *args, **kwargs)
        listmix.TextEditMixin.__init__(self)

    def OpenEditor(self, col, row):
        """Work around limitation of TextEditMixin on Linux
        where if the horizontal scroll bar is present it is not
        possible to open the editor.
        @param col: column to open editor at
        @param row: row to pen editor at

        """
        # give the derived class a chance to Allow/Veto this edit.
        evt = wx.ListEvent(wx.wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, self.Id)
        evt.m_itemIndex = row
        evt.m_col = col
        item = self.GetItem(row, col)
        evt.m_item.SetId(item.GetId()) 
        evt.m_item.SetColumn(item.GetColumn()) 
        evt.m_item.SetData(item.GetData()) 
        evt.m_item.SetText(item.GetText()) 
        ret = self.GetEventHandler().ProcessEvent(evt)
        if ret and not evt.IsAllowed():
            return   # user code doesn't allow the edit.

        if self.GetColumn(col).m_format != self.col_style:
            self.make_editor(self.GetColumn(col).m_format)
    
        x0 = self.col_locs[col]
        x1 = self.col_locs[col+1] - x0

        scrolloffset = self.GetScrollPos(wx.HORIZONTAL)

        # scroll forward
        if wx.Platform == "__WXMSW__" and x0+x1-scrolloffset > self.GetSize()[0]:
            # don't start scrolling unless we really need to
            offset = x0+x1-self.GetSize()[0]-scrolloffset
            # scroll a bit more than what is minimum required
            # so we don't have to scroll everytime the user presses TAB
            # which is very tireing to the eye
            addoffset = self.GetSize()[0]/4
            # but be careful at the end of the list
            if addoffset + scrolloffset < self.GetSize()[0]:
                offset += addoffset

            self.ScrollList(offset, 0)
            scrolloffset = self.GetScrollPos(wx.HORIZONTAL)

        y0 = self.GetItemRect(row)[1]
        
        editor = self.editor
        editor.SetDimensions(x0-scrolloffset,y0, x1,-1)
        
        editor.SetValue(self.GetItem(row, col).GetText()) 
        editor.Show()
        editor.Raise()
        editor.SetSelection(-1,-1)
        editor.SetFocus()
    
        self.curRow = row
        self.curCol = col

class EToggleEditListCtrl(listmix.CheckListCtrlMixin,
                          listmix.TextEditMixin,
                          EBaseListCtrl):
    """ListCtrl with Editable cells and images that can be toggled in the
    the first column.

    """
    def __init__(self, *args, **kwargs):
        EBaseListCtrl.__init__(self, *args, **kwargs)
        listmix.TextEditMixin.__init__(self)
        listmix.CheckListCtrlMixin.__init__(self)
        self.Unbind(wx.EVT_LEFT_DCLICK)

    def GetCheckedItems(self):
        """Get the list of checked indexes"""
        count = self.GetItemCount()
        return [item for item in range(count) if self.IsChecked(item)]

    def SetCheckedBitmap(self, bmp):
        """Set the bitmap to use for the Checked state
        @param bmp: wx.Bitmap

        """
        assert isinstance(bmp, wx.Bitmap) and bmp.IsOk()
        imgl = self.GetImageList(wx.IMAGE_LIST_SMALL)
        imgl.Replace(self.check_image, bmp)

    def SetUnCheckedBitmap(self, bmp):
        """Set the bitmap to use for the un-Checked state
        @param bmp: wx.Bitmap

        """
        assert isinstance(bmp, wx.Bitmap) and bmp.IsOk()
        imgl = self.GetImageList(wx.IMAGE_LIST_SMALL)
        imgl.Replace(self.uncheck_image, bmp)
