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