1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
|
# London Law -- a networked manhunting board game
# Copyright (C) 2003-2004, 2005 Paul Pelzl
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, Version 2, as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# AutoListCtrl.py
#
# This module contains a base class list control that does the following:
# * sort by column when clicking on headers (ColumnSorterMixin)
# * auto-expands the width of the last column to fill available space
# (ListCtrlAutoWidthMixin)
# * supports realtime addition and removal of items
#
# This base class will be used in both the game room browser and the
# team selection window.
#
# appears after first logging in to a server. Users may join exactly one game
# at a time, at which point a player registration window is spawned.
from twisted.python import log
import wx
from wx.lib.mixins.listctrl import ColumnSorterMixin, ListCtrlAutoWidthMixin
from londonlaw.common.config import *
import os.path
# the AutoWidthMixin simply resizes the last column of of the
# ListCtrl to take up all remaining space.
class AutoWidthListCtrl(wx.ListCtrl, ListCtrlAutoWidthMixin):
def __init__(self, parent, ID, pos = wx.DefaultPosition,
size = wx.DefaultSize, style = 0):
wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
ListCtrlAutoWidthMixin.__init__(self)
# 'headers' is a list of column headers.
# 'placeholder' should be a list of display data that is shown when
# the list is empty (same length as 'headers').
class AutoListCtrl(AutoWidthListCtrl, ColumnSorterMixin):
def __init__(self, parent, ID, headers, placeholder = None):
AutoWidthListCtrl.__init__(self, parent, ID, wx.DefaultPosition, wx.DefaultSize,
wx.LC_REPORT|wx.LC_SINGLE_SEL)
self.headers = headers
# load in the tiny arrow images that ColumnSorterMixin draws
# in the headers of sorted columns
# WARNING: this segfaults if imageList is a local variable.
# Maybe a wxPython bug... imageList falls out of scope and gets deleted prematurely?
self.imageList = wx.ImageList(16, 16, True)
file1 = os.path.normpath(os.path.join(MEDIAROOT, "images/smalluparrow.png"))
file2 = os.path.normpath(os.path.join(MEDIAROOT, "images/smalldownarrow.png"))
image = wx.Image(file1, wx.BITMAP_TYPE_ANY)
image.SetMaskColour(255, 255, 255)
self.smallUpArrow = self.imageList.Add(wx.BitmapFromImage(image))
image = wx.Image(file2, wx.BITMAP_TYPE_ANY)
image.SetMaskColour(255, 255, 255)
self.smallDnArrow = self.imageList.Add(wx.BitmapFromImage(image))
self.SetImageList(self.imageList, wx.IMAGE_LIST_SMALL)
self.placeholder = placeholder
# data from the server should be formatted as
# ("game name", "game type", "game status", "number of players")
if self.placeholder:
self.itemDataMap = {0 : self.placeholder}
else:
self.itemDataMap = {}
self.populateList()
# this must be called *after* the list has been created
ColumnSorterMixin.__init__(self, len(self.headers))
def populateList(self):
info = wx.ListItem()
info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
info.m_image = -1
info.m_format = wx.LIST_FORMAT_CENTRE
for i in range(len(self.headers)):
info.m_text = self.headers[i]
self.InsertColumnInfo(i, info)
items = self.itemDataMap.items()
for i in range(len(items)):
key, data = items[i]
self.InsertStringItem(i, data[0])
for j in range(1, len(self.headers)):
self.SetStringItem(i, j, data[j])
self.SetItemData(i, key)
# dirty hack... wxWidgets needs a wx.LIST_AUTOSIZE_* that
# chooses the maximum of BOTH header size and list item size
for i in range(len(self.headers) - 1):
self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
itemWidth = self.GetColumnWidth(i)
self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
headerWidth = self.GetColumnWidth(i)
if headerWidth < itemWidth:
self.SetColumnWidth(i, wx.LIST_AUTOSIZE)
# size of last column is set automatically by ListCtrlAutoWidthMixin
# def logListData(self):
# print "itemDataMap = " + str(self.itemDataMap)
# for i in range(len(self.itemDataMap)):
# print "item[" + `i` + "] = " + `self.GetItemData(i)` + ", " + \
# self.GetItemText(i)
# this will either add a new item or update an existing item if the first
# piece of data matches
def addItem(self, data):
log.msg("called GameListWindow.addGameInfo(), data = " + str(data))
# check for pre-existing matching data
foundMatch = False
for item in range(len(self.itemDataMap)):
if data[0] == self.itemDataMap[item][0]:
foundMatch = True
for i in range(1, len(data)):
self.SetStringItem(item, i, data[i])
if not foundMatch:
# if no matches found, add a new item to the list
if self.placeholder:
if self.itemDataMap[0] == self.placeholder:
log.msg("deleting placeholder")
self.DeleteItem(0)
del self.itemDataMap[0]
index = len(self.itemDataMap)
self.itemDataMap[index] = data
self.InsertStringItem(index, data[0])
for i in range(1, len(self.headers)):
self.SetStringItem(index, i, data[i])
self.SetItemData(index, index)
# Note: This is completely asinine. Removing an item should be an easy
# process that does not impact sorting.
# This routine will remove the item with matching data[0] value.
def removeItemByData(self, data):
for key in self.itemDataMap:
if self.itemDataMap[key][0] == data[0]:
# update the datamap
for i in range(key, len(self.itemDataMap)-1):
self.itemDataMap[i] = self.itemDataMap[i+1]
del self.itemDataMap[len(self.itemDataMap)-1]
if len(self.itemDataMap) == 0 and self.placeholder:
self.itemDataMap[0] = self.placeholder
self.InsertStringItem(0, self.placeholder[0])
for i in range(len(self.headers)):
self.SetStringItem(0, i, self.placeholder[i])
break
# delete the requested item
for item in range(self.GetItemCount()):
if self.GetItemText(item) == data[0]:
self.DeleteItem(item)
break
# update the ItemData field associated with the remaining items,
# to keep them in sync with the keys of the itemDataMap
for item in range(len(self.itemDataMap)):
for key in range(len(self.itemDataMap)):
if self.itemDataMap[key][0] == self.GetItemText(item):
self.SetItemData(item, key)
# required by ColumnSorterMixin
def GetListCtrl(self):
return self
# used by ColumnSorterMixin to display up and down arrows
# on sorted column headers
def GetSortImages(self):
return (self.smallDnArrow, self.smallUpArrow)
# arch-tag: DO_NOT_CHANGE_805cd141-cd81-40ae-a5c6-c8f7bacdd2f3
|