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.business import gmPerson
30 from Gnumed.pycommon import gmTools, gmDispatcher
31 from Gnumed.wxpython import gmGuiHelpers
32 from Gnumed.wxGladeWidgets import wxgGenericListSelectorDlg, wxgGenericListManagerPnl
33
34
35 -def get_choices_from_list (
36 parent=None,
37 msg=None,
38 caption=None,
39 choices=None,
40 selections=None,
41 columns=None,
42 data=None,
43 edit_callback=None,
44 new_callback=None,
45 delete_callback=None,
46 refresh_callback=None,
47 single_selection=False,
48 can_return_empty=False,
49 ignore_OK_button=False,
50 left_extra_button=None,
51 middle_extra_button=None,
52 right_extra_button=None):
115
117 """A dialog holding a list and a few buttons to act on the items."""
118
145
148
151
156
159
162
165
166
167
169 if not self.__ignore_OK_button:
170 self._BTN_ok.SetDefault()
171 self._BTN_ok.Enable(True)
172
173 if self.edit_callback is not None:
174 self._BTN_edit.Enable(True)
175
176 if self.delete_callback is not None:
177 self._BTN_delete.Enable(True)
178
180 if self._LCTRL_items.get_selected_items(only_one=True) == -1:
181 if not self.can_return_empty:
182 self._BTN_cancel.SetDefault()
183 self._BTN_ok.Enable(False)
184 self._BTN_edit.Enable(False)
185 self._BTN_delete.Enable(False)
186
198
212
229
242
255
268
269
270
279
280 ignore_OK_button = property(lambda x:x, _set_ignore_OK_button)
281
296
297 left_extra_button = property(lambda x:x, _set_left_extra_button)
298
313
314 middle_extra_button = property(lambda x:x, _set_middle_extra_button)
315
330
331 right_extra_button = property(lambda x:x, _set_right_extra_button)
332
334 return self.__new_callback
335
337 if callback is not None:
338 if self.refresh_callback is None:
339 raise ValueError('refresh callback must be set before new callback can be set')
340 if not callable(callback):
341 raise ValueError('<new> callback is not a callable: %s' % callback)
342 self.__new_callback = callback
343
344 if callback is None:
345 self._BTN_new.Enable(False)
346 self._BTN_new.Hide()
347 else:
348 self._BTN_new.Enable(True)
349 self._BTN_new.Show()
350
351 new_callback = property(_get_new_callback, _set_new_callback)
352
354 return self.__edit_callback
355
357 if callback is not None:
358 if not callable(callback):
359 raise ValueError('<edit> callback is not a callable: %s' % callback)
360 self.__edit_callback = callback
361
362 if callback is None:
363 self._BTN_edit.Enable(False)
364 self._BTN_edit.Hide()
365 else:
366 self._BTN_edit.Enable(True)
367 self._BTN_edit.Show()
368
369 edit_callback = property(_get_edit_callback, _set_edit_callback)
370
372 return self.__delete_callback
373
375 if callback is not None:
376 if self.refresh_callback is None:
377 raise ValueError('refresh callback must be set before delete callback can be set')
378 if not callable(callback):
379 raise ValueError('<delete> callback is not a callable: %s' % callback)
380 self.__delete_callback = callback
381
382 if callback is None:
383 self._BTN_delete.Enable(False)
384 self._BTN_delete.Hide()
385 else:
386 self._BTN_delete.Enable(True)
387 self._BTN_delete.Show()
388
389 delete_callback = property(_get_delete_callback, _set_delete_callback)
390
392 return self.__refresh_callback
393
401
403 if callback is not None:
404 if not callable(callback):
405 raise ValueError('<refresh> callback is not a callable: %s' % callback)
406 self.__refresh_callback = callback
407 if callback is not None:
408 wx.CallAfter(self._set_refresh_callback_helper)
409
410 refresh_callback = property(_get_refresh_callback, _set_refresh_callback)
411
413 """A panel holding a generic multi-column list and action buttions."""
414
434
435
436
439
441 self._LCTRL_items.set_string_items(items = items)
442 self._LCTRL_items.set_column_widths()
443
444 if (items is None) or (len(items) == 0):
445 self._BTN_edit.Enable(False)
446 self._BTN_remove.Enable(False)
447 else:
448 self._LCTRL_items.Select(0)
449
452
455
458
459
460
462 if self.edit_callback is not None:
463 self._BTN_edit.Enable(True)
464 if self.delete_callback is not None:
465 self._BTN_remove.Enable(True)
466
468 if self._LCTRL_items.get_selected_items(only_one=True) == -1:
469 self._BTN_edit.Enable(False)
470 self._BTN_remove.Enable(False)
471
482
496
510
511
512
514 return self.__new_callback
515
517 self.__new_callback = callback
518 self._BTN_add.Enable(callback is not None)
519
520 new_callback = property(_get_new_callback, _set_new_callback)
521
523
525
526 try:
527 kwargs['style'] = kwargs['style'] | wx.LC_REPORT
528 except KeyError:
529 kwargs['style'] = wx.LC_REPORT
530
531 self.__is_single_selection = ((kwargs['style'] & wx.LC_SINGLE_SEL) == wx.LC_SINGLE_SEL)
532
533 wx.ListCtrl.__init__(self, *args, **kwargs)
534 listmixins.ListCtrlAutoWidthMixin.__init__(self)
535
536 self.__widths = None
537 self.__data = None
538
539
540
542 """(Re)define the columns.
543
544 Note that this will (have to) delete the items.
545 """
546 self.ClearAll()
547 if columns is None:
548 return
549 for idx in range(len(columns)):
550 self.InsertColumn(idx, columns[idx])
551
553 """Set the column width policy.
554
555 widths = None:
556 use previous policy if any or default policy
557 widths != None:
558 use this policy and remember it for later calls
559
560 This means there is no way to *revert* to the default policy :-(
561 """
562
563 if widths is not None:
564 self.__widths = widths
565 for idx in range(len(self.__widths)):
566 self.SetColumnWidth(col = idx, width = self.__widths[idx])
567 return
568
569
570 if self.__widths is not None:
571 for idx in range(len(self.__widths)):
572 self.SetColumnWidth(col = idx, width = self.__widths[idx])
573 return
574
575
576 if self.GetItemCount() == 0:
577 width_type = wx.LIST_AUTOSIZE_USEHEADER
578 else:
579 width_type = wx.LIST_AUTOSIZE
580 for idx in range(self.GetColumnCount()):
581 self.SetColumnWidth(col = idx, width = width_type)
582
584 """All item members must be unicode()able or None."""
585
586 self.DeleteAllItems()
587 self.__data = items
588
589 if items is None:
590 return
591
592 for item in items:
593 try:
594 item[0]
595 if not isinstance(item, basestring):
596 is_numerically_iterable = True
597 else:
598 is_numerically_iterable = False
599 except TypeError:
600 is_numerically_iterable = False
601
602 if is_numerically_iterable:
603
604
605 col_val = unicode(item[0])
606 row_num = self.InsertStringItem(index = sys.maxint, label = col_val)
607 for col_idx in range(1, min(self.GetColumnCount(), len(item))):
608 col_val = unicode(item[col_idx])
609 self.SetStringItem(index = row_num, col = col_idx, label = col_val)
610 else:
611
612 col_val = unicode(item)
613 row_num = self.InsertStringItem(index = sys.maxint, label = col_val)
614
616 """<data must be a list corresponding to the item indices>"""
617 self.__data = data
618
620 self.Select(0, on = 0)
621 for idx in selections:
622 self.Select(idx = idx, on = 1)
623
624
625
626
628 labels = []
629 for col_idx in self.GetColumnCount():
630 col = self.GetColumn(col = col_idx)
631 labels.append(col.GetText())
632 return labels
633
635 if self.__data is None:
636 return None
637
638 return self.__data[item_idx]
639
641
642 if self.__is_single_selection or only_one:
643 return self.GetFirstSelected()
644
645 items = []
646 idx = self.GetFirstSelected()
647 while idx != -1:
648 items.append(idx)
649 idx = self.GetNextSelected(idx)
650
651 return items
652
654
655 if self.__is_single_selection or only_one:
656 if self.__data is None:
657 return None
658 idx = self.GetFirstSelected()
659 if idx == -1:
660 return None
661 return self.__data[idx]
662
663 data = []
664 if self.__data is None:
665 return data
666 idx = self.GetFirstSelected()
667 while idx != -1:
668 data.append(self.__data[idx])
669 idx = self.GetNextSelected(idx)
670
671 return data
672
674 self.Select(idx = self.GetFirstSelected(), on = 0)
675
676
677
678 if __name__ == '__main__':
679
680 from Gnumed.pycommon import gmI18N
681 gmI18N.activate_locale()
682 gmI18N.install_domain()
683
684
686 app = wx.PyWidgetTester(size = (400, 500))
687 dlg = wx.MultiChoiceDialog (
688 parent = None,
689 message = 'test message',
690 caption = 'test caption',
691 choices = ['a', 'b', 'c', 'd', 'e']
692 )
693 dlg.ShowModal()
694 sels = dlg.GetSelections()
695 print "selected:"
696 for sel in sels:
697 print sel
698
700
701 def edit(argument):
702 print "editor called with:"
703 print argument
704
705 def refresh(lctrl):
706 choices = ['a', 'b', 'c']
707 lctrl.set_string_items(choices)
708
709 app = wx.PyWidgetTester(size = (200, 50))
710 chosen = get_choices_from_list (
711
712 caption = 'select health issues',
713
714
715 columns = ['issue'],
716 refresh_callback = refresh
717
718 )
719 print "chosen:"
720 print chosen
721
722 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
723 test_get_choices_from_list()
724
725
726
727
728