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 if msg is None: 135 self._LBL_message.Hide() 136 else: 137 self._LBL_message.SetLabel(msg) 138 139 self.left_extra_button = None 140 self.middle_extra_button = None 141 self.right_extra_button = None 142 143 self.refresh_callback = None # called when new/edit/delete callbacks return True (IOW were not cancelled) 144 self.new_callback = None # called when NEW button pressed, no argument passed in 145 self.edit_callback = None # called when EDIT button pressed, data of topmost selected item passed in 146 self.delete_callback = None # called when DELETE button pressed, data of topmost selected item passed in 147 148 self.ignore_OK_button = False # by default do show/use the OK button 149 150 self.can_return_empty = False
151 #------------------------------------------------------------
152 - def set_columns(self, columns=None):
153 self._LCTRL_items.set_columns(columns = columns)
154 #------------------------------------------------------------
155 - def set_column_widths(self, widths=None):
156 self._LCTRL_items.set_column_widths(widths = widths)
157 #------------------------------------------------------------
158 - def set_string_items(self, items = None):
159 self._LCTRL_items.set_string_items(items = items) 160 self._LCTRL_items.set_column_widths() 161 self._LCTRL_items.Select(0)
162 #------------------------------------------------------------
163 - def set_selections(self, selections = None):
164 self._LCTRL_items.set_selections(selections = selections)
165 #------------------------------------------------------------
166 - def set_data(self, data = None):
167 self._LCTRL_items.set_data(data = data)
168 #------------------------------------------------------------
169 - def get_selected_item_data(self, only_one=False):
170 return self._LCTRL_items.get_selected_item_data(only_one=only_one)
171 #------------------------------------------------------------ 172 # event handlers 173 #------------------------------------------------------------
174 - def _on_list_item_selected(self, event):
175 if not self.__ignore_OK_button: 176 self._BTN_ok.SetDefault() 177 self._BTN_ok.Enable(True) 178 179 if self.edit_callback is not None: 180 self._BTN_edit.Enable(True) 181 182 if self.delete_callback is not None: 183 self._BTN_delete.Enable(True)
184 #------------------------------------------------------------
185 - def _on_list_item_deselected(self, event):
186 if self._LCTRL_items.get_selected_items(only_one=True) == -1: 187 if not self.can_return_empty: 188 self._BTN_cancel.SetDefault() 189 self._BTN_ok.Enable(False) 190 self._BTN_edit.Enable(False) 191 self._BTN_delete.Enable(False)
192 #------------------------------------------------------------
193 - def _on_new_button_pressed(self, event):
194 if not self.new_callback(): 195 return 196 if self.refresh_callback is None: 197 return 198 wx.BeginBusyCursor() 199 try: 200 self.refresh_callback(lctrl = self._LCTRL_items) 201 finally: 202 wx.EndBusyCursor() 203 self._LCTRL_items.set_column_widths()
204 #------------------------------------------------------------
205 - def _on_edit_button_pressed(self, event):
206 # if the edit button *can* be pressed there are *supposed* 207 # to be both an item selected and an editor configured 208 if not self.edit_callback(self._LCTRL_items.get_selected_item_data(only_one=True)): 209 return 210 if self.refresh_callback is None: 211 return 212 wx.BeginBusyCursor() 213 try: 214 self.refresh_callback(lctrl = self._LCTRL_items) 215 finally: 216 wx.EndBusyCursor() 217 self._LCTRL_items.set_column_widths()
218 #------------------------------------------------------------
219 - def _on_delete_button_pressed(self, event):
220 # if the delete button *can* be pressed there are *supposed* 221 # to be both an item selected and a deletor configured 222 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 223 if item_data is None: 224 return 225 if not self.delete_callback(item_data): 226 return 227 if self.refresh_callback is None: 228 return 229 wx.BeginBusyCursor() 230 try: 231 self.refresh_callback(lctrl = self._LCTRL_items) 232 finally: 233 wx.EndBusyCursor() 234 self._LCTRL_items.set_column_widths()
235 #------------------------------------------------------------
236 - def _on_left_extra_button_pressed(self, event):
237 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 238 if not self.__left_extra_button_callback(item_data): 239 return 240 if self.refresh_callback is None: 241 return 242 wx.BeginBusyCursor() 243 try: 244 self.refresh_callback(lctrl = self._LCTRL_items) 245 finally: 246 wx.EndBusyCursor() 247 self._LCTRL_items.set_column_widths()
248 #------------------------------------------------------------
249 - def _on_middle_extra_button_pressed(self, event):
250 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 251 if not self.__middle_extra_button_callback(item_data): 252 return 253 if self.refresh_callback is None: 254 return 255 wx.BeginBusyCursor() 256 try: 257 self.refresh_callback(lctrl = self._LCTRL_items) 258 finally: 259 wx.EndBusyCursor() 260 self._LCTRL_items.set_column_widths()
261 #------------------------------------------------------------
262 - def _on_right_extra_button_pressed(self, event):
263 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 264 if not self.__right_extra_button_callback(item_data): 265 return 266 if self.refresh_callback is None: 267 return 268 wx.BeginBusyCursor() 269 try: 270 self.refresh_callback(lctrl = self._LCTRL_items) 271 finally: 272 wx.EndBusyCursor() 273 self._LCTRL_items.set_column_widths()
274 #------------------------------------------------------------ 275 # properties 276 #------------------------------------------------------------
277 - def _set_ignore_OK_button(self, ignored):
278 self.__ignore_OK_button = ignored 279 if self.__ignore_OK_button: 280 self._BTN_ok.Enable(False) 281 self._BTN_ok.Hide() 282 else: 283 self._BTN_ok.Enable(True) 284 self._BTN_ok.Show()
285 286 ignore_OK_button = property(lambda x:x, _set_ignore_OK_button) 287 #------------------------------------------------------------
288 - def _set_left_extra_button(self, definition):
289 if definition is None: 290 self._BTN_extra_left.Enable(False) 291 self._BTN_extra_left.Hide() 292 return 293 294 (label, tooltip, callback) = definition 295 if not callable(callback): 296 raise ValueError('<left extra button> callback is not a callable: %s' % callback) 297 self.__left_extra_button_callback = callback 298 self._BTN_extra_left.SetLabel(label) 299 self._BTN_extra_left.SetToolTipString(tooltip) 300 self._BTN_extra_left.Enable(True) 301 self._BTN_extra_left.Show()
302 303 left_extra_button = property(lambda x:x, _set_left_extra_button) 304 #------------------------------------------------------------
305 - def _set_middle_extra_button(self, definition):
306 if definition is None: 307 self._BTN_extra_middle.Enable(False) 308 self._BTN_extra_middle.Hide() 309 return 310 311 (label, tooltip, callback) = definition 312 if not callable(callback): 313 raise ValueError('<middle extra button> callback is not a callable: %s' % callback) 314 self.__middle_extra_button_callback = callback 315 self._BTN_extra_middle.SetLabel(label) 316 self._BTN_extra_middle.SetToolTipString(tooltip) 317 self._BTN_extra_middle.Enable(True) 318 self._BTN_extra_middle.Show()
319 320 middle_extra_button = property(lambda x:x, _set_middle_extra_button) 321 #------------------------------------------------------------
322 - def _set_right_extra_button(self, definition):
323 if definition is None: 324 self._BTN_extra_right.Enable(False) 325 self._BTN_extra_right.Hide() 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 #================================================================
423 -class cGenericListManagerPnl(wxgGenericListManagerPnl.wxgGenericListManagerPnl):
424 """A panel holding a generic multi-column list and action buttions.""" 425
426 - def __init__(self, *args, **kwargs):
427 428 try: 429 msg = kwargs['msg'] 430 del kwargs['msg'] 431 except KeyError: msg = None 432 433 wxgGenericListManagerPnl.wxgGenericListManagerPnl.__init__(self, *args, **kwargs) 434 435 if msg is None: 436 self._LBL_message.Hide() 437 else: 438 self._LBL_message.SetLabel(msg) 439 440 # new/edit/delete must return True/False to enable refresh 441 self.__new_callback = None # called when NEW button pressed, no argument passed in 442 self.edit_callback = None # called when EDIT button pressed, data of topmost selected item passed in 443 self.delete_callback = None # called when DELETE button pressed, data of topmost selected item passed in 444 self.refresh_callback = None # called when new/edit/delete callbacks return True (IOW were not cancelled)
445 #------------------------------------------------------------ 446 # external API 447 #------------------------------------------------------------
448 - def set_columns(self, columns=None):
449 self._LCTRL_items.set_columns(columns = columns)
450 #------------------------------------------------------------
451 - def set_string_items(self, items = None):
452 self._LCTRL_items.set_string_items(items = items) 453 self._LCTRL_items.set_column_widths() 454 455 if (items is None) or (len(items) == 0): 456 self._BTN_edit.Enable(False) 457 self._BTN_remove.Enable(False) 458 else: 459 self._LCTRL_items.Select(0)
460 #------------------------------------------------------------
461 - def set_selections(self, selections = None):
462 self._LCTRL_items.set_selections(selections = selections)
463 #------------------------------------------------------------
464 - def set_data(self, data = None):
465 self._LCTRL_items.set_data(data = data)
466 #------------------------------------------------------------
467 - def get_selected_item_data(self, only_one=False):
468 return self._LCTRL_items.get_selected_item_data(only_one=only_one)
469 #------------------------------------------------------------ 470 # event handlers 471 #------------------------------------------------------------
472 - def _on_list_item_selected(self, event):
473 if self.edit_callback is not None: 474 self._BTN_edit.Enable(True) 475 if self.delete_callback is not None: 476 self._BTN_remove.Enable(True)
477 #------------------------------------------------------------
478 - def _on_list_item_deselected(self, event):
479 if self._LCTRL_items.get_selected_items(only_one=True) == -1: 480 self._BTN_edit.Enable(False) 481 self._BTN_remove.Enable(False)
482 #------------------------------------------------------------
483 - def _on_add_button_pressed(self, event):
484 if not self.new_callback(): 485 return 486 if self.refresh_callback is None: 487 return 488 wx.BeginBusyCursor() 489 try: 490 self.refresh_callback(lctrl = self._LCTRL_items) 491 finally: 492 wx.EndBusyCursor()
493 #------------------------------------------------------------
494 - def _on_edit_button_pressed(self, event):
495 item = self._LCTRL_items.get_selected_item_data(only_one=True) 496 if item is None: 497 return 498 if not self.edit_callback(item): 499 return 500 if self.refresh_callback is None: 501 return 502 wx.BeginBusyCursor() 503 try: 504 self.refresh_callback(lctrl = self._LCTRL_items) 505 finally: 506 wx.EndBusyCursor()
507 #------------------------------------------------------------
508 - def _on_remove_button_pressed(self, event):
509 item = self._LCTRL_items.get_selected_item_data(only_one=True) 510 if item is None: 511 return 512 if not self.delete_callback(item): 513 return 514 if self.refresh_callback is None: 515 return 516 wx.BeginBusyCursor() 517 try: 518 self.refresh_callback(lctrl = self._LCTRL_items) 519 finally: 520 wx.EndBusyCursor()
521 #------------------------------------------------------------ 522 # properties 523 #------------------------------------------------------------
524 - def _get_new_callback(self):
525 return self.__new_callback
526
527 - def _set_new_callback(self, callback):
528 self.__new_callback = callback 529 self._BTN_add.Enable(callback is not None)
530 531 new_callback = property(_get_new_callback, _set_new_callback)
532 #================================================================ 533 from Gnumed.wxGladeWidgets import wxgItemPickerDlg 534
535 -class cItemPickerDlg(wxgItemPickerDlg.wxgItemPickerDlg):
536
537 - def __init__(self, *args, **kwargs):
538 539 try: 540 msg = kwargs['msg'] 541 del kwargs['msg'] 542 except KeyError: 543 msg = None 544 545 wxgItemPickerDlg.wxgItemPickerDlg.__init__(self, *args, **kwargs) 546 547 if msg is None: 548 self._LBL_msg.Hide() 549 else: 550 self._LBL_msg.SetLabel(msg) 551 552 self._LCTRL_left.activate_callback = self.__pick_selected 553 #self._LCTRL_left.item_tooltip_callback = self.__on_get_item_tooltip 554 555 self._LCTRL_left.SetFocus()
556 #------------------------------------------------------------ 557 # external API 558 #------------------------------------------------------------
559 - def set_columns(self, columns=None, columns_right=None):
560 self._LCTRL_left.set_columns(columns = columns) 561 if columns_right is None: 562 self._LCTRL_right.set_columns(columns = columns) 563 else: 564 if len(columns_right) < len(columns): 565 cols = columns 566 else: 567 cols = columns_right[:len(columns)] 568 self._LCTRL_right.set_columns(columns = cols)
569 #------------------------------------------------------------
570 - def set_string_items(self, items = None):
571 self._LCTRL_left.set_string_items(items = items) 572 self._LCTRL_left.set_column_widths() 573 self._LCTRL_right.set_string_items() 574 575 self._BTN_left2right.Enable(False) 576 self._BTN_right2left.Enable(False)
577 #------------------------------------------------------------
578 - def set_selections(self, selections = None):
579 self._LCTRL_left.set_selections(selections = selections)
580 #------------------------------------------------------------
581 - def set_choices(self, choices=None, data=None):
582 self.set_string_items(items = choices) 583 if data is not None: 584 self.set_data(data = data)
585 #------------------------------------------------------------
586 - def set_picks(self, picks=None, data=None):
587 self._LCTRL_right.set_string_items(picks) 588 self._LCTRL_right.set_column_widths() 589 if data is not None: 590 self._LCTRL_right.set_data(data = data)
591 #------------------------------------------------------------
592 - def set_data(self, data = None):
593 self._LCTRL_left.set_data(data = data)
594 #------------------------------------------------------------
595 - def get_picks(self):
596 return self._LCTRL_right.get_item_data()
597 #------------------------------------------------------------ 598 # internal helpers 599 #------------------------------------------------------------
600 - def __pick_selected(self, event=None):
601 if self._LCTRL_left.get_selected_items(only_one = True) == -1: 602 return 603 604 right_items = self._LCTRL_right.get_string_items() 605 right_data = self._LCTRL_right.get_item_data() 606 607 right_items.extend(self._LCTRL_left.get_selected_string_items(only_one = False)) 608 self._LCTRL_right.set_string_items(items = right_items) 609 del right_items 610 611 if right_data is None: 612 self._LCTRL_right.set_data(data = self._LCTRL_left.get_selected_item_data(only_one = False)) 613 else: 614 right_data.extend(self._LCTRL_left.get_selected_item_data(only_one = False)) 615 self._LCTRL_right.set_data(data = right_data) 616 del right_data 617 618 self._LCTRL_right.set_column_widths()
619 #------------------------------------------------------------
620 - def __remove_selected_picks(self):
621 if self._LCTRL_right.get_selected_items(only_one = True) == -1: 622 return 623 624 for item_idx in self._LCTRL_right.get_selected_items(only_one = False): 625 self._LCTRL_right.remove_item(item_idx) 626 627 if self._LCTRL_right.GetItemCount() == 0: 628 self._BTN_right2left.Enable(False)
629 #------------------------------------------------------------ 630 # event handlers 631 #------------------------------------------------------------
632 - def _on_left_list_item_selected(self, event):
633 self._BTN_left2right.Enable(True)
634 #------------------------------------------------------------
635 - def _on_left_list_item_deselected(self, event):
636 if self._LCTRL_left.get_selected_items(only_one = True) == -1: 637 self._BTN_left2right.Enable(False)
638 #------------------------------------------------------------
639 - def _on_right_list_item_selected(self, event):
640 self._BTN_right2left.Enable(True)
641 #------------------------------------------------------------
642 - def _on_right_list_item_deselected(self, event):
643 if self._LCTRL_right.get_selected_items(only_one = True) == -1: 644 self._BTN_right2left.Enable(False)
645 #------------------------------------------------------------
646 - def _on_button_left2right_pressed(self, event):
647 self.__pick_selected()
648 #------------------------------------------------------------
649 - def _on_button_right2left_pressed(self, event):
650 self.__remove_selected_picks()
651 #================================================================
652 -class cReportListCtrl(wx.ListCtrl, listmixins.ListCtrlAutoWidthMixin):
653 654 # FIXME: searching by typing 655
656 - def __init__(self, *args, **kwargs):
657 658 try: 659 kwargs['style'] = kwargs['style'] | wx.LC_REPORT 660 except KeyError: 661 kwargs['style'] = wx.LC_REPORT 662 663 self.__is_single_selection = ((kwargs['style'] & wx.LC_SINGLE_SEL) == wx.LC_SINGLE_SEL) 664 665 wx.ListCtrl.__init__(self, *args, **kwargs) 666 listmixins.ListCtrlAutoWidthMixin.__init__(self) 667 668 self.__widths = None 669 self.__data = None 670 self.__activate_callback = None 671 672 self.Bind(wx.EVT_MOTION, self._on_mouse_motion) 673 self.__item_tooltip_callback = None 674 self.__tt_last_item = None 675 self.__tt_static_part = _("""Select the items you want to work on. 676 677 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.""")
678 #------------------------------------------------------------ 679 # setters 680 #------------------------------------------------------------
681 - def set_columns(self, columns=None):
682 """(Re)define the columns. 683 684 Note that this will (have to) delete the items. 685 """ 686 self.ClearAll() 687 self.__tt_last_item = None 688 if columns is None: 689 return 690 for idx in range(len(columns)): 691 self.InsertColumn(idx, columns[idx])
692 #------------------------------------------------------------
693 - def set_column_widths(self, widths=None):
694 """Set the column width policy. 695 696 widths = None: 697 use previous policy if any or default policy 698 widths != None: 699 use this policy and remember it for later calls 700 701 This means there is no way to *revert* to the default policy :-( 702 """ 703 # explicit policy ? 704 if widths is not None: 705 self.__widths = widths 706 for idx in range(len(self.__widths)): 707 self.SetColumnWidth(col = idx, width = self.__widths[idx]) 708 return 709 710 # previous policy ? 711 if self.__widths is not None: 712 for idx in range(len(self.__widths)): 713 self.SetColumnWidth(col = idx, width = self.__widths[idx]) 714 return 715 716 # default policy ! 717 if self.GetItemCount() == 0: 718 width_type = wx.LIST_AUTOSIZE_USEHEADER 719 else: 720 width_type = wx.LIST_AUTOSIZE 721 for idx in range(self.GetColumnCount()): 722 self.SetColumnWidth(col = idx, width = width_type)
723 #------------------------------------------------------------
724 - def set_string_items(self, items = None):
725 """All item members must be unicode()able or None.""" 726 727 self.DeleteAllItems() 728 self.__data = items 729 self.__tt_last_item = None 730 731 if items is None: 732 return 733 734 for item in items: 735 try: 736 item[0] 737 if not isinstance(item, basestring): 738 is_numerically_iterable = True 739 else: 740 is_numerically_iterable = False 741 except TypeError: 742 is_numerically_iterable = False 743 744 if is_numerically_iterable: 745 # cannot use errors='replace' since then 746 # None/ints/unicode strings fail to get encoded 747 col_val = unicode(item[0]) 748 row_num = self.InsertStringItem(index = sys.maxint, label = col_val) 749 for col_idx in range(1, min(self.GetColumnCount(), len(item))): 750 col_val = unicode(item[col_idx]) 751 self.SetStringItem(index = row_num, col = col_idx, label = col_val) 752 else: 753 # cannot use errors='replace' since then None/ints/unicode strings fails to get encoded 754 col_val = unicode(item) 755 row_num = self.InsertStringItem(index = sys.maxint, label = col_val)
756 #------------------------------------------------------------
757 - def set_data(self, data = None):
758 """<data must be a list corresponding to the item indices>""" 759 self.__data = data 760 self.__tt_last_item = None
761 #------------------------------------------------------------
762 - def set_selections(self, selections=None):
763 self.Select(0, on = 0) 764 for idx in selections: 765 self.Select(idx = idx, on = 1)
766 #self.SetItemState(idx, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) 767 #------------------------------------------------------------ 768 # getters 769 #------------------------------------------------------------
770 - def get_column_labels(self):
771 labels = [] 772 for col_idx in self.GetColumnCount(): 773 col = self.GetColumn(col = col_idx) 774 labels.append(col.GetText()) 775 return labels
776 #------------------------------------------------------------
777 - def get_item(self, item_idx=None):
778 if item_idx is not None: 779 return self.GetItem(item_idx)
780 #------------------------------------------------------------
781 - def get_items(self):
782 return [ self.GetItem(item_idx) for item_idx in range(self.GetItemCount()) ]
783 #------------------------------------------------------------
784 - def get_string_items(self):
785 return [ self.GetItemText(item_idx) for item_idx in range(self.GetItemCount()) ]
786 #------------------------------------------------------------
787 - def get_selected_items(self, only_one=False):
788 789 if self.__is_single_selection or only_one: 790 return self.GetFirstSelected() 791 792 items = [] 793 idx = self.GetFirstSelected() 794 while idx != -1: 795 items.append(idx) 796 idx = self.GetNextSelected(idx) 797 798 return items
799 #------------------------------------------------------------
800 - def get_selected_string_items(self, only_one=False):
801 802 if self.__is_single_selection or only_one: 803 return self.GetItemText(self.GetFirstSelected()) 804 805 items = [] 806 idx = self.GetFirstSelected() 807 while idx != -1: 808 items.append(self.GetItemText(idx)) 809 idx = self.GetNextSelected(idx) 810 811 return items
812 #------------------------------------------------------------
813 - def get_item_data(self, item_idx = None):
814 if self.__data is None: # this isn't entirely clean 815 return None 816 817 if item_idx is not None: 818 return self.__data[item_idx] 819 820 return [ self.__data[item_idx] for item_idx in range(self.GetItemCount()) ]
821 #------------------------------------------------------------
822 - def get_selected_item_data(self, only_one=False):
823 824 if self.__is_single_selection or only_one: 825 if self.__data is None: 826 return None 827 idx = self.GetFirstSelected() 828 if idx == -1: 829 return None 830 return self.__data[idx] 831 832 data = [] 833 if self.__data is None: 834 return data 835 idx = self.GetFirstSelected() 836 while idx != -1: 837 data.append(self.__data[idx]) 838 idx = self.GetNextSelected(idx) 839 840 return data
841 #------------------------------------------------------------
842 - def deselect_selected_item(self):
843 self.Select(idx = self.GetFirstSelected(), on = 0)
844 #------------------------------------------------------------
845 - def remove_item(self, item_idx=None):
846 self.DeleteItem(item_idx) 847 if self.__data is not None: 848 del self.__data[item_idx] 849 self.__tt_last_item = None
850 #------------------------------------------------------------ 851 # event handlers 852 #------------------------------------------------------------
853 - def _on_list_item_activated(self, event):
854 event.Skip() 855 if self.__activate_callback is not None: 856 self.__activate_callback(event)
857 #------------------------------------------------------------
858 - def _on_mouse_motion(self, event):
859 item_idx, where = self.HitTest(wx.Point(event.X, event.Y)) 860 861 if self.__tt_last_item == item_idx: 862 return 863 864 self.__tt_last_item = item_idx 865 866 if item_idx == -1: 867 self.SetToolTipString(self.__tt_static_part) 868 return 869 870 dyna_tt = None 871 if self.__item_tooltip_callback is not None: 872 dyna_tt = self.__item_tooltip_callback(self.__data[item_idx]) 873 874 if dyna_tt is None: 875 self.SetToolTipString(self.__tt_static_part) 876 return 877 878 self.SetToolTipString(dyna_tt)
879 #------------------------------------------------------------ 880 # properties 881 #------------------------------------------------------------
882 - def _get_activate_callback(self):
883 return self.__activate_callback
884
885 - def _set_activate_callback(self, callback):
886 if callback is None: 887 self.Unbind(wx.EVT_LIST_ITEM_ACTIVATED) 888 else: 889 if not callable(callback): 890 raise ValueError('<activate> callback is not a callable: %s' % callback) 891 self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self._on_list_item_activated) 892 self.__activate_callback = callback
893 894 activate_callback = property(_get_activate_callback, _set_activate_callback) 895 #------------------------------------------------------------
896 - def _set_item_tooltip_callback(self, callback):
897 if callback is not None: 898 if not callable(callback): 899 raise ValueError('<item_tooltip> callback is not a callable: %s' % callback) 900 self.__item_tooltip_callback = callback
901 902 item_tooltip_callback = property(lambda x:x, _set_item_tooltip_callback)
903 #================================================================ 904 # main 905 #---------------------------------------------------------------- 906 if __name__ == '__main__': 907 908 if len(sys.argv) < 2: 909 sys.exit() 910 911 if sys.argv[1] != 'test': 912 sys.exit() 913 914 from Gnumed.pycommon import gmI18N 915 gmI18N.activate_locale() 916 gmI18N.install_domain() 917 918 #------------------------------------------------------------
919 - def test_wxMultiChoiceDialog():
920 app = wx.PyWidgetTester(size = (400, 500)) 921 dlg = wx.MultiChoiceDialog ( 922 parent = None, 923 message = 'test message', 924 caption = 'test caption', 925 choices = ['a', 'b', 'c', 'd', 'e'] 926 ) 927 dlg.ShowModal() 928 sels = dlg.GetSelections() 929 print "selected:" 930 for sel in sels: 931 print sel
932 #------------------------------------------------------------
933 - def test_get_choices_from_list():
934 935 def edit(argument): 936 print "editor called with:" 937 print argument
938 939 def refresh(lctrl): 940 choices = ['a', 'b', 'c'] 941 lctrl.set_string_items(choices) 942 943 app = wx.PyWidgetTester(size = (200, 50)) 944 chosen = get_choices_from_list ( 945 # msg = 'select a health issue\nfrom the list below\n', 946 caption = 'select health issues', 947 #choices = [['D.M.II', '4'], ['MS', '3'], ['Fraktur', '2']], 948 #columns = ['issue', 'no of episodes'] 949 columns = ['issue'], 950 refresh_callback = refresh 951 #, edit_callback = edit 952 ) 953 print "chosen:" 954 print chosen 955 #------------------------------------------------------------
956 - def test_item_picker_dlg():
957 app = wx.PyWidgetTester(size = (200, 50)) 958 dlg = cItemPickerDlg(None, -1, msg = 'Pick a few items:') 959 dlg.set_columns(['Plugins'], ['Load in workplace', 'dummy']) 960 #dlg.set_columns(['Plugins'], []) 961 dlg.set_string_items(['patient', 'emr', 'docs']) 962 result = dlg.ShowModal() 963 print result 964 print dlg.get_picks()
965 #------------------------------------------------------------ 966 #test_get_choices_from_list() 967 #test_wxMultiChoiceDialog() 968 test_item_picker_dlg() 969 970 #================================================================ 971 # 972