Package Gnumed :: Package wxpython :: Module gmListWidgets
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmListWidgets

  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  #================================================================ 
 15  __version__ = "$Revision: 1.37 $" 
 16  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>" 
 17  __license__ = "GPL" 
 18   
 19   
 20  import sys, types 
 21   
 22   
 23  import wx 
 24  import wx.lib.mixins.listctrl as listmixins 
 25   
 26   
 27  if __name__ == '__main__': 
 28          sys.path.insert(0, '../../') 
 29  from Gnumed.pycommon import gmTools, gmDispatcher 
 30  from Gnumed.wxpython import gmGuiHelpers 
 31  from Gnumed.wxGladeWidgets import wxgGenericListSelectorDlg, wxgGenericListManagerPnl 
 32   
 33  #================================================================ 
 34  # FIXME: configurable callback on double-click action 
 35   
36 -def get_choices_from_list ( 37 parent=None, 38 msg=None, 39 caption=None, 40 choices=None, 41 selections=None, 42 columns=None, 43 data=None, 44 edit_callback=None, 45 new_callback=None, 46 delete_callback=None, 47 refresh_callback=None, 48 single_selection=False, 49 can_return_empty=False, 50 ignore_OK_button=False, 51 left_extra_button=None, 52 middle_extra_button=None, 53 right_extra_button=None, 54 list_tooltip_callback=None):
55 """Let user select item(s) from a list. 56 57 - new_callback: () 58 - edit_callback: (item data) 59 - delete_callback: (item data) 60 - refresh_callback: (listctrl) 61 - list_tooltip_callback: (item data) 62 63 - left/middle/right_extra_button: (label, tooltip, <callback>) 64 <callback> is called with item_data as the only argument 65 66 returns: 67 on [CANCEL]: None 68 on [OK]: 69 if any items selected: 70 list of selected items 71 else: 72 if can_return_empty is True: 73 empty list 74 else: 75 None 76 """ 77 if caption is None: 78 caption = _('generic multi choice dialog') 79 80 if single_selection: 81 dlg = cGenericListSelectorDlg(parent, -1, title = caption, msg = msg, style = wx.LC_SINGLE_SEL) 82 else: 83 dlg = cGenericListSelectorDlg(parent, -1, title = caption, msg = msg) 84 85 dlg.refresh_callback = refresh_callback 86 dlg.edit_callback = edit_callback 87 dlg.new_callback = new_callback 88 dlg.delete_callback = delete_callback 89 dlg.list_tooltip_callback = list_tooltip_callback 90 91 dlg.ignore_OK_button = ignore_OK_button 92 dlg.left_extra_button = left_extra_button 93 dlg.middle_extra_button = middle_extra_button 94 dlg.right_extra_button = right_extra_button 95 96 dlg.set_columns(columns = columns) 97 98 if refresh_callback is None: 99 dlg.set_string_items(items = choices) # list ctrl will refresh anyway if possible 100 dlg.set_column_widths() 101 102 if data is not None: 103 dlg.set_data(data = data) # can override data set if refresh_callback is not None 104 105 if selections is not None: 106 dlg.set_selections(selections = selections) 107 dlg.can_return_empty = can_return_empty 108 109 btn_pressed = dlg.ShowModal() 110 sels = dlg.get_selected_item_data(only_one = single_selection) 111 dlg.Destroy() 112 113 if btn_pressed == wx.ID_OK: 114 if can_return_empty and (sels is None): 115 return [] 116 return sels 117 118 return None
119 #----------------------------------------------------------------
120 -class cGenericListSelectorDlg(wxgGenericListSelectorDlg.wxgGenericListSelectorDlg):
121 """A dialog holding a list and a few buttons to act on the items.""" 122 123 # FIXME: configurable callback on double-click action 124
125 - def __init__(self, *args, **kwargs):
126 127 try: 128 msg = kwargs['msg'] 129 del kwargs['msg'] 130 except KeyError: msg = None 131 132 wxgGenericListSelectorDlg.wxgGenericListSelectorDlg.__init__(self, *args, **kwargs) 133 134 self.message = msg 135 136 self.left_extra_button = None 137 self.middle_extra_button = None 138 self.right_extra_button = None 139 140 self.refresh_callback = None # called when new/edit/delete callbacks return True (IOW were not cancelled) 141 self.new_callback = None # called when NEW button pressed, no argument passed in 142 self.edit_callback = None # called when EDIT button pressed, data of topmost selected item passed in 143 self.delete_callback = None # called when DELETE button pressed, data of topmost selected item passed in 144 145 self.ignore_OK_button = False # by default do show/use the OK button 146 147 self.can_return_empty = False
148 #------------------------------------------------------------
149 - def set_columns(self, columns=None):
150 self._LCTRL_items.set_columns(columns = columns)
151 #------------------------------------------------------------
152 - def set_column_widths(self, widths=None):
153 self._LCTRL_items.set_column_widths(widths = widths)
154 #------------------------------------------------------------
155 - def set_string_items(self, items = None):
156 self._LCTRL_items.set_string_items(items = items) 157 self._LCTRL_items.set_column_widths() 158 self._LCTRL_items.Select(0)
159 #------------------------------------------------------------
160 - def set_selections(self, selections = None):
161 self._LCTRL_items.set_selections(selections = selections)
162 #------------------------------------------------------------
163 - def set_data(self, data = None):
164 self._LCTRL_items.set_data(data = data)
165 #------------------------------------------------------------
166 - def get_selected_item_data(self, only_one=False):
167 return self._LCTRL_items.get_selected_item_data(only_one=only_one)
168 #------------------------------------------------------------ 169 # event handlers 170 #------------------------------------------------------------
171 - def _on_list_item_selected(self, event):
172 if not self.__ignore_OK_button: 173 self._BTN_ok.SetDefault() 174 self._BTN_ok.Enable(True) 175 176 if self.edit_callback is not None: 177 self._BTN_edit.Enable(True) 178 179 if self.delete_callback is not None: 180 self._BTN_delete.Enable(True)
181 #------------------------------------------------------------
182 - def _on_list_item_deselected(self, event):
183 if self._LCTRL_items.get_selected_items(only_one=True) == -1: 184 if not self.can_return_empty: 185 self._BTN_cancel.SetDefault() 186 self._BTN_ok.Enable(False) 187 self._BTN_edit.Enable(False) 188 self._BTN_delete.Enable(False)
189 #------------------------------------------------------------
190 - def _on_new_button_pressed(self, event):
191 if not self.new_callback(): 192 return 193 if self.refresh_callback is None: 194 return 195 wx.BeginBusyCursor() 196 try: 197 self.refresh_callback(lctrl = self._LCTRL_items) 198 finally: 199 wx.EndBusyCursor() 200 self._LCTRL_items.set_column_widths()
201 #------------------------------------------------------------
202 - def _on_edit_button_pressed(self, event):
203 # if the edit button *can* be pressed there are *supposed* 204 # to be both an item selected and an editor configured 205 if not self.edit_callback(self._LCTRL_items.get_selected_item_data(only_one=True)): 206 return 207 if self.refresh_callback is None: 208 return 209 wx.BeginBusyCursor() 210 try: 211 self.refresh_callback(lctrl = self._LCTRL_items) 212 finally: 213 wx.EndBusyCursor() 214 self._LCTRL_items.set_column_widths()
215 #------------------------------------------------------------
216 - def _on_delete_button_pressed(self, event):
217 # if the delete button *can* be pressed there are *supposed* 218 # to be both an item selected and a deletor configured 219 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 220 if item_data is None: 221 return 222 if not self.delete_callback(item_data): 223 return 224 if self.refresh_callback is None: 225 return 226 wx.BeginBusyCursor() 227 try: 228 self.refresh_callback(lctrl = self._LCTRL_items) 229 finally: 230 wx.EndBusyCursor() 231 self._LCTRL_items.set_column_widths()
232 #------------------------------------------------------------
233 - def _on_left_extra_button_pressed(self, event):
234 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 235 if not self.__left_extra_button_callback(item_data): 236 return 237 if self.refresh_callback is None: 238 return 239 wx.BeginBusyCursor() 240 try: 241 self.refresh_callback(lctrl = self._LCTRL_items) 242 finally: 243 wx.EndBusyCursor() 244 self._LCTRL_items.set_column_widths()
245 #------------------------------------------------------------
246 - def _on_middle_extra_button_pressed(self, event):
247 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 248 if not self.__middle_extra_button_callback(item_data): 249 return 250 if self.refresh_callback is None: 251 return 252 wx.BeginBusyCursor() 253 try: 254 self.refresh_callback(lctrl = self._LCTRL_items) 255 finally: 256 wx.EndBusyCursor() 257 self._LCTRL_items.set_column_widths()
258 #------------------------------------------------------------
259 - def _on_right_extra_button_pressed(self, event):
260 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 261 if not self.__right_extra_button_callback(item_data): 262 return 263 if self.refresh_callback is None: 264 return 265 wx.BeginBusyCursor() 266 try: 267 self.refresh_callback(lctrl = self._LCTRL_items) 268 finally: 269 wx.EndBusyCursor() 270 self._LCTRL_items.set_column_widths()
271 #------------------------------------------------------------ 272 # properties 273 #------------------------------------------------------------
274 - def _set_ignore_OK_button(self, ignored):
275 self.__ignore_OK_button = ignored 276 if self.__ignore_OK_button: 277 self._BTN_ok.Enable(False) 278 self._BTN_ok.Hide() 279 else: 280 self._BTN_ok.Enable(True) 281 self._BTN_ok.Show()
282 283 ignore_OK_button = property(lambda x:x, _set_ignore_OK_button) 284 #------------------------------------------------------------
285 - def _set_left_extra_button(self, definition):
286 if definition is None: 287 self._BTN_extra_left.Enable(False) 288 self._BTN_extra_left.Hide() 289 self.__left_extra_button_callback = None 290 return 291 292 (label, tooltip, callback) = definition 293 if not callable(callback): 294 raise ValueError('<left extra button> callback is not a callable: %s' % callback) 295 self.__left_extra_button_callback = callback 296 self._BTN_extra_left.SetLabel(label) 297 self._BTN_extra_left.SetToolTipString(tooltip) 298 self._BTN_extra_left.Enable(True) 299 self._BTN_extra_left.Show()
300 301 left_extra_button = property(lambda x:x, _set_left_extra_button) 302 #------------------------------------------------------------
303 - def _set_middle_extra_button(self, definition):
304 if definition is None: 305 self._BTN_extra_middle.Enable(False) 306 self._BTN_extra_middle.Hide() 307 self.__middle_extra_button_callback = None 308 return 309 310 (label, tooltip, callback) = definition 311 if not callable(callback): 312 raise ValueError('<middle extra button> callback is not a callable: %s' % callback) 313 self.__middle_extra_button_callback = callback 314 self._BTN_extra_middle.SetLabel(label) 315 self._BTN_extra_middle.SetToolTipString(tooltip) 316 self._BTN_extra_middle.Enable(True) 317 self._BTN_extra_middle.Show()
318 319 middle_extra_button = property(lambda x:x, _set_middle_extra_button) 320 #------------------------------------------------------------
321 - def _set_right_extra_button(self, definition):
322 if definition is None: 323 self._BTN_extra_right.Enable(False) 324 self._BTN_extra_right.Hide() 325 self.__right_extra_button_callback = None 326 return 327 328 (label, tooltip, callback) = definition 329 if not callable(callback): 330 raise ValueError('<right extra button> callback is not a callable: %s' % callback) 331 self.__right_extra_button_callback = callback 332 self._BTN_extra_right.SetLabel(label) 333 self._BTN_extra_right.SetToolTipString(tooltip) 334 self._BTN_extra_right.Enable(True) 335 self._BTN_extra_right.Show()
336 337 right_extra_button = property(lambda x:x, _set_right_extra_button) 338 #------------------------------------------------------------
339 - def _get_new_callback(self):
340 return self.__new_callback
341
342 - def _set_new_callback(self, callback):
343 if callback is not None: 344 if self.refresh_callback is None: 345 raise ValueError('refresh callback must be set before new callback can be set') 346 if not callable(callback): 347 raise ValueError('<new> callback is not a callable: %s' % callback) 348 self.__new_callback = callback 349 350 if callback is None: 351 self._BTN_new.Enable(False) 352 self._BTN_new.Hide() 353 else: 354 self._BTN_new.Enable(True) 355 self._BTN_new.Show()
356 357 new_callback = property(_get_new_callback, _set_new_callback) 358 #------------------------------------------------------------
359 - def _get_edit_callback(self):
360 return self.__edit_callback
361
362 - def _set_edit_callback(self, callback):
363 if callback is not None: 364 if not callable(callback): 365 raise ValueError('<edit> callback is not a callable: %s' % callback) 366 self.__edit_callback = callback 367 368 if callback is None: 369 self._BTN_edit.Enable(False) 370 self._BTN_edit.Hide() 371 else: 372 self._BTN_edit.Enable(True) 373 self._BTN_edit.Show()
374 375 edit_callback = property(_get_edit_callback, _set_edit_callback) 376 #------------------------------------------------------------
377 - def _get_delete_callback(self):
378 return self.__delete_callback
379
380 - def _set_delete_callback(self, callback):
381 if callback is not None: 382 if self.refresh_callback is None: 383 raise ValueError('refresh callback must be set before delete callback can be set') 384 if not callable(callback): 385 raise ValueError('<delete> callback is not a callable: %s' % callback) 386 self.__delete_callback = callback 387 388 if callback is None: 389 self._BTN_delete.Enable(False) 390 self._BTN_delete.Hide() 391 else: 392 self._BTN_delete.Enable(True) 393 self._BTN_delete.Show()
394 395 delete_callback = property(_get_delete_callback, _set_delete_callback) 396 #------------------------------------------------------------
397 - def _get_refresh_callback(self):
398 return self.__refresh_callback
399
401 wx.BeginBusyCursor() 402 try: 403 self.refresh_callback(lctrl = self._LCTRL_items) 404 finally: 405 wx.EndBusyCursor() 406 self._LCTRL_items.set_column_widths()
407
408 - def _set_refresh_callback(self, callback):
409 if callback is not None: 410 if not callable(callback): 411 raise ValueError('<refresh> callback is not a callable: %s' % callback) 412 self.__refresh_callback = callback 413 if callback is not None: 414 wx.CallAfter(self._set_refresh_callback_helper)
415 416 refresh_callback = property(_get_refresh_callback, _set_refresh_callback) 417 #------------------------------------------------------------
418 - def _set_list_tooltip_callback(self, callback):
419 self._LCTRL_items.item_tooltip_callback = callback
420 421 list_tooltip_callback = property(lambda x:x, _set_list_tooltip_callback) 422 #def _get_tooltip(self, item): # inside class 423 #def _get_tooltip(item): # outside class 424 #------------------------------------------------------------
425 - def _set_message(self, message):
426 if message is None: 427 self._LBL_message.Hide() 428 return 429 self._LBL_message.SetLabel(message) 430 self._LBL_message.Show()
431 432 message = property(lambda x:x, _set_message)
433 #================================================================
434 -class cGenericListManagerPnl(wxgGenericListManagerPnl.wxgGenericListManagerPnl):
435 """A panel holding a generic multi-column list and action buttions.""" 436
437 - def __init__(self, *args, **kwargs):
438 439 try: 440 msg = kwargs['msg'] 441 del kwargs['msg'] 442 except KeyError: msg = None 443 444 wxgGenericListManagerPnl.wxgGenericListManagerPnl.__init__(self, *args, **kwargs) 445 446 if msg is None: 447 self._LBL_message.Hide() 448 else: 449 self._LBL_message.SetLabel(msg) 450 451 # new/edit/delete must return True/False to enable refresh 452 self.__new_callback = None # called when NEW button pressed, no argument passed in 453 self.edit_callback = None # called when EDIT button pressed, data of topmost selected item passed in 454 self.delete_callback = None # called when DELETE button pressed, data of topmost selected item passed in 455 self.refresh_callback = None # called when new/edit/delete callbacks return True (IOW were not cancelled)
456 #------------------------------------------------------------ 457 # external API 458 #------------------------------------------------------------
459 - def set_columns(self, columns=None):
460 self._LCTRL_items.set_columns(columns = columns)
461 #------------------------------------------------------------
462 - def set_string_items(self, items = None):
463 self._LCTRL_items.set_string_items(items = items) 464 self._LCTRL_items.set_column_widths() 465 466 if (items is None) or (len(items) == 0): 467 self._BTN_edit.Enable(False) 468 self._BTN_remove.Enable(False) 469 else: 470 self._LCTRL_items.Select(0)
471 #------------------------------------------------------------
472 - def set_selections(self, selections = None):
473 self._LCTRL_items.set_selections(selections = selections)
474 #------------------------------------------------------------
475 - def set_data(self, data = None):
476 self._LCTRL_items.set_data(data = data)
477 #------------------------------------------------------------
478 - def get_selected_item_data(self, only_one=False):
479 return self._LCTRL_items.get_selected_item_data(only_one=only_one)
480 #------------------------------------------------------------ 481 # event handlers 482 #------------------------------------------------------------
483 - def _on_list_item_selected(self, event):
484 if self.edit_callback is not None: 485 self._BTN_edit.Enable(True) 486 if self.delete_callback is not None: 487 self._BTN_remove.Enable(True)
488 #------------------------------------------------------------
489 - def _on_list_item_deselected(self, event):
490 if self._LCTRL_items.get_selected_items(only_one=True) == -1: 491 self._BTN_edit.Enable(False) 492 self._BTN_remove.Enable(False)
493 #------------------------------------------------------------
494 - def _on_add_button_pressed(self, event):
495 if not self.new_callback(): 496 return 497 if self.refresh_callback is None: 498 return 499 wx.BeginBusyCursor() 500 try: 501 self.refresh_callback(lctrl = self._LCTRL_items) 502 finally: 503 wx.EndBusyCursor()
504 #------------------------------------------------------------
505 - def _on_edit_button_pressed(self, event):
506 item = self._LCTRL_items.get_selected_item_data(only_one=True) 507 if item is None: 508 return 509 if not self.edit_callback(item): 510 return 511 if self.refresh_callback is None: 512 return 513 wx.BeginBusyCursor() 514 try: 515 self.refresh_callback(lctrl = self._LCTRL_items) 516 finally: 517 wx.EndBusyCursor()
518 #------------------------------------------------------------
519 - def _on_remove_button_pressed(self, event):
520 item = self._LCTRL_items.get_selected_item_data(only_one=True) 521 if item is None: 522 return 523 if not self.delete_callback(item): 524 return 525 if self.refresh_callback is None: 526 return 527 wx.BeginBusyCursor() 528 try: 529 self.refresh_callback(lctrl = self._LCTRL_items) 530 finally: 531 wx.EndBusyCursor()
532 #------------------------------------------------------------ 533 # properties 534 #------------------------------------------------------------
535 - def _get_new_callback(self):
536 return self.__new_callback
537
538 - def _set_new_callback(self, callback):
539 self.__new_callback = callback 540 self._BTN_add.Enable(callback is not None)
541 542 new_callback = property(_get_new_callback, _set_new_callback)
543 #================================================================ 544 from Gnumed.wxGladeWidgets import wxgItemPickerDlg 545
546 -class cItemPickerDlg(wxgItemPickerDlg.wxgItemPickerDlg):
547
548 - def __init__(self, *args, **kwargs):
549 550 try: 551 msg = kwargs['msg'] 552 del kwargs['msg'] 553 except KeyError: 554 msg = None 555 556 wxgItemPickerDlg.wxgItemPickerDlg.__init__(self, *args, **kwargs) 557 558 if msg is None: 559 self._LBL_msg.Hide() 560 else: 561 self._LBL_msg.SetLabel(msg) 562 563 self._LCTRL_left.activate_callback = self.__pick_selected 564 #self._LCTRL_left.item_tooltip_callback = self.__on_get_item_tooltip 565 566 self._LCTRL_left.SetFocus()
567 #------------------------------------------------------------ 568 # external API 569 #------------------------------------------------------------
570 - def set_columns(self, columns=None, columns_right=None):
571 self._LCTRL_left.set_columns(columns = columns) 572 if columns_right is None: 573 self._LCTRL_right.set_columns(columns = columns) 574 else: 575 if len(columns_right) < len(columns): 576 cols = columns 577 else: 578 cols = columns_right[:len(columns)] 579 self._LCTRL_right.set_columns(columns = cols)
580 #------------------------------------------------------------
581 - def set_string_items(self, items = None):
582 self._LCTRL_left.set_string_items(items = items) 583 self._LCTRL_left.set_column_widths() 584 self._LCTRL_right.set_string_items() 585 586 self._BTN_left2right.Enable(False) 587 self._BTN_right2left.Enable(False)
588 #------------------------------------------------------------
589 - def set_selections(self, selections = None):
590 self._LCTRL_left.set_selections(selections = selections)
591 #------------------------------------------------------------
592 - def set_choices(self, choices=None, data=None):
593 self.set_string_items(items = choices) 594 if data is not None: 595 self.set_data(data = data)
596 #------------------------------------------------------------
597 - def set_picks(self, picks=None, data=None):
598 self._LCTRL_right.set_string_items(picks) 599 self._LCTRL_right.set_column_widths() 600 if data is not None: 601 self._LCTRL_right.set_data(data = data)
602 #------------------------------------------------------------
603 - def set_data(self, data = None):
604 self._LCTRL_left.set_data(data = data)
605 #------------------------------------------------------------
606 - def get_picks(self):
607 return self._LCTRL_right.get_item_data()
608 #------------------------------------------------------------ 609 # internal helpers 610 #------------------------------------------------------------
611 - def __pick_selected(self, event=None):
612 if self._LCTRL_left.get_selected_items(only_one = True) == -1: 613 return 614 615 right_items = self._LCTRL_right.get_string_items() 616 right_data = self._LCTRL_right.get_item_data() 617 618 right_items.extend(self._LCTRL_left.get_selected_string_items(only_one = False)) 619 self._LCTRL_right.set_string_items(items = right_items) 620 del right_items 621 622 if right_data is None: 623 self._LCTRL_right.set_data(data = self._LCTRL_left.get_selected_item_data(only_one = False)) 624 else: 625 right_data.extend(self._LCTRL_left.get_selected_item_data(only_one = False)) 626 self._LCTRL_right.set_data(data = right_data) 627 del right_data 628 629 self._LCTRL_right.set_column_widths()
630 #------------------------------------------------------------
631 - def __remove_selected_picks(self):
632 if self._LCTRL_right.get_selected_items(only_one = True) == -1: 633 return 634 635 for item_idx in self._LCTRL_right.get_selected_items(only_one = False): 636 self._LCTRL_right.remove_item(item_idx) 637 638 if self._LCTRL_right.GetItemCount() == 0: 639 self._BTN_right2left.Enable(False)
640 #------------------------------------------------------------ 641 # event handlers 642 #------------------------------------------------------------
643 - def _on_left_list_item_selected(self, event):
644 self._BTN_left2right.Enable(True)
645 #------------------------------------------------------------
646 - def _on_left_list_item_deselected(self, event):
647 if self._LCTRL_left.get_selected_items(only_one = True) == -1: 648 self._BTN_left2right.Enable(False)
649 #------------------------------------------------------------
650 - def _on_right_list_item_selected(self, event):
651 self._BTN_right2left.Enable(True)
652 #------------------------------------------------------------
653 - def _on_right_list_item_deselected(self, event):
654 if self._LCTRL_right.get_selected_items(only_one = True) == -1: 655 self._BTN_right2left.Enable(False)
656 #------------------------------------------------------------
657 - def _on_button_left2right_pressed(self, event):
658 self.__pick_selected()
659 #------------------------------------------------------------
660 - def _on_button_right2left_pressed(self, event):
661 self.__remove_selected_picks()
662 #================================================================
663 -class cReportListCtrl(wx.ListCtrl, listmixins.ListCtrlAutoWidthMixin):
664 665 # FIXME: searching by typing 666
667 - def __init__(self, *args, **kwargs):
668 669 try: 670 kwargs['style'] = kwargs['style'] | wx.LC_REPORT 671 except KeyError: 672 kwargs['style'] = wx.LC_REPORT 673 674 self.__is_single_selection = ((kwargs['style'] & wx.LC_SINGLE_SEL) == wx.LC_SINGLE_SEL) 675 676 wx.ListCtrl.__init__(self, *args, **kwargs) 677 listmixins.ListCtrlAutoWidthMixin.__init__(self) 678 679 self.__widths = None 680 self.__data = None 681 self.__activate_callback = None 682 683 self.Bind(wx.EVT_MOTION, self._on_mouse_motion) 684 self.__item_tooltip_callback = None 685 self.__tt_last_item = None 686 self.__tt_static_part = _("""Select the items you want to work on. 687 688 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.""")
689 #------------------------------------------------------------ 690 # setters 691 #------------------------------------------------------------
692 - def set_columns(self, columns=None):
693 """(Re)define the columns. 694 695 Note that this will (have to) delete the items. 696 """ 697 self.ClearAll() 698 self.__tt_last_item = None 699 if columns is None: 700 return 701 for idx in range(len(columns)): 702 self.InsertColumn(idx, columns[idx])
703 #------------------------------------------------------------
704 - def set_column_widths(self, widths=None):
705 """Set the column width policy. 706 707 widths = None: 708 use previous policy if any or default policy 709 widths != None: 710 use this policy and remember it for later calls 711 712 This means there is no way to *revert* to the default policy :-( 713 """ 714 # explicit policy ? 715 if widths is not None: 716 self.__widths = widths 717 for idx in range(len(self.__widths)): 718 self.SetColumnWidth(col = idx, width = self.__widths[idx]) 719 return 720 721 # previous policy ? 722 if self.__widths is not None: 723 for idx in range(len(self.__widths)): 724 self.SetColumnWidth(col = idx, width = self.__widths[idx]) 725 return 726 727 # default policy ! 728 if self.GetItemCount() == 0: 729 width_type = wx.LIST_AUTOSIZE_USEHEADER 730 else: 731 width_type = wx.LIST_AUTOSIZE 732 for idx in range(self.GetColumnCount()): 733 self.SetColumnWidth(col = idx, width = width_type)
734 #------------------------------------------------------------
735 - def set_string_items(self, items = None):
736 """All item members must be unicode()able or None.""" 737 738 self.DeleteAllItems() 739 self.__data = items 740 self.__tt_last_item = None 741 742 if items is None: 743 return 744 745 for item in items: 746 try: 747 item[0] 748 if not isinstance(item, basestring): 749 is_numerically_iterable = True 750 else: 751 is_numerically_iterable = False 752 except TypeError: 753 is_numerically_iterable = False 754 755 if is_numerically_iterable: 756 # cannot use errors='replace' since then 757 # None/ints/unicode strings fail to get encoded 758 col_val = unicode(item[0]) 759 row_num = self.InsertStringItem(index = sys.maxint, label = col_val) 760 for col_idx in range(1, min(self.GetColumnCount(), len(item))): 761 col_val = unicode(item[col_idx]) 762 self.SetStringItem(index = row_num, col = col_idx, label = col_val) 763 else: 764 # cannot use errors='replace' since then None/ints/unicode strings fails to get encoded 765 col_val = unicode(item) 766 row_num = self.InsertStringItem(index = sys.maxint, label = col_val)
767 #------------------------------------------------------------
768 - def set_data(self, data = None):
769 """<data must be a list corresponding to the item indices>""" 770 self.__data = data 771 self.__tt_last_item = None
772 #------------------------------------------------------------
773 - def set_selections(self, selections=None):
774 self.Select(0, on = 0) 775 for idx in selections: 776 self.Select(idx = idx, on = 1)
777 #self.SetItemState(idx, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) 778 #------------------------------------------------------------ 779 # getters 780 #------------------------------------------------------------
781 - def get_column_labels(self):
782 labels = [] 783 for col_idx in self.GetColumnCount(): 784 col = self.GetColumn(col = col_idx) 785 labels.append(col.GetText()) 786 return labels
787 #------------------------------------------------------------
788 - def get_item(self, item_idx=None):
789 if item_idx is not None: 790 return self.GetItem(item_idx)
791 #------------------------------------------------------------
792 - def get_items(self):
793 return [ self.GetItem(item_idx) for item_idx in range(self.GetItemCount()) ]
794 #------------------------------------------------------------
795 - def get_string_items(self):
796 return [ self.GetItemText(item_idx) for item_idx in range(self.GetItemCount()) ]
797 #------------------------------------------------------------
798 - def get_selected_items(self, only_one=False):
799 800 if self.__is_single_selection or only_one: 801 return self.GetFirstSelected() 802 803 items = [] 804 idx = self.GetFirstSelected() 805 while idx != -1: 806 items.append(idx) 807 idx = self.GetNextSelected(idx) 808 809 return items
810 #------------------------------------------------------------
811 - def get_selected_string_items(self, only_one=False):
812 813 if self.__is_single_selection or only_one: 814 return self.GetItemText(self.GetFirstSelected()) 815 816 items = [] 817 idx = self.GetFirstSelected() 818 while idx != -1: 819 items.append(self.GetItemText(idx)) 820 idx = self.GetNextSelected(idx) 821 822 return items
823 #------------------------------------------------------------
824 - def get_item_data(self, item_idx = None):
825 if self.__data is None: # this isn't entirely clean 826 return None 827 828 if item_idx is not None: 829 return self.__data[item_idx] 830 831 return [ self.__data[item_idx] for item_idx in range(self.GetItemCount()) ]
832 #------------------------------------------------------------
833 - def get_selected_item_data(self, only_one=False):
834 835 if self.__is_single_selection or only_one: 836 if self.__data is None: 837 return None 838 idx = self.GetFirstSelected() 839 if idx == -1: 840 return None 841 return self.__data[idx] 842 843 data = [] 844 if self.__data is None: 845 return data 846 idx = self.GetFirstSelected() 847 while idx != -1: 848 data.append(self.__data[idx]) 849 idx = self.GetNextSelected(idx) 850 851 return data
852 #------------------------------------------------------------
853 - def deselect_selected_item(self):
854 self.Select(idx = self.GetFirstSelected(), on = 0)
855 #------------------------------------------------------------
856 - def remove_item(self, item_idx=None):
857 self.DeleteItem(item_idx) 858 if self.__data is not None: 859 del self.__data[item_idx] 860 self.__tt_last_item = None
861 #------------------------------------------------------------ 862 # event handlers 863 #------------------------------------------------------------
864 - def _on_list_item_activated(self, event):
865 event.Skip() 866 if self.__activate_callback is not None: 867 self.__activate_callback(event)
868 #------------------------------------------------------------
869 - def _on_mouse_motion(self, event):
870 item_idx, where = self.HitTest(wx.Point(event.X, event.Y)) 871 872 if self.__tt_last_item == item_idx: 873 return 874 875 self.__tt_last_item = item_idx 876 877 if item_idx == -1: 878 self.SetToolTipString(self.__tt_static_part) 879 return 880 881 dyna_tt = None 882 if self.__item_tooltip_callback is not None: 883 dyna_tt = self.__item_tooltip_callback(self.__data[item_idx]) 884 885 if dyna_tt is None: 886 self.SetToolTipString(self.__tt_static_part) 887 return 888 889 self.SetToolTipString(dyna_tt)
890 #------------------------------------------------------------ 891 # properties 892 #------------------------------------------------------------
893 - def _get_activate_callback(self):
894 return self.__activate_callback
895
896 - def _set_activate_callback(self, callback):
897 if callback is None: 898 self.Unbind(wx.EVT_LIST_ITEM_ACTIVATED) 899 else: 900 if not callable(callback): 901 raise ValueError('<activate> callback is not a callable: %s' % callback) 902 self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self._on_list_item_activated) 903 self.__activate_callback = callback
904 905 activate_callback = property(_get_activate_callback, _set_activate_callback) 906 #------------------------------------------------------------
907 - def _set_item_tooltip_callback(self, callback):
908 if callback is not None: 909 if not callable(callback): 910 raise ValueError('<item_tooltip> callback is not a callable: %s' % callback) 911 self.__item_tooltip_callback = callback
912 913 item_tooltip_callback = property(lambda x:x, _set_item_tooltip_callback)
914 #================================================================ 915 # main 916 #---------------------------------------------------------------- 917 if __name__ == '__main__': 918 919 if len(sys.argv) < 2: 920 sys.exit() 921 922 if sys.argv[1] != 'test': 923 sys.exit() 924 925 from Gnumed.pycommon import gmI18N 926 gmI18N.activate_locale() 927 gmI18N.install_domain() 928 929 #------------------------------------------------------------
930 - def test_wxMultiChoiceDialog():
931 app = wx.PyWidgetTester(size = (400, 500)) 932 dlg = wx.MultiChoiceDialog ( 933 parent = None, 934 message = 'test message', 935 caption = 'test caption', 936 choices = ['a', 'b', 'c', 'd', 'e'] 937 ) 938 dlg.ShowModal() 939 sels = dlg.GetSelections() 940 print "selected:" 941 for sel in sels: 942 print sel
943 #------------------------------------------------------------
944 - def test_get_choices_from_list():
945 946 def edit(argument): 947 print "editor called with:" 948 print argument
949 950 def refresh(lctrl): 951 choices = ['a', 'b', 'c'] 952 lctrl.set_string_items(choices) 953 954 app = wx.PyWidgetTester(size = (200, 50)) 955 chosen = get_choices_from_list ( 956 # msg = 'select a health issue\nfrom the list below\n', 957 caption = 'select health issues', 958 #choices = [['D.M.II', '4'], ['MS', '3'], ['Fraktur', '2']], 959 #columns = ['issue', 'no of episodes'] 960 columns = ['issue'], 961 refresh_callback = refresh 962 #, edit_callback = edit 963 ) 964 print "chosen:" 965 print chosen 966 #------------------------------------------------------------
967 - def test_item_picker_dlg():
968 app = wx.PyWidgetTester(size = (200, 50)) 969 dlg = cItemPickerDlg(None, -1, msg = 'Pick a few items:') 970 dlg.set_columns(['Plugins'], ['Load in workplace', 'dummy']) 971 #dlg.set_columns(['Plugins'], []) 972 dlg.set_string_items(['patient', 'emr', 'docs']) 973 result = dlg.ShowModal() 974 print result 975 print dlg.get_picks()
976 #------------------------------------------------------------ 977 #test_get_choices_from_list() 978 #test_wxMultiChoiceDialog() 979 test_item_picker_dlg() 980 981 #================================================================ 982 # 983