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          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   
  27   
  28  import wx 
  29  import wx.lib.mixins.listctrl as listmixins 
  30   
  31   
  32  _log = logging.getLogger('gm.list_ui') 
  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 columns=None, 41 choices=None, 42 data=None, 43 selections=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 from Gnumed.wxGladeWidgets import wxgGenericListSelectorDlg 121
122 -class cGenericListSelectorDlg(wxgGenericListSelectorDlg.wxgGenericListSelectorDlg):
123 """A dialog holding a list and a few buttons to act on the items.""" 124 125 # FIXME: configurable callback on double-click action 126
127 - def __init__(self, *args, **kwargs):
128 129 try: 130 msg = kwargs['msg'] 131 del kwargs['msg'] 132 except KeyError: msg = None 133 134 wxgGenericListSelectorDlg.wxgGenericListSelectorDlg.__init__(self, *args, **kwargs) 135 136 self.message = msg 137 138 self.left_extra_button = None 139 self.middle_extra_button = None 140 self.right_extra_button = None 141 142 self.refresh_callback = None # called when new/edit/delete callbacks return True (IOW were not cancelled) 143 self.new_callback = None # called when NEW button pressed, no argument passed in 144 self.edit_callback = None # called when EDIT button pressed, data of topmost selected item passed in 145 self.delete_callback = None # called when DELETE button pressed, data of topmost selected item passed in 146 147 self.can_return_empty = False 148 self.ignore_OK_button = False # by default do show/use the OK button
149 #------------------------------------------------------------
150 - def set_columns(self, columns=None):
151 self._LCTRL_items.set_columns(columns = columns)
152 #------------------------------------------------------------
153 - def set_column_widths(self, widths=None):
154 self._LCTRL_items.set_column_widths(widths = widths)
155 #------------------------------------------------------------
156 - def set_string_items(self, items = None):
157 self._LCTRL_items.set_string_items(items = items) 158 self._LCTRL_items.set_column_widths() 159 self._LCTRL_items.Select(0)
160 #------------------------------------------------------------
161 - def set_selections(self, selections = None):
162 self._LCTRL_items.set_selections(selections = selections) 163 if selections is None: 164 return 165 if len(selections) == 0: 166 return 167 if self.ignore_OK_button: 168 return 169 self._BTN_ok.Enable(True) 170 self._BTN_ok.SetDefault()
171 #------------------------------------------------------------
172 - def set_data(self, data = None):
173 self._LCTRL_items.set_data(data = data)
174 #------------------------------------------------------------
175 - def get_selected_item_data(self, only_one=False):
176 return self._LCTRL_items.get_selected_item_data(only_one=only_one)
177 #------------------------------------------------------------ 178 # event handlers 179 #------------------------------------------------------------
180 - def _on_list_item_selected(self, event):
181 if not self.__ignore_OK_button: 182 self._BTN_ok.SetDefault() 183 self._BTN_ok.Enable(True) 184 185 if self.edit_callback is not None: 186 self._BTN_edit.Enable(True) 187 188 if self.delete_callback is not None: 189 self._BTN_delete.Enable(True)
190 #------------------------------------------------------------
191 - def _on_list_item_deselected(self, event):
192 if self._LCTRL_items.get_selected_items(only_one=True) == -1: 193 if not self.can_return_empty: 194 self._BTN_cancel.SetDefault() 195 self._BTN_ok.Enable(False) 196 self._BTN_edit.Enable(False) 197 self._BTN_delete.Enable(False)
198 #------------------------------------------------------------
199 - def _on_new_button_pressed(self, event):
200 if not self.new_callback(): 201 self._LCTRL_items.SetFocus() 202 return 203 if self.refresh_callback is None: 204 self._LCTRL_items.SetFocus() 205 return 206 wx.BeginBusyCursor() 207 try: 208 self.refresh_callback(lctrl = self._LCTRL_items) 209 finally: 210 wx.EndBusyCursor() 211 self._LCTRL_items.set_column_widths() 212 self._LCTRL_items.SetFocus()
213 #------------------------------------------------------------
214 - def _on_edit_button_pressed(self, event):
215 # if the edit button *can* be pressed there are *supposed* 216 # to be both an item selected and an editor configured 217 if not self.edit_callback(self._LCTRL_items.get_selected_item_data(only_one=True)): 218 self._LCTRL_items.SetFocus() 219 return 220 if self.refresh_callback is None: 221 self._LCTRL_items.SetFocus() 222 return 223 wx.BeginBusyCursor() 224 try: 225 self.refresh_callback(lctrl = self._LCTRL_items) 226 finally: 227 wx.EndBusyCursor() 228 self._LCTRL_items.set_column_widths() 229 self._LCTRL_items.SetFocus()
230 #------------------------------------------------------------
231 - def _on_delete_button_pressed(self, event):
232 # if the delete button *can* be pressed there are *supposed* 233 # to be both an item selected and a deletor configured 234 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 235 if item_data is None: 236 self._LCTRL_items.SetFocus() 237 return 238 if not self.delete_callback(item_data): 239 self._LCTRL_items.SetFocus() 240 return 241 if self.refresh_callback is None: 242 self._LCTRL_items.SetFocus() 243 return 244 wx.BeginBusyCursor() 245 try: 246 self.refresh_callback(lctrl = self._LCTRL_items) 247 finally: 248 wx.EndBusyCursor() 249 self._LCTRL_items.set_column_widths() 250 self._LCTRL_items.SetFocus()
251 #------------------------------------------------------------
252 - def _on_left_extra_button_pressed(self, event):
253 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 254 if not self.__left_extra_button_callback(item_data): 255 self._LCTRL_items.SetFocus() 256 return 257 if self.refresh_callback is None: 258 self._LCTRL_items.SetFocus() 259 return 260 wx.BeginBusyCursor() 261 try: 262 self.refresh_callback(lctrl = self._LCTRL_items) 263 finally: 264 wx.EndBusyCursor() 265 self._LCTRL_items.set_column_widths() 266 self._LCTRL_items.SetFocus()
267 #------------------------------------------------------------
268 - def _on_middle_extra_button_pressed(self, event):
269 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 270 if not self.__middle_extra_button_callback(item_data): 271 self._LCTRL_items.SetFocus() 272 return 273 if self.refresh_callback is None: 274 self._LCTRL_items.SetFocus() 275 return 276 wx.BeginBusyCursor() 277 try: 278 self.refresh_callback(lctrl = self._LCTRL_items) 279 finally: 280 wx.EndBusyCursor() 281 self._LCTRL_items.set_column_widths() 282 self._LCTRL_items.SetFocus()
283 #------------------------------------------------------------
284 - def _on_right_extra_button_pressed(self, event):
285 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 286 if not self.__right_extra_button_callback(item_data): 287 self._LCTRL_items.SetFocus() 288 return 289 if self.refresh_callback is None: 290 self._LCTRL_items.SetFocus() 291 return 292 wx.BeginBusyCursor() 293 try: 294 self.refresh_callback(lctrl = self._LCTRL_items) 295 finally: 296 wx.EndBusyCursor() 297 self._LCTRL_items.set_column_widths() 298 self._LCTRL_items.SetFocus()
299 #------------------------------------------------------------ 300 # properties 301 #------------------------------------------------------------
302 - def _set_ignore_OK_button(self, ignored):
303 self.__ignore_OK_button = ignored 304 if self.__ignore_OK_button: 305 self._BTN_ok.Hide() 306 self._BTN_ok.Enable(False) 307 else: 308 self._BTN_ok.Show() 309 if self._LCTRL_items.get_selected_items(only_one=True) == -1: 310 if self.can_return_empty: 311 self._BTN_ok.Enable(True) 312 else: 313 self._BTN_ok.Enable(False) 314 self._BTN_cancel.SetDefault()
315 316 ignore_OK_button = property(lambda x:x, _set_ignore_OK_button) 317 #------------------------------------------------------------
318 - def _set_left_extra_button(self, definition):
319 if definition is None: 320 self._BTN_extra_left.Enable(False) 321 self._BTN_extra_left.Hide() 322 self.__left_extra_button_callback = None 323 return 324 325 (label, tooltip, callback) = definition 326 if not callable(callback): 327 raise ValueError('<left extra button> callback is not a callable: %s' % callback) 328 self.__left_extra_button_callback = callback 329 self._BTN_extra_left.SetLabel(label) 330 self._BTN_extra_left.SetToolTipString(tooltip) 331 self._BTN_extra_left.Enable(True) 332 self._BTN_extra_left.Show()
333 334 left_extra_button = property(lambda x:x, _set_left_extra_button) 335 #------------------------------------------------------------
336 - def _set_middle_extra_button(self, definition):
337 if definition is None: 338 self._BTN_extra_middle.Enable(False) 339 self._BTN_extra_middle.Hide() 340 self.__middle_extra_button_callback = None 341 return 342 343 (label, tooltip, callback) = definition 344 if not callable(callback): 345 raise ValueError('<middle extra button> callback is not a callable: %s' % callback) 346 self.__middle_extra_button_callback = callback 347 self._BTN_extra_middle.SetLabel(label) 348 self._BTN_extra_middle.SetToolTipString(tooltip) 349 self._BTN_extra_middle.Enable(True) 350 self._BTN_extra_middle.Show()
351 352 middle_extra_button = property(lambda x:x, _set_middle_extra_button) 353 #------------------------------------------------------------
354 - def _set_right_extra_button(self, definition):
355 if definition is None: 356 self._BTN_extra_right.Enable(False) 357 self._BTN_extra_right.Hide() 358 self.__right_extra_button_callback = None 359 return 360 361 (label, tooltip, callback) = definition 362 if not callable(callback): 363 raise ValueError('<right extra button> callback is not a callable: %s' % callback) 364 self.__right_extra_button_callback = callback 365 self._BTN_extra_right.SetLabel(label) 366 self._BTN_extra_right.SetToolTipString(tooltip) 367 self._BTN_extra_right.Enable(True) 368 self._BTN_extra_right.Show()
369 370 right_extra_button = property(lambda x:x, _set_right_extra_button) 371 #------------------------------------------------------------
372 - def _get_new_callback(self):
373 return self.__new_callback
374
375 - def _set_new_callback(self, callback):
376 if callback is not None: 377 if self.refresh_callback is None: 378 raise ValueError('refresh callback must be set before new callback can be set') 379 if not callable(callback): 380 raise ValueError('<new> callback is not a callable: %s' % callback) 381 self.__new_callback = callback 382 383 if callback is None: 384 self._BTN_new.Enable(False) 385 self._BTN_new.Hide() 386 else: 387 self._BTN_new.Enable(True) 388 self._BTN_new.Show()
389 390 new_callback = property(_get_new_callback, _set_new_callback) 391 #------------------------------------------------------------
392 - def _get_edit_callback(self):
393 return self.__edit_callback
394
395 - def _set_edit_callback(self, callback):
396 if callback is not None: 397 if not callable(callback): 398 raise ValueError('<edit> callback is not a callable: %s' % callback) 399 self.__edit_callback = callback 400 401 if callback is None: 402 self._BTN_edit.Enable(False) 403 self._BTN_edit.Hide() 404 else: 405 self._BTN_edit.Enable(True) 406 self._BTN_edit.Show()
407 408 edit_callback = property(_get_edit_callback, _set_edit_callback) 409 #------------------------------------------------------------
410 - def _get_delete_callback(self):
411 return self.__delete_callback
412
413 - def _set_delete_callback(self, callback):
414 if callback is not None: 415 if self.refresh_callback is None: 416 raise ValueError('refresh callback must be set before delete callback can be set') 417 if not callable(callback): 418 raise ValueError('<delete> callback is not a callable: %s' % callback) 419 self.__delete_callback = callback 420 421 if callback is None: 422 self._BTN_delete.Enable(False) 423 self._BTN_delete.Hide() 424 else: 425 self._BTN_delete.Enable(True) 426 self._BTN_delete.Show()
427 428 delete_callback = property(_get_delete_callback, _set_delete_callback) 429 #------------------------------------------------------------
430 - def _get_refresh_callback(self):
431 return self.__refresh_callback
432
434 wx.BeginBusyCursor() 435 try: 436 self.refresh_callback(lctrl = self._LCTRL_items) 437 finally: 438 wx.EndBusyCursor() 439 self._LCTRL_items.set_column_widths()
440
441 - def _set_refresh_callback(self, callback):
442 if callback is not None: 443 if not callable(callback): 444 raise ValueError('<refresh> callback is not a callable: %s' % callback) 445 self.__refresh_callback = callback 446 if callback is not None: 447 wx.CallAfter(self._set_refresh_callback_helper)
448 449 refresh_callback = property(_get_refresh_callback, _set_refresh_callback) 450 #------------------------------------------------------------
451 - def _set_list_tooltip_callback(self, callback):
452 self._LCTRL_items.item_tooltip_callback = callback
453 454 list_tooltip_callback = property(lambda x:x, _set_list_tooltip_callback) 455 #def _get_tooltip(self, item): # inside a class 456 #def _get_tooltip(item): # outside a class 457 #------------------------------------------------------------
458 - def _set_message(self, message):
459 if message is None: 460 self._LBL_message.Hide() 461 return 462 self._LBL_message.SetLabel(message) 463 self._LBL_message.Show()
464 465 message = property(lambda x:x, _set_message)
466 #================================================================ 467 from Gnumed.wxGladeWidgets import wxgGenericListManagerPnl 468
469 -class cGenericListManagerPnl(wxgGenericListManagerPnl.wxgGenericListManagerPnl):
470 """A panel holding a generic multi-column list and action buttions.""" 471
472 - def __init__(self, *args, **kwargs):
473 474 try: 475 msg = kwargs['msg'] 476 del kwargs['msg'] 477 except KeyError: msg = None 478 479 wxgGenericListManagerPnl.wxgGenericListManagerPnl.__init__(self, *args, **kwargs) 480 481 if msg is None: 482 self._LBL_message.Hide() 483 else: 484 self._LBL_message.SetLabel(msg) 485 486 # new/edit/delete must return True/False to enable refresh 487 self.__new_callback = None # called when NEW button pressed, no argument passed in 488 self.edit_callback = None # called when EDIT button pressed, data of topmost selected item passed in 489 self.delete_callback = None # called when DELETE button pressed, data of topmost selected item passed in 490 self.refresh_callback = None # called when new/edit/delete callbacks return True (IOW were not cancelled) 491 492 self.__select_callback = None # called when an item is selected, data of topmost selected item passed in 493 494 self.left_extra_button = None 495 self.middle_extra_button = None 496 self.right_extra_button = None
497 #------------------------------------------------------------ 498 # external API 499 #------------------------------------------------------------
500 - def set_columns(self, columns=None):
501 self._LCTRL_items.set_columns(columns = columns)
502 #------------------------------------------------------------
503 - def set_string_items(self, items = None):
504 self._LCTRL_items.set_string_items(items = items) 505 self._LCTRL_items.set_column_widths() 506 507 if (items is None) or (len(items) == 0): 508 self._BTN_edit.Enable(False) 509 self._BTN_remove.Enable(False) 510 else: 511 self._LCTRL_items.Select(0)
512 #------------------------------------------------------------
513 - def set_selections(self, selections = None):
514 self._LCTRL_items.set_selections(selections = selections)
515 #------------------------------------------------------------
516 - def set_data(self, data = None):
517 self._LCTRL_items.set_data(data = data)
518 #------------------------------------------------------------
519 - def get_selected_item_data(self, only_one=False):
520 return self._LCTRL_items.get_selected_item_data(only_one=only_one)
521 #------------------------------------------------------------ 522 # event handlers 523 #------------------------------------------------------------
524 - def _on_list_item_selected(self, event):
525 if self.edit_callback is not None: 526 self._BTN_edit.Enable(True) 527 if self.delete_callback is not None: 528 self._BTN_remove.Enable(True) 529 if self.__select_callback is not None: 530 item = self._LCTRL_items.get_selected_item_data(only_one=True) 531 self.__select_callback(item)
532 #------------------------------------------------------------
533 - def _on_list_item_deselected(self, event):
534 if self._LCTRL_items.get_selected_items(only_one=True) == -1: 535 self._BTN_edit.Enable(False) 536 self._BTN_remove.Enable(False) 537 if self.__select_callback is not None: 538 self.__select_callback(None)
539 #------------------------------------------------------------
540 - def _on_add_button_pressed(self, event):
541 if not self.new_callback(): 542 return 543 if self.refresh_callback is None: 544 return 545 wx.BeginBusyCursor() 546 try: 547 self.refresh_callback(lctrl = self._LCTRL_items) 548 finally: 549 wx.EndBusyCursor()
550 #------------------------------------------------------------
551 - def _on_list_item_activated(self, event):
552 if self.edit_callback is None: 553 return 554 self._on_edit_button_pressed(event)
555 #------------------------------------------------------------
556 - def _on_edit_button_pressed(self, event):
557 item = self._LCTRL_items.get_selected_item_data(only_one=True) 558 if item is None: 559 return 560 if not self.edit_callback(item): 561 return 562 if self.refresh_callback is None: 563 return 564 wx.BeginBusyCursor() 565 try: 566 self.refresh_callback(lctrl = self._LCTRL_items) 567 finally: 568 wx.EndBusyCursor()
569 #------------------------------------------------------------
570 - def _on_remove_button_pressed(self, event):
571 item = self._LCTRL_items.get_selected_item_data(only_one=True) 572 if item is None: 573 return 574 if not self.delete_callback(item): 575 return 576 if self.refresh_callback is None: 577 return 578 wx.BeginBusyCursor() 579 try: 580 self.refresh_callback(lctrl = self._LCTRL_items) 581 finally: 582 wx.EndBusyCursor()
583 #------------------------------------------------------------
584 - def _on_left_extra_button_pressed(self, event):
585 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 586 if not self.__left_extra_button_callback(item_data): 587 self._LCTRL_items.SetFocus() 588 return 589 if self.refresh_callback is None: 590 self._LCTRL_items.SetFocus() 591 return 592 wx.BeginBusyCursor() 593 try: 594 self.refresh_callback(lctrl = self._LCTRL_items) 595 finally: 596 wx.EndBusyCursor() 597 self._LCTRL_items.set_column_widths() 598 self._LCTRL_items.SetFocus()
599 #------------------------------------------------------------
600 - def _on_middle_extra_button_pressed(self, event):
601 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 602 if not self.__middle_extra_button_callback(item_data): 603 self._LCTRL_items.SetFocus() 604 return 605 if self.refresh_callback is None: 606 self._LCTRL_items.SetFocus() 607 return 608 wx.BeginBusyCursor() 609 try: 610 self.refresh_callback(lctrl = self._LCTRL_items) 611 finally: 612 wx.EndBusyCursor() 613 self._LCTRL_items.set_column_widths() 614 self._LCTRL_items.SetFocus()
615 #------------------------------------------------------------
616 - def _on_right_extra_button_pressed(self, event):
617 item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 618 if not self.__right_extra_button_callback(item_data): 619 self._LCTRL_items.SetFocus() 620 return 621 if self.refresh_callback is None: 622 self._LCTRL_items.SetFocus() 623 return 624 wx.BeginBusyCursor() 625 try: 626 self.refresh_callback(lctrl = self._LCTRL_items) 627 finally: 628 wx.EndBusyCursor() 629 self._LCTRL_items.set_column_widths() 630 self._LCTRL_items.SetFocus()
631 #------------------------------------------------------------ 632 # properties 633 #------------------------------------------------------------
634 - def _get_new_callback(self):
635 return self.__new_callback
636
637 - def _set_new_callback(self, callback):
638 if callback is not None: 639 if not callable(callback): 640 raise ValueError('<new> callback is not a callable: %s' % callback) 641 self.__new_callback = callback 642 self._BTN_add.Enable(callback is not None)
643 644 new_callback = property(_get_new_callback, _set_new_callback) 645 #------------------------------------------------------------
646 - def _get_select_callback(self):
647 return self.__select_callback
648
649 - def _set_select_callback(self, callback):
650 if callback is not None: 651 if not callable(callback): 652 raise ValueError('<select> callback is not a callable: %s' % callback) 653 self.__select_callback = callback
654 655 select_callback = property(_get_select_callback, _set_select_callback) 656 #------------------------------------------------------------
657 - def _get_message(self):
658 return self._LBL_message.GetLabel()
659
660 - def _set_message(self, msg):
661 if msg is None: 662 self._LBL_message.Hide() 663 self._LBL_message.SetLabel(u'') 664 else: 665 self._LBL_message.SetLabel(msg) 666 self._LBL_message.Show() 667 self.Layout()
668 669 message = property(_get_message, _set_message) 670 #------------------------------------------------------------
671 - def _set_left_extra_button(self, definition):
672 if definition is None: 673 self._BTN_extra_left.Enable(False) 674 self._BTN_extra_left.Hide() 675 self.__left_extra_button_callback = None 676 return 677 678 (label, tooltip, callback) = definition 679 if not callable(callback): 680 raise ValueError('<left extra button> callback is not a callable: %s' % callback) 681 self.__left_extra_button_callback = callback 682 self._BTN_extra_left.SetLabel(label) 683 self._BTN_extra_left.SetToolTipString(tooltip) 684 self._BTN_extra_left.Enable(True) 685 self._BTN_extra_left.Show()
686 687 left_extra_button = property(lambda x:x, _set_left_extra_button) 688 #------------------------------------------------------------
689 - def _set_middle_extra_button(self, definition):
690 if definition is None: 691 self._BTN_extra_middle.Enable(False) 692 self._BTN_extra_middle.Hide() 693 self.__middle_extra_button_callback = None 694 return 695 696 (label, tooltip, callback) = definition 697 if not callable(callback): 698 raise ValueError('<middle extra button> callback is not a callable: %s' % callback) 699 self.__middle_extra_button_callback = callback 700 self._BTN_extra_middle.SetLabel(label) 701 self._BTN_extra_middle.SetToolTipString(tooltip) 702 self._BTN_extra_middle.Enable(True) 703 self._BTN_extra_middle.Show()
704 705 middle_extra_button = property(lambda x:x, _set_middle_extra_button) 706 #------------------------------------------------------------
707 - def _set_right_extra_button(self, definition):
708 if definition is None: 709 self._BTN_extra_right.Enable(False) 710 self._BTN_extra_right.Hide() 711 self.__right_extra_button_callback = None 712 return 713 714 (label, tooltip, callback) = definition 715 if not callable(callback): 716 raise ValueError('<right extra button> callback is not a callable: %s' % callback) 717 self.__right_extra_button_callback = callback 718 self._BTN_extra_right.SetLabel(label) 719 self._BTN_extra_right.SetToolTipString(tooltip) 720 self._BTN_extra_right.Enable(True) 721 self._BTN_extra_right.Show()
722 723 right_extra_button = property(lambda x:x, _set_right_extra_button)
724 #================================================================ 725 from Gnumed.wxGladeWidgets import wxgItemPickerDlg 726
727 -class cItemPickerDlg(wxgItemPickerDlg.wxgItemPickerDlg):
728
729 - def __init__(self, *args, **kwargs):
730 731 try: 732 msg = kwargs['msg'] 733 del kwargs['msg'] 734 except KeyError: 735 msg = None 736 737 wxgItemPickerDlg.wxgItemPickerDlg.__init__(self, *args, **kwargs) 738 739 if msg is None: 740 self._LBL_msg.Hide() 741 else: 742 self._LBL_msg.SetLabel(msg) 743 744 self._LCTRL_left.activate_callback = self.__pick_selected 745 #self._LCTRL_left.item_tooltip_callback = self.__on_get_item_tooltip 746 self.__extra_button_callback = None 747 748 self._LCTRL_left.SetFocus()
749 #------------------------------------------------------------ 750 # external API 751 #------------------------------------------------------------
752 - def set_columns(self, columns=None, columns_right=None):
753 self._LCTRL_left.set_columns(columns = columns) 754 if columns_right is None: 755 self._LCTRL_right.set_columns(columns = columns) 756 else: 757 if len(columns_right) < len(columns): 758 cols = columns 759 else: 760 cols = columns_right[:len(columns)] 761 self._LCTRL_right.set_columns(columns = cols)
762 #------------------------------------------------------------
763 - def set_string_items(self, items = None):
764 self._LCTRL_left.set_string_items(items = items) 765 self._LCTRL_left.set_column_widths() 766 self._LCTRL_right.set_string_items() 767 768 self._BTN_left2right.Enable(False) 769 self._BTN_right2left.Enable(False)
770 #------------------------------------------------------------
771 - def set_selections(self, selections = None):
772 self._LCTRL_left.set_selections(selections = selections)
773 #------------------------------------------------------------
774 - def set_choices(self, choices=None, data=None):
775 self.set_string_items(items = choices) 776 if data is not None: 777 self.set_data(data = data)
778 #------------------------------------------------------------
779 - def set_picks(self, picks=None, data=None):
780 self._LCTRL_right.set_string_items(picks) 781 self._LCTRL_right.set_column_widths() 782 if data is not None: 783 self._LCTRL_right.set_data(data = data)
784 #------------------------------------------------------------
785 - def set_data(self, data = None):
786 self._LCTRL_left.set_data(data = data)
787 #------------------------------------------------------------
788 - def get_picks(self):
789 return self._LCTRL_right.get_item_data()
790 791 picks = property(get_picks, lambda x:x) 792 #------------------------------------------------------------
793 - def _set_extra_button(self, definition):
794 if definition is None: 795 self._BTN_extra.Enable(False) 796 self._BTN_extra.Hide() 797 self.__extra_button_callback = None 798 return 799 800 (label, tooltip, callback) = definition 801 if not callable(callback): 802 raise ValueError('<extra button> callback is not a callable: %s' % callback) 803 self.__extra_button_callback = callback 804 self._BTN_extra.SetLabel(label) 805 self._BTN_extra.SetToolTipString(tooltip) 806 self._BTN_extra.Enable(True) 807 self._BTN_extra.Show()
808 809 extra_button = property(lambda x:x, _set_extra_button) 810 #------------------------------------------------------------ 811 # internal helpers 812 #------------------------------------------------------------
813 - def __pick_selected(self, event=None):
814 if self._LCTRL_left.get_selected_items(only_one = True) == -1: 815 return 816 817 right_items = self._LCTRL_right.get_string_items() 818 right_data = self._LCTRL_right.get_item_data() 819 820 right_items.extend(self._LCTRL_left.get_selected_string_items(only_one = False)) 821 self._LCTRL_right.set_string_items(items = right_items) 822 del right_items 823 824 if right_data is None: 825 self._LCTRL_right.set_data(data = self._LCTRL_left.get_selected_item_data(only_one = False)) 826 else: 827 right_data.extend(self._LCTRL_left.get_selected_item_data(only_one = False)) 828 self._LCTRL_right.set_data(data = right_data) 829 del right_data 830 831 self._LCTRL_right.set_column_widths()
832 #------------------------------------------------------------
833 - def __remove_selected_picks(self):
834 if self._LCTRL_right.get_selected_items(only_one = True) == -1: 835 return 836 837 for item_idx in self._LCTRL_right.get_selected_items(only_one = False): 838 self._LCTRL_right.remove_item(item_idx) 839 840 if self._LCTRL_right.GetItemCount() == 0: 841 self._BTN_right2left.Enable(False)
842 #------------------------------------------------------------ 843 # event handlers 844 #------------------------------------------------------------
845 - def _on_left_list_item_selected(self, event):
846 self._BTN_left2right.Enable(True)
847 #------------------------------------------------------------
848 - def _on_left_list_item_deselected(self, event):
849 if self._LCTRL_left.get_selected_items(only_one = True) == -1: 850 self._BTN_left2right.Enable(False)
851 #------------------------------------------------------------
852 - def _on_right_list_item_selected(self, event):
853 self._BTN_right2left.Enable(True)
854 #------------------------------------------------------------
855 - def _on_right_list_item_deselected(self, event):
856 if self._LCTRL_right.get_selected_items(only_one = True) == -1: 857 self._BTN_right2left.Enable(False)
858 #------------------------------------------------------------
859 - def _on_button_left2right_pressed(self, event):
860 self.__pick_selected()
861 #------------------------------------------------------------
862 - def _on_button_right2left_pressed(self, event):
863 self.__remove_selected_picks()
864 #------------------------------------------------------------
865 - def _on_extra_button_pressed(self, event):
866 self.__extra_button_callback()
867 # item_data = self._LCTRL_items.get_selected_item_data(only_one=True) 868 # if not self.__left_extra_button_callback(item_data): 869 # self._LCTRL_items.SetFocus() 870 # return 871 # if self.refresh_callback is None: 872 # self._LCTRL_items.SetFocus() 873 # return 874 # wx.BeginBusyCursor() 875 # try: 876 # self.refresh_callback(lctrl = self._LCTRL_items) 877 # finally: 878 # wx.EndBusyCursor() 879 # self._LCTRL_items.set_column_widths() 880 # self._LCTRL_items.SetFocus() 881 #================================================================
882 -class cReportListCtrl(wx.ListCtrl, listmixins.ListCtrlAutoWidthMixin):
883 884 # FIXME: searching by typing 885
886 - def __init__(self, *args, **kwargs):
887 888 self.debug = None 889 890 try: 891 kwargs['style'] = kwargs['style'] | wx.LC_REPORT 892 except KeyError: 893 kwargs['style'] = wx.LC_REPORT 894 895 self.__is_single_selection = ((kwargs['style'] & wx.LC_SINGLE_SEL) == wx.LC_SINGLE_SEL) 896 897 wx.ListCtrl.__init__(self, *args, **kwargs) 898 listmixins.ListCtrlAutoWidthMixin.__init__(self) 899 900 self.__widths = None 901 self.__data = None 902 self.__activate_callback = None 903 self.__rightclick_callback = None 904 905 self.Bind(wx.EVT_MOTION, self._on_mouse_motion) 906 self.__item_tooltip_callback = None 907 self.__tt_last_item = None 908 self.__tt_static_part = _("""Select the items you want to work on. 909 910 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.""")
911 #------------------------------------------------------------ 912 # setters 913 #------------------------------------------------------------
914 - def set_columns(self, columns=None):
915 """(Re)define the columns. 916 917 Note that this will (have to) delete the items. 918 """ 919 self.ClearAll() 920 self.__tt_last_item = None 921 if columns is None: 922 return 923 for idx in range(len(columns)): 924 self.InsertColumn(idx, columns[idx])
925 #------------------------------------------------------------
926 - def set_column_widths(self, widths=None):
927 """Set the column width policy. 928 929 widths = None: 930 use previous policy if any or default policy 931 widths != None: 932 use this policy and remember it for later calls 933 934 This means there is no way to *revert* to the default policy :-( 935 """ 936 # explicit policy ? 937 if widths is not None: 938 self.__widths = widths 939 for idx in range(len(self.__widths)): 940 self.SetColumnWidth(col = idx, width = self.__widths[idx]) 941 return 942 943 # previous policy ? 944 if self.__widths is not None: 945 for idx in range(len(self.__widths)): 946 self.SetColumnWidth(col = idx, width = self.__widths[idx]) 947 return 948 949 # default policy ! 950 if self.GetItemCount() == 0: 951 width_type = wx.LIST_AUTOSIZE_USEHEADER 952 else: 953 width_type = wx.LIST_AUTOSIZE 954 for idx in range(self.GetColumnCount()): 955 self.SetColumnWidth(col = idx, width = width_type)
956 #------------------------------------------------------------
957 - def set_string_items(self, items=None):
958 """All item members must be unicode()able or None.""" 959 960 wx.BeginBusyCursor() 961 962 loop = 0 963 while True: 964 if loop > 3: 965 _log.debug('unable to delete list items after looping 3 times, continuing and hoping for the best') 966 break 967 loop += 1 968 if self.debug is not None: 969 _log.debug('[round %s] GetItemCount() before DeleteAllItems(): %s (%s, thread [%s])', loop, self.GetItemCount(), self.debug, thread.get_ident()) 970 if not self.DeleteAllItems(): 971 _log.debug('DeleteAllItems() failed (%s)', self.debug) 972 item_count = self.GetItemCount() 973 if self.debug is not None: 974 _log.debug('GetItemCount() after DeleteAllItems(): %s (%s)', item_count, self.debug) 975 if item_count == 0: 976 break 977 wx.SafeYield(None, True) 978 _log.debug('GetItemCount() not 0 after DeleteAllItems() (%s)', self.debug) 979 time.sleep(0.3) 980 wx.SafeYield(None, True) 981 982 if items is None: 983 self.data = None 984 wx.EndBusyCursor() 985 return 986 987 for item in items: 988 try: 989 item[0] 990 if not isinstance(item, basestring): 991 is_numerically_iterable = True 992 # do not iterate over individual chars in a string, however 993 else: 994 is_numerically_iterable = False 995 except TypeError: 996 is_numerically_iterable = False 997 998 if is_numerically_iterable: 999 # cannot use errors='replace' since then 1000 # None/ints/unicode strings fail to get encoded 1001 col_val = unicode(item[0]) 1002 row_num = self.InsertStringItem(index = sys.maxint, label = col_val) 1003 for col_num in range(1, min(self.GetColumnCount(), len(item))): 1004 col_val = unicode(item[col_num]) 1005 self.SetStringItem(index = row_num, col = col_num, label = col_val) 1006 else: 1007 # cannot use errors='replace' since then None/ints/unicode strings fails to get encoded 1008 col_val = unicode(item) 1009 row_num = self.InsertStringItem(index = sys.maxint, label = col_val) 1010 1011 self.data = items 1012 1013 wx.EndBusyCursor()
1014 #------------------------------------------------------------
1015 - def set_data(self, data=None):
1016 """<data must be a list corresponding to the item indices>""" 1017 if data is not None: 1018 item_count = self.GetItemCount() 1019 if len(data) != item_count: 1020 _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()) 1021 self.__data = data 1022 self.__tt_last_item = None 1023 return
1024
1025 - def _get_data(self):
1026 return self.__data
1027 1028 data = property(_get_data, set_data) 1029 #------------------------------------------------------------
1030 - def set_selections(self, selections=None):
1031 self.Select(0, on = 0) 1032 if selections is None: 1033 return 1034 for idx in selections: 1035 self.Select(idx = idx, on = 1)
1036 #self.SetItemState(idx, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) 1037
1038 - def __get_selections(self):
1039 if self.__is_single_selection: 1040 return [self.GetFirstSelected()] 1041 selections = [] 1042 idx = self.GetFirstSelected() 1043 while idx != -1: 1044 selections.append(idx) 1045 idx = self.GetNextSelected(idx) 1046 return selections
1047 1048 selections = property(__get_selections, set_selections) 1049 #------------------------------------------------------------ 1050 # getters 1051 #------------------------------------------------------------
1052 - def get_column_labels(self):
1053 labels = [] 1054 for col_idx in self.GetColumnCount(): 1055 col = self.GetColumn(col = col_idx) 1056 labels.append(col.GetText()) 1057 return labels
1058 #------------------------------------------------------------
1059 - def get_item(self, item_idx=None):
1060 if item_idx is not None: 1061 return self.GetItem(item_idx)
1062 #------------------------------------------------------------
1063 - def get_items(self):
1064 return [ self.GetItem(item_idx) for item_idx in range(self.GetItemCount()) ]
1065 #------------------------------------------------------------
1066 - def get_string_items(self):
1067 return [ self.GetItemText(item_idx) for item_idx in range(self.GetItemCount()) ]
1068 #------------------------------------------------------------
1069 - def get_selected_items(self, only_one=False):
1070 1071 if self.__is_single_selection or only_one: 1072 return self.GetFirstSelected() 1073 1074 items = [] 1075 idx = self.GetFirstSelected() 1076 while idx != -1: 1077 items.append(idx) 1078 idx = self.GetNextSelected(idx) 1079 1080 return items
1081 #------------------------------------------------------------
1082 - def get_selected_string_items(self, only_one=False):
1083 1084 if self.__is_single_selection or only_one: 1085 return self.GetItemText(self.GetFirstSelected()) 1086 1087 items = [] 1088 idx = self.GetFirstSelected() 1089 while idx != -1: 1090 items.append(self.GetItemText(idx)) 1091 idx = self.GetNextSelected(idx) 1092 1093 return items
1094 #------------------------------------------------------------
1095 - def get_item_data(self, item_idx = None):
1096 if self.__data is None: # this isn't entirely clean 1097 return None 1098 1099 if item_idx is not None: 1100 return self.__data[item_idx] 1101 1102 return [ self.__data[item_idx] for item_idx in range(self.GetItemCount()) ]
1103 #------------------------------------------------------------
1104 - def get_selected_item_data(self, only_one=False):
1105 1106 if self.__is_single_selection or only_one: 1107 if self.__data is None: 1108 return None 1109 idx = self.GetFirstSelected() 1110 if idx == -1: 1111 return None 1112 return self.__data[idx] 1113 1114 data = [] 1115 if self.__data is None: 1116 return data 1117 idx = self.GetFirstSelected() 1118 while idx != -1: 1119 data.append(self.__data[idx]) 1120 idx = self.GetNextSelected(idx) 1121 1122 return data
1123 #------------------------------------------------------------
1124 - def deselect_selected_item(self):
1125 self.Select(idx = self.GetFirstSelected(), on = 0)
1126 #------------------------------------------------------------
1127 - def remove_item(self, item_idx=None):
1128 self.DeleteItem(item_idx) 1129 if self.__data is not None: 1130 del self.__data[item_idx] 1131 self.__tt_last_item = None
1132 #------------------------------------------------------------ 1133 # event handlers 1134 #------------------------------------------------------------
1135 - def _on_list_item_activated(self, event):
1136 event.Skip() 1137 if self.__activate_callback is not None: 1138 self.__activate_callback(event)
1139 #------------------------------------------------------------
1140 - def _on_list_item_rightclicked(self, event):
1141 event.Skip() 1142 if self.__rightclick_callback is not None: 1143 self.__rightclick_callback(event)
1144 #------------------------------------------------------------
1145 - def _on_mouse_motion(self, event):
1146 """Update tooltip on mouse motion. 1147 1148 for s in dir(wx): 1149 if s.startswith('LIST_HITTEST'): 1150 print s, getattr(wx, s) 1151 1152 LIST_HITTEST_ABOVE 1 1153 LIST_HITTEST_BELOW 2 1154 LIST_HITTEST_NOWHERE 4 1155 LIST_HITTEST_ONITEM 672 1156 LIST_HITTEST_ONITEMICON 32 1157 LIST_HITTEST_ONITEMLABEL 128 1158 LIST_HITTEST_ONITEMRIGHT 256 1159 LIST_HITTEST_ONITEMSTATEICON 512 1160 LIST_HITTEST_TOLEFT 1024 1161 LIST_HITTEST_TORIGHT 2048 1162 """ 1163 item_idx, where_flag = self.HitTest(wx.Point(event.X, event.Y)) 1164 1165 # pointer on item related area at all ? 1166 if where_flag not in [ 1167 wx.LIST_HITTEST_ONITEMLABEL, 1168 wx.LIST_HITTEST_ONITEMICON, 1169 wx.LIST_HITTEST_ONITEMSTATEICON, 1170 wx.LIST_HITTEST_ONITEMRIGHT, 1171 wx.LIST_HITTEST_ONITEM 1172 ]: 1173 self.__tt_last_item = None # not on any item 1174 self.SetToolTipString(self.__tt_static_part) 1175 return 1176 1177 # same item as last time around ? 1178 if self.__tt_last_item == item_idx: 1179 return 1180 1181 # remeber the new item we are on 1182 self.__tt_last_item = item_idx 1183 1184 # HitTest() can return -1 if it so pleases, meaning that no item 1185 # was hit or else that maybe there aren't any items (empty list) 1186 if item_idx == wx.NOT_FOUND: 1187 self.SetToolTipString(self.__tt_static_part) 1188 return 1189 1190 # do we *have* item data ? 1191 if self.__data is None: 1192 self.SetToolTipString(self.__tt_static_part) 1193 return 1194 1195 # under some circumstances the item_idx returned 1196 # by HitTest() may be out of bounds with respect to 1197 # self.__data, this hints at a sync problem between 1198 # setting display items and associated data 1199 if ( 1200 (item_idx > (len(self.__data) - 1)) 1201 or 1202 (item_idx < -1) 1203 ): 1204 self.SetToolTipString(self.__tt_static_part) 1205 print "*************************************************************" 1206 print "GNUmed has detected an inconsistency with list item tooltips." 1207 print "" 1208 print "This is not a big problem and you can keep working." 1209 print "" 1210 print "However, please send us the following so we can fix GNUmed:" 1211 print "" 1212 print "item idx: %s" % item_idx 1213 print 'where flag: %s' % where_flag 1214 print 'data list length: %s' % len(self.__data) 1215 print "*************************************************************" 1216 return 1217 1218 dyna_tt = None 1219 if self.__item_tooltip_callback is not None: 1220 dyna_tt = self.__item_tooltip_callback(self.__data[item_idx]) 1221 1222 if dyna_tt is None: 1223 self.SetToolTipString(self.__tt_static_part) 1224 return 1225 1226 self.SetToolTipString(dyna_tt)
1227 #------------------------------------------------------------ 1228 # properties 1229 #------------------------------------------------------------
1230 - def _get_activate_callback(self):
1231 return self.__activate_callback
1232
1233 - def _set_activate_callback(self, callback):
1234 if callback is None: 1235 self.Unbind(wx.EVT_LIST_ITEM_ACTIVATED) 1236 else: 1237 if not callable(callback): 1238 raise ValueError('<activate> callback is not a callable: %s' % callback) 1239 self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self._on_list_item_activated) 1240 self.__activate_callback = callback
1241 1242 activate_callback = property(_get_activate_callback, _set_activate_callback) 1243 #------------------------------------------------------------
1244 - def _get_rightclick_callback(self):
1245 return self.__rightclick_callback
1246
1247 - def _set_rightclick_callback(self, callback):
1248 if callback is None: 1249 self.Unbind(wx.EVT_LIST_ITEM_RIGHT_CLICK) 1250 else: 1251 if not callable(callback): 1252 raise ValueError('<rightclick> callback is not a callable: %s' % callback) 1253 self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self._on_list_item_rightclicked) 1254 self.__rightclick_callback = callback
1255 1256 rightclick_callback = property(_get_rightclick_callback, _set_rightclick_callback) 1257 #------------------------------------------------------------
1258 - def _set_item_tooltip_callback(self, callback):
1259 if callback is not None: 1260 if not callable(callback): 1261 raise ValueError('<item_tooltip> callback is not a callable: %s' % callback) 1262 self.__item_tooltip_callback = callback
1263 1264 # the callback must be a function which takes a single argument 1265 # the argument is the data for the item the tooltip is on 1266 # the callback must return None if no item tooltip is to be shown 1267 # otherwise it must return a string (possibly with \n) 1268 item_tooltip_callback = property(lambda x:x, _set_item_tooltip_callback)
1269 #================================================================ 1270 # main 1271 #---------------------------------------------------------------- 1272 if __name__ == '__main__': 1273 1274 if len(sys.argv) < 2: 1275 sys.exit() 1276 1277 if sys.argv[1] != 'test': 1278 sys.exit() 1279 1280 sys.path.insert(0, '../../') 1281 1282 from Gnumed.pycommon import gmI18N 1283 gmI18N.activate_locale() 1284 gmI18N.install_domain() 1285 1286 #------------------------------------------------------------
1287 - def test_wxMultiChoiceDialog():
1288 app = wx.PyWidgetTester(size = (400, 500)) 1289 dlg = wx.MultiChoiceDialog ( 1290 parent = None, 1291 message = 'test message', 1292 caption = 'test caption', 1293 choices = ['a', 'b', 'c', 'd', 'e'] 1294 ) 1295 dlg.ShowModal() 1296 sels = dlg.GetSelections() 1297 print "selected:" 1298 for sel in sels: 1299 print sel
1300 #------------------------------------------------------------
1301 - def test_get_choices_from_list():
1302 1303 def edit(argument): 1304 print "editor called with:" 1305 print argument
1306 1307 def refresh(lctrl): 1308 choices = ['a', 'b', 'c'] 1309 lctrl.set_string_items(choices) 1310 1311 app = wx.PyWidgetTester(size = (200, 50)) 1312 chosen = get_choices_from_list ( 1313 # msg = 'select a health issue\nfrom the list below\n', 1314 caption = 'select health issues', 1315 #choices = [['D.M.II', '4'], ['MS', '3'], ['Fraktur', '2']], 1316 #columns = ['issue', 'no of episodes'] 1317 columns = ['issue'], 1318 refresh_callback = refresh 1319 #, edit_callback = edit 1320 ) 1321 print "chosen:" 1322 print chosen 1323 #------------------------------------------------------------
1324 - def test_item_picker_dlg():
1325 app = wx.PyWidgetTester(size = (200, 50)) 1326 dlg = cItemPickerDlg(None, -1, msg = 'Pick a few items:') 1327 dlg.set_columns(['Plugins'], ['Load in workplace', 'dummy']) 1328 #dlg.set_columns(['Plugins'], []) 1329 dlg.set_string_items(['patient', 'emr', 'docs']) 1330 result = dlg.ShowModal() 1331 print result 1332 print dlg.get_picks()
1333 #------------------------------------------------------------ 1334 #test_get_choices_from_list() 1335 #test_wxMultiChoiceDialog() 1336 test_item_picker_dlg() 1337 1338 #================================================================ 1339 # 1340