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
16
17 __version__ = "$Revision: 1.36 $"
18 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
19 __license__ = "GPL"
20
21
22 import sys, types
23
24
25 import wx
26 import wx.lib.mixins.listctrl as listmixins
27
28
29 if __name__ == '__main__':
30 sys.path.insert(0, '../../')
31 from Gnumed.business import gmPerson
32 from Gnumed.pycommon import gmTools, gmDispatcher
33 from Gnumed.wxpython import gmGuiHelpers
34 from Gnumed.wxGladeWidgets import wxgGenericListSelectorDlg, wxgGenericListManagerPnl
35
36
37 -def get_choices_from_list(parent=None, msg=None, caption=None, choices=None, selections=None, columns=None, data=None, edit_callback=None, new_callback=None, delete_callback=None, refresh_callback=None, single_selection=False, can_return_empty=False):
82
84 """A dialog holding a list and a few buttons to act on the items."""
85
87
88 try:
89 msg = kwargs['msg']
90 del kwargs['msg']
91 except KeyError: msg = None
92
93 wxgGenericListSelectorDlg.wxgGenericListSelectorDlg.__init__(self, *args, **kwargs)
94
95 if msg is None:
96 self._LBL_message.Hide()
97 else:
98 self._LBL_message.SetLabel(msg)
99
100 self.refresh_callback = None
101 self.new_callback = None
102 self.edit_callback = None
103 self.delete_callback = None
104
105 self.can_return_empty = False
106
109
112
117
120
123
126
127
128
130 self._BTN_ok.Enable(True)
131 self._BTN_ok.SetDefault()
132 if self.edit_callback is not None:
133 self._BTN_edit.Enable(True)
134 if self.delete_callback is not None:
135 self._BTN_delete.Enable(True)
136
138 if self._LCTRL_items.get_selected_items(only_one=True) == -1:
139 if not self.can_return_empty:
140 self._BTN_ok.Enable(False)
141 self._BTN_cancel.SetDefault()
142 self._BTN_edit.Enable(False)
143 self._BTN_delete.Enable(False)
144
152
162
175
176
177
179 return self.__new_callback
180
182 if callback is not None:
183 if self.refresh_callback is None:
184 raise ValueError('refresh callback must be set before new callback can be set')
185 if not callable(callback):
186 raise ValueError('<new> callback is not a callable: %s' % callback)
187 self.__new_callback = callback
188
189 if callback is None:
190 self._BTN_new.Enable(False)
191 self._BTN_new.Hide()
192 else:
193 self._BTN_new.Enable(True)
194 self._BTN_new.Show()
195
196 new_callback = property(_get_new_callback, _set_new_callback)
197
199 return self.__edit_callback
200
202 if callback is not None:
203 if self.refresh_callback is None:
204 raise ValueError('refresh callback must be set before edit callback can be set')
205 if not callable(callback):
206 raise ValueError('<edit> callback is not a callable: %s' % callback)
207 self.__edit_callback = callback
208
209 if callback is None:
210 self._BTN_edit.Enable(False)
211 self._BTN_edit.Hide()
212 else:
213 self._BTN_edit.Enable(True)
214 self._BTN_edit.Show()
215
216 edit_callback = property(_get_edit_callback, _set_edit_callback)
217
219 return self.__delete_callback
220
222 if callback is not None:
223 if self.refresh_callback is None:
224 raise ValueError('refresh callback must be set before delete callback can be set')
225 if not callable(callback):
226 raise ValueError('<delete> callback is not a callable: %s' % callback)
227 self.__delete_callback = callback
228
229 if callback is None:
230 self._BTN_delete.Enable(False)
231 self._BTN_delete.Hide()
232 else:
233 self._BTN_delete.Enable(True)
234 self._BTN_delete.Show()
235
236 delete_callback = property(_get_delete_callback, _set_delete_callback)
237
239 return self.__refresh_callback
240
244
246 if callback is not None:
247 if not callable(callback):
248 raise ValueError('<refresh> callback is not a callable: %s' % callback)
249 self.__refresh_callback = callback
250 if callback is not None:
251 wx.CallAfter(self._set_refresh_callback_helper)
252
253 refresh_callback = property(_get_refresh_callback, _set_refresh_callback)
254
256 """A panel holding a generic multi-column list and action buttions."""
257
259
260 try:
261 msg = kwargs['msg']
262 del kwargs['msg']
263 except KeyError: msg = None
264
265 wxgGenericListManagerPnl.wxgGenericListManagerPnl.__init__(self, *args, **kwargs)
266
267 if msg is None:
268 self._LBL_message.Hide()
269 else:
270 self._LBL_message.SetLabel(msg)
271
272
273 self.__new_callback = None
274 self.edit_callback = None
275 self.delete_callback = None
276 self.refresh_callback = None
277
278
279
282
284 self._LCTRL_items.set_string_items(items = items)
285 self._LCTRL_items.set_column_widths()
286
287 if (items is None) or (len(items) == 0):
288 self._BTN_edit.Enable(False)
289 self._BTN_remove.Enable(False)
290 else:
291 self._LCTRL_items.Select(0)
292
295
298
301
302
303
305 if self.edit_callback is not None:
306 self._BTN_edit.Enable(True)
307 if self.delete_callback is not None:
308 self._BTN_remove.Enable(True)
309
311 if self._LCTRL_items.get_selected_items(only_one=True) == -1:
312 self._BTN_edit.Enable(False)
313 self._BTN_remove.Enable(False)
314
321
331
341
342
343
345 return self.__new_callback
346
348 self.__new_callback = callback
349 self._BTN_add.Enable(callback is not None)
350
351 new_callback = property(_get_new_callback, _set_new_callback)
352
354
356
357 try:
358 kwargs['style'] = kwargs['style'] | wx.LC_REPORT
359 except KeyError:
360 kwargs['style'] = wx.LC_REPORT
361
362 self.__is_single_selection = ((kwargs['style'] & wx.LC_SINGLE_SEL) == wx.LC_SINGLE_SEL)
363
364 wx.ListCtrl.__init__(self, *args, **kwargs)
365 listmixins.ListCtrlAutoWidthMixin.__init__(self)
366
367 self.__widths = None
368 self.__data = None
369
370
371
373 """(Re)define the columns.
374
375 Note that this will (have to) delete the items.
376 """
377 self.ClearAll()
378 if columns is None:
379 return
380 for idx in range(len(columns)):
381 self.InsertColumn(idx, columns[idx])
382
384 """Set the column width policy.
385
386 widths = None:
387 use previous policy if any or default policy
388 widths != None:
389 use this policy and remember it for later calls
390
391 This means there is no way to *revert* to the default policy :-(
392 """
393
394 if widths is not None:
395 self.__widths = widths
396 for idx in range(len(self.__widths)):
397 self.SetColumnWidth(col = idx, width = self.__widths[idx])
398 return
399
400
401 if self.__widths is not None:
402 for idx in range(len(self.__widths)):
403 self.SetColumnWidth(col = idx, width = self.__widths[idx])
404 return
405
406
407 if self.GetItemCount() == 0:
408 width_type = wx.LIST_AUTOSIZE_USEHEADER
409 else:
410 width_type = wx.LIST_AUTOSIZE
411 for idx in range(self.GetColumnCount()):
412 self.SetColumnWidth(col = idx, width = width_type)
413
415 """All item members must be unicode()able or None."""
416
417 self.DeleteAllItems()
418 self.__data = items
419
420 if items is None:
421 return
422
423 for item in items:
424 try:
425 item[0]
426 if not isinstance(item, basestring):
427 is_numerically_iterable = True
428 else:
429 is_numerically_iterable = False
430 except TypeError:
431 is_numerically_iterable = False
432
433 if is_numerically_iterable:
434
435
436 col_val = unicode(item[0])
437 row_num = self.InsertStringItem(index = sys.maxint, label = col_val)
438 for col_idx in range(1, min(self.GetColumnCount(), len(item))):
439 col_val = unicode(item[col_idx])
440 self.SetStringItem(index = row_num, col = col_idx, label = col_val)
441 else:
442
443 col_val = unicode(item)
444 row_num = self.InsertStringItem(index = sys.maxint, label = col_val)
445
447 """<data must be a list corresponding to the item indices>"""
448 self.__data = data
449
451 self.Select(0, on = 0)
452 for idx in selections:
453 self.Select(idx = idx, on = 1)
454
455
456
458 labels = []
459 for col_idx in self.GetColumnCount():
460 col = self.GetColumn(col = col_idx)
461 labels.append(col.GetText())
462 return labels
463
465 if self.__data is None:
466 return None
467
468 return self.__data[item_idx]
469
471
472 if self.__is_single_selection or only_one:
473 return self.GetFirstSelected()
474
475 items = []
476 idx = self.GetFirstSelected()
477 while idx != -1:
478 items.append(idx)
479 idx = self.GetNextSelected(idx)
480
481 return items
482
484
485 if self.__is_single_selection or only_one:
486 if self.__data is None:
487 return None
488 idx = self.GetFirstSelected()
489 if idx == -1:
490 return None
491 return self.__data[idx]
492
493 data = []
494 if self.__data is None:
495 return data
496 idx = self.GetFirstSelected()
497 while idx != -1:
498 data.append(self.__data[idx])
499 idx = self.GetNextSelected(idx)
500
501 return data
502
504 self.Select(idx = self.GetFirstSelected(), on = 0)
505
506
507
508 if __name__ == '__main__':
509
510 from Gnumed.pycommon import gmI18N
511 gmI18N.activate_locale()
512 gmI18N.install_domain()
513
514
516 app = wx.PyWidgetTester(size = (400, 500))
517 dlg = wx.MultiChoiceDialog (
518 parent = None,
519 message = 'test message',
520 caption = 'test caption',
521 choices = ['a', 'b', 'c', 'd', 'e']
522 )
523 dlg.ShowModal()
524 sels = dlg.GetSelections()
525 print "selected:"
526 for sel in sels:
527 print sel
528
530
531 def edit(argument):
532 print "editor called with:"
533 print argument
534
535 def refresh(lctrl):
536 choices = ['a', 'b', 'c']
537 lctrl.set_string_items(choices)
538
539 app = wx.PyWidgetTester(size = (200, 50))
540 chosen = get_choices_from_list (
541
542 caption = 'select health issues',
543
544
545 columns = ['issue'],
546 refresh_callback = refresh
547
548 )
549 print "chosen:"
550 print chosen
551
552 if (len(sys.argv) > 1) and (sys.argv[1] == 'test'):
553 test_get_choices_from_list()
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683