1 """GNUmed list controls and widgets.
2
3 TODO:
4
5 From: Rob McMullen <rob.mcmullen@gmail.com>
6 To: wxPython-users@lists.wxwidgets.org
7 Subject: Re: [wxPython-users] ANN: ColumnSizer mixin for ListCtrl
8
9 Thanks for all the suggestions, on and off line. There's an update
10 with a new name (ColumnAutoSizeMixin) and better sizing algorithm at:
11
12 http://trac.flipturn.org/browser/trunk/peppy/lib/column_autosize.py
13
14 sorting: http://code.activestate.com/recipes/426407/
15 """
16
17 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
18 __license__ = "GPL v2 or later"
19
20
21 import sys
22 import types
23 import logging
24 import thread
25 import time
26 import re as regex
27
28
29 import wx
30 import wx.lib.mixins.listctrl as listmixins
31
32
33 _log = logging.getLogger('gm.list_ui')
34
35
36
37 -def get_choices_from_list (
38 parent=None,
39 msg=None,
40 caption=None,
41 columns=None,
42 choices=None,
43 data=None,
44 selections=None,
45 edit_callback=None,
46 new_callback=None,
47 delete_callback=None,
48 refresh_callback=None,
49 single_selection=False,
50 can_return_empty=False,
51 ignore_OK_button=False,
52 left_extra_button=None,
53 middle_extra_button=None,
54 right_extra_button=None,
55 list_tooltip_callback=None):
120
121 from Gnumed.wxGladeWidgets import wxgGenericListSelectorDlg
122
124 """A dialog holding a list and a few buttons to act on the items."""
125
126
127
150
153
156
161
172
175
178
179
180
182 if not self.__ignore_OK_button:
183 self._BTN_ok.SetDefault()
184 self._BTN_ok.Enable(True)
185
186 if self.edit_callback is not None:
187 self._BTN_edit.Enable(True)
188
189 if self.delete_callback is not None:
190 self._BTN_delete.Enable(True)
191
193 if self._LCTRL_items.get_selected_items(only_one=True) == -1:
194 if not self.can_return_empty:
195 self._BTN_cancel.SetDefault()
196 self._BTN_ok.Enable(False)
197 self._BTN_edit.Enable(False)
198 self._BTN_delete.Enable(False)
199
214
231
252
268
284
300
301
302
316
317 ignore_OK_button = property(lambda x:x, _set_ignore_OK_button)
318
334
335 left_extra_button = property(lambda x:x, _set_left_extra_button)
336
352
353 middle_extra_button = property(lambda x:x, _set_middle_extra_button)
354
370
371 right_extra_button = property(lambda x:x, _set_right_extra_button)
372
374 return self.__new_callback
375
377 if callback is not None:
378 if self.refresh_callback is None:
379 raise ValueError('refresh callback must be set before new callback can be set')
380 if not callable(callback):
381 raise ValueError('<new> callback is not a callable: %s' % callback)
382 self.__new_callback = callback
383
384 if callback is None:
385 self._BTN_new.Enable(False)
386 self._BTN_new.Hide()
387 else:
388 self._BTN_new.Enable(True)
389 self._BTN_new.Show()
390
391 new_callback = property(_get_new_callback, _set_new_callback)
392
394 return self.__edit_callback
395
397 if callback is not None:
398 if not callable(callback):
399 raise ValueError('<edit> callback is not a callable: %s' % callback)
400 self.__edit_callback = callback
401
402 if callback is None:
403 self._BTN_edit.Enable(False)
404 self._BTN_edit.Hide()
405 else:
406 self._BTN_edit.Enable(True)
407 self._BTN_edit.Show()
408
409 edit_callback = property(_get_edit_callback, _set_edit_callback)
410
412 return self.__delete_callback
413
415 if callback is not None:
416 if self.refresh_callback is None:
417 raise ValueError('refresh callback must be set before delete callback can be set')
418 if not callable(callback):
419 raise ValueError('<delete> callback is not a callable: %s' % callback)
420 self.__delete_callback = callback
421
422 if callback is None:
423 self._BTN_delete.Enable(False)
424 self._BTN_delete.Hide()
425 else:
426 self._BTN_delete.Enable(True)
427 self._BTN_delete.Show()
428
429 delete_callback = property(_get_delete_callback, _set_delete_callback)
430
432 return self.__refresh_callback
433
441
443 if callback is not None:
444 if not callable(callback):
445 raise ValueError('<refresh> callback is not a callable: %s' % callback)
446 self.__refresh_callback = callback
447 if callback is not None:
448 wx.CallAfter(self._set_refresh_callback_helper)
449
450 refresh_callback = property(_get_refresh_callback, _set_refresh_callback)
451
454
455 list_tooltip_callback = property(lambda x:x, _set_list_tooltip_callback)
456
457
458
460 if message is None:
461 self._LBL_message.Hide()
462 return
463 self._LBL_message.SetLabel(message)
464 self._LBL_message.Show()
465
466 message = property(lambda x:x, _set_message)
467
468 from Gnumed.wxGladeWidgets import wxgGenericListManagerPnl
469
471 """A panel holding a generic multi-column list and action buttions."""
472
498
499
500
503
513
516
519
522
523
524
526 if self.edit_callback is not None:
527 self._BTN_edit.Enable(True)
528 if self.delete_callback is not None:
529 self._BTN_remove.Enable(True)
530 if self.__select_callback is not None:
531 item = self._LCTRL_items.get_selected_item_data(only_one=True)
532 self.__select_callback(item)
533
535 if self._LCTRL_items.get_selected_items(only_one=True) == -1:
536 self._BTN_edit.Enable(False)
537 self._BTN_remove.Enable(False)
538 if self.__select_callback is not None:
539 self.__select_callback(None)
540
551
556
570
584
600
616
632
633
634
636 return self.__new_callback
637
639 if callback is not None:
640 if not callable(callback):
641 raise ValueError('<new> callback is not a callable: %s' % callback)
642 self.__new_callback = callback
643 self._BTN_add.Enable(callback is not None)
644
645 new_callback = property(_get_new_callback, _set_new_callback)
646
648 return self.__select_callback
649
651 if callback is not None:
652 if not callable(callback):
653 raise ValueError('<select> callback is not a callable: %s' % callback)
654 self.__select_callback = callback
655
656 select_callback = property(_get_select_callback, _set_select_callback)
657
659 return self._LBL_message.GetLabel()
660
662 if msg is None:
663 self._LBL_message.Hide()
664 self._LBL_message.SetLabel(u'')
665 else:
666 self._LBL_message.SetLabel(msg)
667 self._LBL_message.Show()
668 self.Layout()
669
670 message = property(_get_message, _set_message)
671
687
688 left_extra_button = property(lambda x:x, _set_left_extra_button)
689
705
706 middle_extra_button = property(lambda x:x, _set_middle_extra_button)
707
723
724 right_extra_button = property(lambda x:x, _set_right_extra_button)
725
726 from Gnumed.wxGladeWidgets import wxgItemPickerDlg
727
729
731
732 try:
733 msg = kwargs['msg']
734 del kwargs['msg']
735 except KeyError:
736 msg = None
737
738 wxgItemPickerDlg.wxgItemPickerDlg.__init__(self, *args, **kwargs)
739
740 if msg is None:
741 self._LBL_msg.Hide()
742 else:
743 self._LBL_msg.SetLabel(msg)
744
745 self._LCTRL_left.activate_callback = self.__pick_selected
746
747 self.__extra_button_callback = None
748
749 self._LCTRL_left.SetFocus()
750
751
752
753 - def set_columns(self, columns=None, columns_right=None):
754 self._LCTRL_left.set_columns(columns = columns)
755 if columns_right is None:
756 self._LCTRL_right.set_columns(columns = columns)
757 else:
758 if len(columns_right) < len(columns):
759 cols = columns
760 else:
761 cols = columns_right[:len(columns)]
762 self._LCTRL_right.set_columns(columns = cols)
763
771
774
779
785
788
791
792 picks = property(get_picks, lambda x:x)
793
809
810 extra_button = property(lambda x:x, _set_extra_button)
811
812
813
833
835 if self._LCTRL_right.get_selected_items(only_one = True) == -1:
836 return
837
838 for item_idx in self._LCTRL_right.get_selected_items(only_one = False):
839 self._LCTRL_right.remove_item(item_idx)
840
841 if self._LCTRL_right.GetItemCount() == 0:
842 self._BTN_right2left.Enable(False)
843
844
845
847 self._BTN_left2right.Enable(True)
848
850 if self._LCTRL_left.get_selected_items(only_one = True) == -1:
851 self._BTN_left2right.Enable(False)
852
854 self._BTN_right2left.Enable(True)
855
857 if self._LCTRL_right.get_selected_items(only_one = True) == -1:
858 self._BTN_right2left.Enable(False)
859
862
865
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883 -class cReportListCtrl(wx.ListCtrl, listmixins.ListCtrlAutoWidthMixin, listmixins.ColumnSorterMixin):
884
885 get_data_idx_for_item = wx.ListCtrl.GetItemData
886
887 sort_order_tags = {
888 True: u' [\u03b1\u0391 \u2192 \u03c9\u03A9]',
889 False: u' [\u03c9\u03A9 \u2192 \u03b1\u0391]'
890 }
891
893
894 self.debug = None
895
896 try:
897 kwargs['style'] = kwargs['style'] | wx.LC_REPORT
898 except KeyError:
899 kwargs['style'] = wx.LC_REPORT
900
901 self.__is_single_selection = ((kwargs['style'] & wx.LC_SINGLE_SEL) == wx.LC_SINGLE_SEL)
902
903 wx.ListCtrl.__init__(self, *args, **kwargs)
904 listmixins.ListCtrlAutoWidthMixin.__init__(self)
905
906
907 self._invalidate_item2data_idx_map()
908 listmixins.ColumnSorterMixin.__init__(self, 0)
909
910
911
912 self.__widths = None
913 self.__data = None
914 self.__activate_callback = None
915 self.__rightclick_callback = None
916
917 self.__item_tooltip_callback = None
918 self.__tt_last_item = None
919 self.__tt_static_part = _("""Select the items you want to work on.
920
921 A discontinuous selection may depend on your holding down a platform-dependent modifier key (<ctrl>, <alt>, etc) or key combination (eg. <ctrl-shift> or <ctrl-alt>) while clicking.""")
922 self.Bind(wx.EVT_MOTION, self._on_mouse_motion)
923
924 self.__next_line_to_search = 0
925 self.__search_data = None
926 self.__search_dlg = None
927 self.__searchable_cols = None
928
929 self.Bind(wx.EVT_CHAR, self._on_char)
930 self.Bind(wx.EVT_FIND_CLOSE, self._on_search_dlg_closed)
931 self.Bind(wx.EVT_FIND, self._on_search_first_match)
932 self.Bind(wx.EVT_FIND_NEXT, self._on_search_next_match)
933
934
935
937 """(Re)define the columns.
938
939 Note that this will (have to) delete the items.
940 """
941 self.ClearAll()
942 self.__tt_last_item = None
943 if columns is None:
944 return
945 for idx in range(len(columns)):
946 self.InsertColumn(idx, columns[idx])
947
948 self._invalidate_item2data_idx_map()
949
951 """Set the column width policy.
952
953 widths = None:
954 use previous policy if any or default policy
955 widths != None:
956 use this policy and remember it for later calls
957
958 This means there is no way to *revert* to the default policy :-(
959 """
960
961 if widths is not None:
962 self.__widths = widths
963 for idx in range(len(self.__widths)):
964 self.SetColumnWidth(col = idx, width = self.__widths[idx])
965 return
966
967
968 if self.__widths is not None:
969 for idx in range(len(self.__widths)):
970 self.SetColumnWidth(col = idx, width = self.__widths[idx])
971 return
972
973
974 if self.GetItemCount() == 0:
975 width_type = wx.LIST_AUTOSIZE_USEHEADER
976 else:
977 width_type = wx.LIST_AUTOSIZE
978 for idx in range(self.GetColumnCount()):
979 self.SetColumnWidth(col = idx, width = width_type)
980
982 """All item members must be unicode()able or None."""
983
984 wx.BeginBusyCursor()
985
986 loop = 0
987 while True:
988 if loop > 3:
989 _log.debug('unable to delete list items after looping 3 times, continuing and hoping for the best')
990 break
991 loop += 1
992 if self.debug is not None:
993 _log.debug('[round %s] GetItemCount() before DeleteAllItems(): %s (%s, thread [%s])', loop, self.GetItemCount(), self.debug, thread.get_ident())
994 if not self.DeleteAllItems():
995 _log.debug('DeleteAllItems() failed (%s)', self.debug)
996 item_count = self.GetItemCount()
997 if self.debug is not None:
998 _log.debug('GetItemCount() after DeleteAllItems(): %s (%s)', item_count, self.debug)
999 if item_count == 0:
1000 break
1001 wx.SafeYield(None, True)
1002 _log.debug('GetItemCount() not 0 after DeleteAllItems() (%s)', self.debug)
1003 time.sleep(0.3)
1004 wx.SafeYield(None, True)
1005
1006 if items is None:
1007 self.data = None
1008 wx.EndBusyCursor()
1009 return
1010
1011 for item in items:
1012 try:
1013 item[0]
1014 if not isinstance(item, basestring):
1015 is_numerically_iterable = True
1016
1017 else:
1018 is_numerically_iterable = False
1019 except TypeError:
1020 is_numerically_iterable = False
1021
1022 if is_numerically_iterable:
1023
1024
1025 col_val = unicode(item[0])
1026 row_num = self.InsertStringItem(index = sys.maxint, label = col_val)
1027 for col_num in range(1, min(self.GetColumnCount(), len(item))):
1028 col_val = unicode(item[col_num])
1029 self.SetStringItem(index = row_num, col = col_num, label = col_val)
1030 else:
1031
1032 col_val = unicode(item)
1033 row_num = self.InsertStringItem(index = sys.maxint, label = col_val)
1034
1035 self.SetItemData(row_num, row_num)
1036
1037 self.data = items
1038 self._invalidate_item2data_idx_map()
1039
1040 wx.EndBusyCursor()
1041
1043 """<data> assumed to be a list corresponding to the item indices"""
1044
1045
1046 if data is not None:
1047 item_count = self.GetItemCount()
1048 if len(data) != item_count:
1049 _log.debug('<data> length (%s) must be equal to number of list items (%s) (%s, thread [%s])', len(data), item_count, self.debug, thread.get_ident())
1050
1051 for item_idx in range(len(data)):
1052 self.SetItemData(item_idx, item_idx)
1053 self.__data = data
1054 self.__tt_last_item = None
1055
1056
1057 return
1058
1063
1064 data = property(_get_data, set_data)
1065
1072
1073
1075 if self.__is_single_selection:
1076 return [self.GetFirstSelected()]
1077 selections = []
1078 idx = self.GetFirstSelected()
1079 while idx != -1:
1080 selections.append(idx)
1081 idx = self.GetNextSelected(idx)
1082 return selections
1083
1084 selections = property(__get_selections, set_selections)
1085
1086
1087
1089 labels = []
1090 for col_idx in self.GetColumnCount():
1091 col = self.GetColumn(col = col_idx)
1092 labels.append(col.GetText())
1093 return labels
1094
1096 if item_idx is not None:
1097 return self.GetItem(item_idx)
1098
1100 return [ self.GetItem(item_idx) for item_idx in range(self.GetItemCount()) ]
1101
1103 return [ self.GetItemText(item_idx) for item_idx in range(self.GetItemCount()) ]
1104
1106
1107 if self.__is_single_selection or only_one:
1108 return self.GetFirstSelected()
1109
1110 items = []
1111 idx = self.GetFirstSelected()
1112 while idx != -1:
1113 items.append(idx)
1114 idx = self.GetNextSelected(idx)
1115
1116 return items
1117
1119
1120 if self.__is_single_selection or only_one:
1121 return self.GetItemText(self.GetFirstSelected())
1122
1123 items = []
1124 idx = self.GetFirstSelected()
1125 while idx != -1:
1126 items.append(self.GetItemText(idx))
1127 idx = self.GetNextSelected(idx)
1128
1129 return items
1130
1132 if self.__data is None:
1133 return None
1134
1135
1136 if item_idx is not None:
1137 return self.__data[self.get_data_idx_for_item(item_idx)]
1138
1139
1140
1141
1142 return [ self.__data[self.get_data_idx_for_item(item_idx)] for item_idx in range(self.GetItemCount()) ]
1143
1145
1146 if self.__is_single_selection or only_one:
1147 if self.__data is None:
1148 return None
1149 idx = self.GetFirstSelected()
1150 if idx == -1:
1151 return None
1152 return self.__data[self.get_data_idx_for_item(idx)]
1153
1154 data = []
1155 if self.__data is None:
1156 return data
1157 idx = self.GetFirstSelected()
1158 while idx != -1:
1159 data.append(self.__data[self.get_data_idx_for_item(idx)])
1160 idx = self.GetNextSelected(idx)
1161
1162 return data
1163
1165 self.Select(idx = self.GetFirstSelected(), on = 0)
1166
1168 if self.__data is not None:
1169 del self.__data[self.get_data_idx_for_item(item_idx)]
1170 self.DeleteItem(item_idx)
1171 self.__tt_last_item = None
1172
1173
1174
1176 event.Skip()
1177 if self.__activate_callback is not None:
1178 self.__activate_callback(event)
1179
1181 event.Skip()
1182 if self.__rightclick_callback is not None:
1183 self.__rightclick_callback(event)
1184
1186
1187 if evt.GetModifiers() != wx.MOD_CMD:
1188 evt.Skip()
1189 return
1190
1191 if unichr(evt.GetRawKeyCode()) != u'f':
1192 evt.Skip()
1193 return
1194
1195 if self.__search_dlg is not None:
1196 self.__search_dlg.Close()
1197 return
1198
1199 if len(self.__searchable_cols) == 0:
1200 return
1201
1202 if self.__search_data is None:
1203 self.__search_data = wx.FindReplaceData()
1204 self.__search_dlg = wx.FindReplaceDialog (
1205 self,
1206 self.__search_data,
1207 _('Search in list'),
1208 wx.FR_NOUPDOWN | wx.FR_NOMATCHCASE | wx.FR_NOWHOLEWORD
1209 )
1210 self.__search_dlg.Show(True)
1211
1213 self.__search_dlg.Destroy()
1214 self.__search_dlg = None
1215
1217 evt.Skip()
1218 if self.__search_dlg is None:
1219 return
1220 print self.FindFocus()
1221 print self.__search_dlg
1222
1223
1225 for row_idx in range(self.__next_line_to_search, self.ItemCount):
1226 for col_idx in range(self.ColumnCount):
1227 if col_idx not in self.__searchable_cols:
1228 continue
1229 col_val = self.GetItem(row_idx, col_idx).GetText()
1230 if regex.search(search_term, col_val, regex.U | regex.I) is not None:
1231 self.Select(row_idx)
1232 self.EnsureVisible(row_idx)
1233 if row_idx == self.ItemCount - 1:
1234
1235 self.__next_line_to_search = 0
1236 else:
1237 self.__next_line_to_search = row_idx + 1
1238 return True
1239
1240 self.__next_line_to_search = 0
1241 return False
1242
1244 self.__on_search_match(evt.GetFindString())
1245
1247 self.__on_search_match(evt.GetFindString())
1248
1250 """Update tooltip on mouse motion.
1251
1252 for s in dir(wx):
1253 if s.startswith('LIST_HITTEST'):
1254 print s, getattr(wx, s)
1255
1256 LIST_HITTEST_ABOVE 1
1257 LIST_HITTEST_BELOW 2
1258 LIST_HITTEST_NOWHERE 4
1259 LIST_HITTEST_ONITEM 672
1260 LIST_HITTEST_ONITEMICON 32
1261 LIST_HITTEST_ONITEMLABEL 128
1262 LIST_HITTEST_ONITEMRIGHT 256
1263 LIST_HITTEST_ONITEMSTATEICON 512
1264 LIST_HITTEST_TOLEFT 1024
1265 LIST_HITTEST_TORIGHT 2048
1266 """
1267 item_idx, where_flag = self.HitTest(wx.Point(event.X, event.Y))
1268
1269
1270 if where_flag not in [
1271 wx.LIST_HITTEST_ONITEMLABEL,
1272 wx.LIST_HITTEST_ONITEMICON,
1273 wx.LIST_HITTEST_ONITEMSTATEICON,
1274 wx.LIST_HITTEST_ONITEMRIGHT,
1275 wx.LIST_HITTEST_ONITEM
1276 ]:
1277 self.__tt_last_item = None
1278 self.SetToolTipString(self.__tt_static_part)
1279 return
1280
1281
1282 if self.__tt_last_item == item_idx:
1283 return
1284
1285
1286 self.__tt_last_item = item_idx
1287
1288
1289
1290 if item_idx == wx.NOT_FOUND:
1291 self.SetToolTipString(self.__tt_static_part)
1292 return
1293
1294
1295 if self.__data is None:
1296 self.SetToolTipString(self.__tt_static_part)
1297 return
1298
1299
1300
1301
1302
1303 if (
1304 (item_idx > (len(self.__data) - 1))
1305 or
1306 (item_idx < -1)
1307 ):
1308 self.SetToolTipString(self.__tt_static_part)
1309 print "*************************************************************"
1310 print "GNUmed has detected an inconsistency with list item tooltips."
1311 print ""
1312 print "This is not a big problem and you can keep working."
1313 print ""
1314 print "However, please send us the following so we can fix GNUmed:"
1315 print ""
1316 print "item idx: %s" % item_idx
1317 print 'where flag: %s' % where_flag
1318 print 'data list length: %s' % len(self.__data)
1319 print "*************************************************************"
1320 return
1321
1322 dyna_tt = None
1323 if self.__item_tooltip_callback is not None:
1324 dyna_tt = self.__item_tooltip_callback(self.__data[self.get_data_idx_for_item(item_idx)])
1325
1326 if dyna_tt is None:
1327 self.SetToolTipString(self.__tt_static_part)
1328 return
1329
1330 self.SetToolTipString(dyna_tt)
1331
1332
1333
1335 return self.__activate_callback
1336
1338 if callback is None:
1339 self.Unbind(wx.EVT_LIST_ITEM_ACTIVATED)
1340 else:
1341 if not callable(callback):
1342 raise ValueError('<activate> callback is not a callable: %s' % callback)
1343 self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self._on_list_item_activated)
1344 self.__activate_callback = callback
1345
1346 activate_callback = property(_get_activate_callback, _set_activate_callback)
1347
1349 return self.__rightclick_callback
1350
1352 if callback is None:
1353 self.Unbind(wx.EVT_LIST_ITEM_RIGHT_CLICK)
1354 else:
1355 if not callable(callback):
1356 raise ValueError('<rightclick> callback is not a callable: %s' % callback)
1357 self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self._on_list_item_rightclicked)
1358 self.__rightclick_callback = callback
1359
1360 rightclick_callback = property(_get_rightclick_callback, _set_rightclick_callback)
1361
1367
1368
1369
1370
1371
1372 item_tooltip_callback = property(lambda x:x, _set_item_tooltip_callback)
1373
1375
1376 if cols is None:
1377 self.__searchable_cols = range(self.ColumnCount)
1378 return
1379
1380
1381 new_cols = {}
1382 for col in cols:
1383 if col < self.ColumnCount:
1384 new_cols[col] = True
1385 self.__searchable_cols = new_cols.keys()
1386
1387 searchable_columns = property(lambda x:x, _set_searchable_cols)
1388
1389
1390
1392 if self.itemDataMap is None:
1393 self._update_item2data_idx_map()
1394
1395 return self
1396
1398 self._cleanup_column_headers()
1399
1400 col_idx, is_ascending = self.GetSortState()
1401 col_state = self.GetColumn(col_idx)
1402 col_state.m_text += self.sort_order_tags[is_ascending]
1403 self.SetColumn(col_idx, col_state)
1404
1406 dict2sort = {}
1407 item_count = self.GetItemCount()
1408 if item_count == 0:
1409 return dict2sort
1410 col_count = self.GetColumnCount()
1411 for item_idx in range(item_count):
1412 dict2sort[item_idx] = ()
1413 if col_count == 0:
1414 continue
1415 for col_idx in range(col_count):
1416 dict2sort[item_idx] += (self.GetItem(item_idx, col_idx).GetText(), )
1417
1418 return dict2sort
1419
1421 for col_idx in range(self.ColumnCount):
1422 col_state = self.GetColumn(col_idx)
1423 if col_state.m_text.endswith(self.sort_order_tags[True]):
1424 col_state.m_text = col_state.m_text[:-len(self.sort_order_tags[True])]
1425 if col_state.m_text.endswith(self.sort_order_tags[False]):
1426 col_state.m_text = col_state.m_text[:-len(self.sort_order_tags[False])]
1427 self.SetColumn(col_idx, col_state)
1428
1430 self.itemDataMap = None
1431 self.SetColumnCount(self.GetColumnCount())
1432 self._cleanup_column_headers()
1433
1435 self.itemDataMap = self._prepare_items_for_sorting()
1436
1438
1439
1440
1441
1442
1443
1444 event.Skip()
1445
1446
1447
1448
1449 if __name__ == '__main__':
1450
1451 if len(sys.argv) < 2:
1452 sys.exit()
1453
1454 if sys.argv[1] != 'test':
1455 sys.exit()
1456
1457 sys.path.insert(0, '../../')
1458
1459 from Gnumed.pycommon import gmI18N
1460 gmI18N.activate_locale()
1461 gmI18N.install_domain()
1462
1463
1465 app = wx.PyWidgetTester(size = (400, 500))
1466 dlg = wx.MultiChoiceDialog (
1467 parent = None,
1468 message = 'test message',
1469 caption = 'test caption',
1470 choices = ['a', 'b', 'c', 'd', 'e']
1471 )
1472 dlg.ShowModal()
1473 sels = dlg.GetSelections()
1474 print "selected:"
1475 for sel in sels:
1476 print sel
1477
1479
1480 def edit(argument):
1481 print "editor called with:"
1482 print argument
1483
1484 def refresh(lctrl):
1485 choices = ['a', 'b', 'c']
1486 lctrl.set_string_items(choices)
1487
1488 app = wx.PyWidgetTester(size = (200, 50))
1489 chosen = get_choices_from_list (
1490
1491 caption = 'select health issues',
1492
1493
1494 columns = ['issue'],
1495 refresh_callback = refresh
1496
1497 )
1498 print "chosen:"
1499 print chosen
1500
1502 app = wx.PyWidgetTester(size = (200, 50))
1503 dlg = cItemPickerDlg(None, -1, msg = 'Pick a few items:')
1504 dlg.set_columns(['Plugins'], ['Load in workplace', 'dummy'])
1505
1506 dlg.set_string_items(['patient', 'emr', 'docs'])
1507 result = dlg.ShowModal()
1508 print result
1509 print dlg.get_picks()
1510
1511
1512
1513 test_item_picker_dlg()
1514
1515
1516
1517