3434# <https://www.gnu.org/licenses/>.
3535
3636import wx
37+ import wx .lib .mixins .listctrl as listmix
38+ import images
3739from i18n import _
3840
3941
42+ # ============================================================================
43+ # Class ListCtrl
44+ # ============================================================================
45+ class ListCtrl (wx .ListCtrl , listmix .ListCtrlAutoWidthMixin ):
46+ def __init__ (self , parent , ID , pos = wx .DefaultPosition , size = wx .DefaultSize , style = 0 ):
47+ wx .ListCtrl .__init__ (self , parent , ID , pos , size , style )
48+ listmix .ListCtrlAutoWidthMixin .__init__ (self )
49+
50+
4051# ============================================================================
4152# Class DeviceSelectorDialog
4253# ============================================================================
43- class DeviceSelectorDialog (wx .Dialog ):
54+ class DeviceSelectorDialog (wx .Dialog , listmix . ColumnSorterMixin ):
4455
4556 # ============================================================================
4657 # Function __init__
4758 # ============================================================================
48- def __init__ (self , parent , devices , title = _ ("Select Device" ), message = _ ("Select a device:" ), select_device = None ):
49- super (). __init__ (parent , title = title , style = wx .DEFAULT_DIALOG_STYLE | wx .RESIZE_BORDER )
59+ def __init__ (self , parent , devices , title = _ ("Select Device" ), message = _ ("Select a device:" ), select_device = None , show_filename = True ):
60+ wx . Dialog . __init__ (self , parent , title = title , style = wx .DEFAULT_DIALOG_STYLE | wx .RESIZE_BORDER )
5061
5162 self .devices = devices
5263 self .selected_device = None
5364 self ._select_device = select_device
65+ self .show_filename = show_filename
5466
5567 self ._create_ui (message )
5668 self ._bind_events ()
@@ -67,18 +79,45 @@ def _create_ui(self, message):
6779 message_label = wx .StaticText (self , label = message )
6880 main_sizer .Add (message_label , 0 , wx .ALL | wx .EXPAND , 10 )
6981
82+ # Sort arrow images
83+ self .il = wx .ImageList (16 , 16 )
84+ self .sm_up = self .il .Add (images .SmallUpArrow .GetBitmap ())
85+ self .sm_dn = self .il .Add (images .SmallDnArrow .GetBitmap ())
86+
7087 # Device list
71- self .device_list = wx .ListCtrl (self , style = wx .LC_REPORT | wx .LC_SINGLE_SEL )
72- self .device_list .AppendColumn ("Device" , width = 200 )
73- self .device_list .AppendColumn ("Filename" , width = 500 )
88+ self .device_list = ListCtrl (self , - 1 , style = wx .LC_REPORT | wx .LC_SINGLE_SEL | wx .BORDER_NONE )
89+ self .device_list .SetImageList (self .il , wx .IMAGE_LIST_SMALL )
90+ self .device_list .AppendColumn (_ ("Device" ), width = 200 )
91+ if self .show_filename :
92+ self .device_list .AppendColumn (_ ("Filename" ), width = 400 )
93+
94+ has_dates = any ('last_updated' in d for d in self .devices )
95+ if has_dates :
96+ self .device_list .AppendColumn (_ ("Last Updated" ), width = 110 )
7497
7598 # Populate the list
99+ self .itemDataMap = {}
76100 selected_index = None
77101
78102 for i , device in enumerate (self .devices ):
79103 index = self .device_list .InsertItem (i , device .get ('device' , 'Unknown' ))
80- self .device_list .SetItem (index , 1 , device .get ('zip_filename' , '' ))
104+ self .device_list .SetItemColumnImage (index , 0 , - 1 ) # suppress row icon
105+ col = 1
106+ if self .show_filename :
107+ self .device_list .SetItem (index , col , device .get ('zip_filename' , '' ))
108+ col += 1
109+ if has_dates :
110+ self .device_list .SetItem (index , col , device .get ('last_updated' , '' ))
81111 self .device_list .SetItemData (index , i )
112+
113+ # Build sort map tuple, must match column order
114+ map_vals = [device .get ('device' , '' )]
115+ if self .show_filename :
116+ map_vals .append (device .get ('zip_filename' , '' ))
117+ if has_dates :
118+ map_vals .append (device .get ('last_updated' , '' ))
119+ self .itemDataMap [i ] = tuple (map_vals )
120+
82121 if selected_index is None and self ._matches_select_device (device ):
83122 selected_index = index
84123
@@ -89,6 +128,10 @@ def _create_ui(self, message):
89128 elif self .devices :
90129 self .device_list .Select (0 )
91130
131+ # Init column sorter, must be after itemDataMap and device_list are ready
132+ num_cols = 1 + (1 if self .show_filename else 0 ) + (1 if has_dates else 0 )
133+ listmix .ColumnSorterMixin .__init__ (self , num_cols )
134+
92135 main_sizer .Add (self .device_list , 1 , wx .ALL | wx .EXPAND , 10 )
93136
94137 # Buttons
@@ -106,6 +149,20 @@ def _create_ui(self, message):
106149
107150 self .SetSizer (main_sizer )
108151
152+ # ============================================================================
153+ # Function GetListCtrl
154+ # ============================================================================
155+ # Used by ColumnSorterMixin
156+ def GetListCtrl (self ):
157+ return self .device_list
158+
159+ # ============================================================================
160+ # Function GetSortImages
161+ # ============================================================================
162+ # Used by ColumnSorterMixin
163+ def GetSortImages (self ):
164+ return (self .sm_dn , self .sm_up )
165+
109166 # ============================================================================
110167 # Function _matches_select_device
111168 # ============================================================================
@@ -196,7 +253,7 @@ def get_selected_device(self):
196253# ============================================================================
197254# Function show_device_selector
198255# ============================================================================
199- def show_device_selector (parent , devices , title = _ ("Select Device" ), message = _ ("Select a device:" ), select_device = None ):
256+ def show_device_selector (parent , devices , title = _ ("Select Device" ), message = _ ("Select a device:" ), select_device = None , show_filename = True ):
200257 """
201258 Show device selector dialog and return selected device.
202259
@@ -206,6 +263,7 @@ def show_device_selector(parent, devices, title=_("Select Device"), message=_("S
206263 title: Dialog title
207264 message: Message to display above the list
208265 select_device: Preferred device (dict or string identifier) to pre-select if available
266+ show_filename: Whether to show the Filename column (default True)
209267
210268 Returns:
211269 Selected device dictionary or None if cancelled
@@ -214,7 +272,7 @@ def show_device_selector(parent, devices, title=_("Select Device"), message=_("S
214272 wx .MessageBox (_ ("No devices available." ), _ ("Error" ), wx .OK | wx .ICON_ERROR , parent )
215273 return None
216274
217- dialog = DeviceSelectorDialog (parent , devices , title , message , select_device = select_device )
275+ dialog = DeviceSelectorDialog (parent , devices , title , message , select_device = select_device , show_filename = show_filename )
218276
219277 try :
220278 if dialog .ShowModal () == wx .ID_OK :
0 commit comments