X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/30aaddfe894a409879598e2a4077932b2e14aac5..68bc8549d81adc1b6f031bdbb03b91a71944197c:/wxPython/wxPython/lib/mixins/listctrl.py diff --git a/wxPython/wxPython/lib/mixins/listctrl.py b/wxPython/wxPython/lib/mixins/listctrl.py index e31a871cbc..db3c5d658a 100644 --- a/wxPython/wxPython/lib/mixins/listctrl.py +++ b/wxPython/wxPython/lib/mixins/listctrl.py @@ -17,7 +17,7 @@ from wxPython.wx import * class wxColumnSorterMixin: """ A mixin class that handles sorting of a wxListCtrl in REPORT mode when - the coilumn header is clicked on. + the column header is clicked on. There are a few requirments needed in order for this to work genericly: @@ -34,57 +34,229 @@ class wxColumnSorterMixin: objects representing the values in each column. These values are compared in the column sorter to determine sort order. + Interesting methods to override are GetColumnSorter, + GetSecondarySortValues, and GetSortImages. See below for details. """ + def __init__(self, numColumns): self._colSortFlag = [0] * numColumns - self._col = 0 - self._colSortFlag[self._col] = 1 + self._col = -1 list = self.GetListCtrl() if not list: raise ValueError, "No wxListCtrl available" - EVT_LIST_COL_CLICK(list, list.GetId(), self.OnColClick) + EVT_LIST_COL_CLICK(list, list.GetId(), self.__OnColClick) def SortListItems(self, col=-1, ascending=1): """Sort the list on demand. Can also be used to set the sort column and order.""" + oldCol = self._col if col != -1: self._col = col self._colSortFlag[col] = ascending - self.GetListCtrl().SortItems(self.ColumnSorter) + self.GetListCtrl().SortItems(self.GetColumnSorter()) + self.__updateImages(oldCol) + + + def GetColumnWidths(self): + """ + Returns a list of column widths. Can be used to help restore the current + view later. + """ + list = self.GetListCtrl() + rv = [] + for x in range(len(self._colSortFlag)): + rv.append(list.GetColumnWidth(x)) + return rv + + + def GetSortImages(self): + """ + Returns a tuple of image list indexesthe indexes in the image list for an image to be put on the column + header when sorting in descending order. + """ + return (-1, -1) # (decending, ascending) image IDs + + + def GetColumnSorter(self): + """Returns a callable object to be used for comparing column values when sorting.""" + return self.__ColumnSorter + + def GetSecondarySortValues(self, col, key1, key2): + """Returns a tuple of 2 values to use for secondary sort values when the + items in the selected column match equal. The default just returns the + item data values.""" + return (key1, key2) - def OnColClick(self, evt): - self._col = col = evt.m_col + + def __OnColClick(self, evt): + oldCol = self._col + self._col = col = evt.GetColumn() self._colSortFlag[col] = not self._colSortFlag[col] - self.GetListCtrl().SortItems(self.ColumnSorter) + self.GetListCtrl().SortItems(self.GetColumnSorter()) + self.__updateImages(oldCol) + evt.Skip() - def ColumnSorter(self, key1, key2): + def __ColumnSorter(self, key1, key2): col = self._col - sortFlag = self._colSortFlag[col] + ascending = self._colSortFlag[col] item1 = self.itemDataMap[key1][col] item2 = self.itemDataMap[key2][col] - if item1 == item2: return 0 - if sortFlag: - if item1 < item2: return -1 - else: return 1 + + cmpVal = cmp(item1, item2) + + # If the items are equal then pick something else to make the sort value unique + if cmpVal == 0: + cmpVal = apply(cmp, self.GetSecondarySortValues(col, key1, key2)) + + if ascending: + return cmpVal else: - if item1 > item2: return -1 - else: return 1 + return -cmpVal - def GetColumnWidths(self): - list = self.GetListCtrl() - rv = [] - for x in range(len(self._colSortFlag)): - rv.append(list.GetColumnWidth(x)) - return rv + def __updateImages(self, oldCol): + sortImages = self.GetSortImages() + if self._col != -1 and sortImages[0] != -1: + img = sortImages[self._colSortFlag[self._col]] + list = self.GetListCtrl() + if oldCol != -1: + list.ClearColumnImage(oldCol) + list.SetColumnImage(self._col, img) + #---------------------------------------------------------------------------- +#---------------------------------------------------------------------------- + +class wxListCtrlAutoWidthMixin: + """ A mix-in class that automatically resizes the last column to take up + the remaining width of the wxListCtrl. + + This causes the wxListCtrl to automatically take up the full width of + the list, without either a horizontal scroll bar (unless absolutely + necessary) or empty space to the right of the last column. + NOTE: This only works for report-style lists. + WARNING: If you override the EVT_SIZE event in your wxListCtrl, make + sure you call event.Skip() to ensure that the mixin's + _OnResize method is called. + This mix-in class was written by Erik Westra +""" + def __init__(self): + """ Standard initialiser. + """ + self._needResize = false + self._lastColMinWidth = None + EVT_SIZE(self, self._onResize) + EVT_LIST_COL_END_DRAG(self, self.GetId(), self._onEndColDrag) + EVT_IDLE(self, self._onIdle) + def resizeLastColumn(self, minWidth): + """ Resize the last column appropriately. + + If the list's columns are too wide to fit within the window, we use + a horizontal scrollbar. Otherwise, we expand the right-most column + to take up the remaining free space in the list. + + This method is called automatically when the wxListCtrl is resized; + you can also call it yourself whenever you want the last column to + be resized appropriately (eg, when adding, removing or resizing + columns). + + 'minWidth' is the preferred minimum width for the last column. + """ + self._lastColMinWidth = minWidth + self._doResize() + + # ===================== + # == Private Methods == + # ===================== + + def _onResize(self, event): + """ Respond to the wxListCtrl being resized. + + We automatically resize the last column in the list. + """ + self._doResize() + + + def _onEndColDrag(self, event): + """ Respond to the user resizing one of our columns. + + We resize the last column in the list to match. Note that, because + of a quirk in the way columns are resized under MS Windows, we + actually have to do the column resize in idle time. + """ + self._needResize = true + + + def _onIdle(self, event): + """ Respond to an idle event. + + We resize the last column, if we've been asked to do so. + """ + if self._needResize: + self._doResize() + self.Refresh() # Fixes redraw problem under MS Windows. + self._needResize = false + + + def _doResize(self): + """ Resize the last column as appropriate. + + If the list's columns are too wide to fit within the window, we use + a horizontal scrollbar. Otherwise, we expand the right-most column + to take up the remaining free space in the list. + + We remember the current size of the last column, before resizing, + as the preferred minimum width if we haven't previously been given + or calculated a minimum width. This ensure that repeated calls to + _doResize() don't cause the last column to size itself too large. + """ + numCols = self.GetColumnCount() + if numCols == 0: return # Nothing to resize. + + if self._lastColMinWidth == None: + self._lastColMinWidth = self.GetColumnWidth(numCols - 1) + + listWidth = self.GetSize().width + if self.GetItemCount() > self.GetCountPerPage(): + # We're showing the vertical scrollbar -> allow for scrollbar width + scrollWidth = wxSystemSettings_GetSystemMetric(wxSYS_VSCROLL_X) + listWidth = listWidth - scrollWidth + + totColWidth = 0 # Width of all columns except last one. + for col in range(numCols-1): + totColWidth = totColWidth + self.GetColumnWidth(col) + + lastColWidth = self.GetColumnWidth(numCols - 1) + + margin = 6 # NOTE: This is the extra number of pixels required to make + # the wxListCtrl size correctly, at least under + # Windows 2000. Unfortunately, different OSs and + # even different versions of the same OS may implement + # the wxListCtrl differently, so different margins may + # be needed to get the columns resized correctly. No + # doubt the margin could be calculated in a more + # intelligent manner... + + if totColWidth + self._lastColMinWidth > listWidth - margin: + # We haven't got the width to show the last column at its minimum + # width -> set it to its minimum width and allow the horizontal + # scrollbar to show. + self.SetColumnWidth(numCols-1, self._lastColMinWidth) + return + + # Resize the last column to take up the remaining available space. + + self.SetColumnWidth(numCols-1, listWidth - totColWidth - margin) + + + +#----------------------------------------------------------------------------