Package Gnumed :: Package wxpython :: Module gmGuiHelpers
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmGuiHelpers

  1  """GNUmed GUI helper classes and functions. 
  2   
  3  This module provides some convenient wxPython GUI 
  4  helper thingies that are widely used throughout 
  5  GNUmed. 
  6  """ 
  7  # ======================================================================== 
  8  __version__ = "$Revision: 1.106 $" 
  9  __author__  = "K. Hilbert <Karsten.Hilbert@gmx.net>" 
 10  __license__ = "GPL v2 or later (details at http://www.gnu.org)" 
 11   
 12  import os 
 13  import logging 
 14  import sys 
 15   
 16   
 17  import wx 
 18   
 19   
 20  if __name__ == '__main__': 
 21          sys.path.insert(0, '../../') 
 22  from Gnumed.pycommon import gmMatchProvider 
 23  from Gnumed.wxpython import gmPhraseWheel 
 24   
 25   
 26  _log = logging.getLogger('gm.main') 
 27  # ======================================================================== 
28 -class cThreeValuedLogicPhraseWheel(gmPhraseWheel.cPhraseWheel):
29
30 - def __init__(self, *args, **kwargs):
31 32 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 33 34 items = [ 35 {'list_label': _('Yes: + / ! / 1'), 'field_label': _('yes'), 'data': True, 'weight': 0}, 36 {'list_label': _('No: - / 0'), 'field_label': _('no'), 'data': False, 'weight': 1}, 37 {'list_label': _('Unknown: ?'), 'field_label': _('unknown'), 'data': None, 'weight': 2}, 38 ] 39 mp = gmMatchProvider.cMatchProvider_FixedList(items) 40 mp.setThresholds(1, 1, 2) 41 mp.word_separators = '[ :/]+' 42 mp.word_separators = None 43 mp.ignored_chars = r"[.'\\(){}\[\]<>~#*$%^_=&@\t23456]+" + r'"' 44 45 self.matcher = mp
46 # ======================================================================== 47 from Gnumed.wxGladeWidgets import wxg2ButtonQuestionDlg 48
49 -class c2ButtonQuestionDlg(wxg2ButtonQuestionDlg.wxg2ButtonQuestionDlg):
50
51 - def __init__(self, *args, **kwargs):
52 53 caption = kwargs['caption'] 54 question = kwargs['question'] 55 button_defs = kwargs['button_defs'][:2] 56 del kwargs['caption'] 57 del kwargs['question'] 58 del kwargs['button_defs'] 59 60 try: 61 show_checkbox = kwargs['show_checkbox'] 62 del kwargs['show_checkbox'] 63 except KeyError: 64 show_checkbox = False 65 66 try: 67 checkbox_msg = kwargs['checkbox_msg'] 68 del kwargs['checkbox_msg'] 69 except KeyError: 70 checkbox_msg = None 71 72 try: 73 checkbox_tooltip = kwargs['checkbox_tooltip'] 74 del kwargs['checkbox_tooltip'] 75 except KeyError: 76 checkbox_tooltip = None 77 78 wxg2ButtonQuestionDlg.wxg2ButtonQuestionDlg.__init__(self, *args, **kwargs) 79 80 self.SetTitle(title = caption) 81 self._LBL_question.SetLabel(label = question) 82 83 if not show_checkbox: 84 self._CHBOX_dont_ask_again.Hide() 85 else: 86 if checkbox_msg is not None: 87 self._CHBOX_dont_ask_again.SetLabel(checkbox_msg) 88 if checkbox_tooltip is not None: 89 self._CHBOX_dont_ask_again.SetToolTipString(checkbox_tooltip) 90 91 buttons = [self._BTN_1, self._BTN_2] 92 for idx in range(len(button_defs)): 93 buttons[idx].SetLabel(label = button_defs[idx]['label']) 94 buttons[idx].SetToolTipString(button_defs[idx]['tooltip']) 95 try: 96 if button_defs[idx]['default'] is True: 97 buttons[idx].SetDefault() 98 buttons[idx].SetFocus() 99 except KeyError: 100 pass 101 102 self.Fit()
103 #--------------------------------------------------------
104 - def checkbox_is_checked(self):
105 return self._CHBOX_dont_ask_again.IsChecked()
106 #-------------------------------------------------------- 107 # event handlers 108 #--------------------------------------------------------
109 - def _on_BTN_1_pressed(self, evt):
110 if self.IsModal(): 111 self.EndModal(wx.ID_YES) 112 else: 113 self.Close()
114 #--------------------------------------------------------
115 - def _on_BTN_2_pressed(self, evt):
116 if self.IsModal(): 117 self.EndModal(wx.ID_NO) 118 else: 119 self.Close()
120 # ======================================================================== 121 from Gnumed.wxGladeWidgets import wxg3ButtonQuestionDlg 122
123 -class c3ButtonQuestionDlg(wxg3ButtonQuestionDlg.wxg3ButtonQuestionDlg):
124
125 - def __init__(self, *args, **kwargs):
126 127 caption = kwargs['caption'] 128 question = kwargs['question'] 129 button_defs = kwargs['button_defs'][:3] 130 del kwargs['caption'] 131 del kwargs['question'] 132 del kwargs['button_defs'] 133 134 try: 135 show_checkbox = kwargs['show_checkbox'] 136 del kwargs['show_checkbox'] 137 except KeyError: 138 show_checkbox = False 139 140 try: 141 checkbox_msg = kwargs['checkbox_msg'] 142 del kwargs['checkbox_msg'] 143 except KeyError: 144 checkbox_msg = None 145 146 try: 147 checkbox_tooltip = kwargs['checkbox_tooltip'] 148 del kwargs['checkbox_tooltip'] 149 except KeyError: 150 checkbox_tooltip = None 151 152 wxg3ButtonQuestionDlg.wxg3ButtonQuestionDlg.__init__(self, *args, **kwargs) 153 154 self.SetTitle(title = caption) 155 self._LBL_question.SetLabel(label = question) 156 157 if not show_checkbox: 158 self._CHBOX_dont_ask_again.Hide() 159 else: 160 if checkbox_msg is not None: 161 self._CHBOX_dont_ask_again.SetLabel(checkbox_msg) 162 if checkbox_tooltip is not None: 163 self._CHBOX_dont_ask_again.SetToolTipString(checkbox_tooltip) 164 165 buttons = [self._BTN_1, self._BTN_2, self._BTN_3] 166 for idx in range(len(button_defs)): 167 buttons[idx].SetLabel(label = button_defs[idx]['label']) 168 buttons[idx].SetToolTipString(button_defs[idx]['tooltip']) 169 try: 170 if button_defs[idx]['default'] is True: 171 buttons[idx].SetDefault() 172 buttons[idx].SetFocus() 173 except KeyError: 174 pass 175 176 self.Fit()
177 #--------------------------------------------------------
178 - def checkbox_is_checked(self):
179 return self._CHBOX_dont_ask_again.IsChecked()
180 #-------------------------------------------------------- 181 # event handlers 182 #--------------------------------------------------------
183 - def _on_BTN_1_pressed(self, evt):
184 if self.IsModal(): 185 self.EndModal(wx.ID_YES) 186 else: 187 self.Close()
188 #--------------------------------------------------------
189 - def _on_BTN_2_pressed(self, evt):
190 if self.IsModal(): 191 self.EndModal(wx.ID_NO) 192 else: 193 self.Close()
194 # ======================================================================== 195 from Gnumed.wxGladeWidgets import wxgMultilineTextEntryDlg 196
197 -class cMultilineTextEntryDlg(wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg):
198 """Editor for a bit of text.""" 199
200 - def __init__(self, *args, **kwargs):
201 202 try: 203 title = kwargs['title'] 204 del kwargs['title'] 205 except KeyError: 206 title = None 207 208 try: 209 msg = kwargs['msg'] 210 del kwargs['msg'] 211 except KeyError: 212 msg = None 213 214 try: 215 data = kwargs['data'] 216 del kwargs['data'] 217 except KeyError: 218 data = None 219 220 try: 221 self.original_text = kwargs['text'] 222 del kwargs['text'] 223 except KeyError: 224 self.original_text = None 225 226 wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg.__init__(self, *args, **kwargs) 227 228 if title is not None: 229 self.SetTitle(title) 230 231 if self.original_text is not None: 232 self._TCTRL_text.SetValue(self.original_text) 233 self._BTN_restore.Enable(True) 234 235 if msg is None: 236 self._LBL_msg.Hide() 237 else: 238 self._LBL_msg.SetLabel(msg) 239 self.Layout() 240 self.Refresh() 241 242 if data is None: 243 self._TCTRL_data.Hide() 244 else: 245 self._TCTRL_data.SetValue(data) 246 self.Layout() 247 self.Refresh()
248 #-------------------------------------------------------- 249 # properties 250 #--------------------------------------------------------
251 - def _get_value(self):
252 return self._TCTRL_text.GetValue()
253 254 value = property(_get_value, lambda x:x) 255 #--------------------------------------------------------
256 - def _get_is_user_formatted(self):
257 return self._CHBOX_is_already_formatted.IsChecked()
258 259 is_user_formatted = property(_get_is_user_formatted, lambda x:x) 260 #--------------------------------------------------------
261 - def _set_enable_user_formatting(self, value):
262 self._CHBOX_is_already_formatted.Enable(value)
263 264 enable_user_formatting = property(lambda x:x, _set_enable_user_formatting) 265 #-------------------------------------------------------- 266 # event handlers 267 #--------------------------------------------------------
268 - def _on_save_button_pressed(self, evt):
269 270 if self.IsModal(): 271 self.EndModal(wx.ID_SAVE) 272 else: 273 self.Close()
274 #--------------------------------------------------------
275 - def _on_clear_button_pressed(self, evt):
276 self._TCTRL_text.SetValue(u'')
277 #--------------------------------------------------------
278 - def _on_restore_button_pressed(self, evt):
279 if self.original_text is not None: 280 self._TCTRL_text.SetValue(self.original_text)
281 # ======================================================================== 282 from Gnumed.business import gmSurgery 283 from Gnumed.wxGladeWidgets import wxgGreetingEditorDlg 284
285 -class cGreetingEditorDlg(wxgGreetingEditorDlg.wxgGreetingEditorDlg):
286
287 - def __init__(self, *args, **kwargs):
288 wxgGreetingEditorDlg.wxgGreetingEditorDlg.__init__(self, *args, **kwargs) 289 290 self.surgery = gmSurgery.gmCurrentPractice() 291 self._TCTRL_message.SetValue(self.surgery.db_logon_banner)
292 #-------------------------------------------------------- 293 # event handlers 294 #--------------------------------------------------------
295 - def _on_save_button_pressed(self, evt):
296 self.surgery.db_logon_banner = self._TCTRL_message.GetValue().strip() 297 if self.IsModal(): 298 self.EndModal(wx.ID_SAVE) 299 else: 300 self.Close()
301 # ========================================================================
302 -class cTreeExpansionHistoryMixin:
303 """TreeCtrl mixin class to record expansion history."""
304 - def __init__(self):
305 if not isinstance(self, wx.TreeCtrl): 306 raise TypeError('[%s]: mixin can only be applied to wx.TreeCtrl, not [%s]' % (cTreeExpansionHistoryMixin, self.__class__.__name__)) 307 self.expansion_state = {}
308 #-------------------------------------------------------- 309 # public API 310 #--------------------------------------------------------
311 - def snapshot_expansion(self):
312 self.__record_subtree_expansion(start_node_id = self.GetRootItem())
313 #--------------------------------------------------------
314 - def restore_expansion(self):
315 if len(self.expansion_state) == 0: 316 return True 317 self.__restore_subtree_expansion(start_node_id = self.GetRootItem())
318 #--------------------------------------------------------
319 - def print_expansion(self):
320 if len(self.expansion_state) == 0: 321 print "currently no expansion snapshot available" 322 return True 323 print "last snapshot of state of expansion" 324 print "-----------------------------------" 325 print "listing expanded nodes:" 326 for node_id in self.expansion_state.keys(): 327 print "node ID:", node_id 328 print " selected:", self.expansion_state[node_id]
329 #-------------------------------------------------------- 330 # internal API 331 #--------------------------------------------------------
332 - def __record_subtree_expansion(self, start_node_id=None):
333 """This records node expansion states based on the item label. 334 335 A side effect of this is that identically named items can 336 become unduly synchronized in their expand state after a 337 snapshot/restore cycle. 338 339 Better choices might be 340 341 id(item.GetPyData()) or 342 item.GetPyData().get_tree_uid() 343 344 where get_tree_uid(): 345 346 '[%s:%s]' % (self.__class__.__name__, id(self)) 347 348 or some such. This would survive renaming of the item. 349 350 For database items it may be useful to include the 351 primary key which would - contrary to id() - survive 352 reloads from the database. 353 """ 354 # protect against empty tree where not even 355 # a root node exists 356 if not start_node_id.IsOk(): 357 return True 358 359 if not self.IsExpanded(start_node_id): 360 return True 361 362 self.expansion_state[self.GetItemText(start_node_id)] = self.IsSelected(start_node_id) 363 364 child_id, cookie = self.GetFirstChild(start_node_id) 365 while child_id.IsOk(): 366 self.__record_subtree_expansion(start_node_id = child_id) 367 child_id, cookie = self.GetNextChild(start_node_id, cookie) 368 369 return
370 #--------------------------------------------------------
371 - def __restore_subtree_expansion(self, start_node_id=None):
372 start_node_label = self.GetItemText(start_node_id) 373 try: 374 node_selected = self.expansion_state[start_node_label] 375 except KeyError: 376 return 377 378 self.Expand(start_node_id) 379 if node_selected: 380 self.SelectItem(start_node_id) 381 382 child_id, cookie = self.GetFirstChild(start_node_id) 383 while child_id.IsOk(): 384 self.__restore_subtree_expansion(start_node_id = child_id) 385 child_id, cookie = self.GetNextChild(start_node_id, cookie) 386 387 return
388 # ========================================================================
389 -class cFileDropTarget(wx.FileDropTarget):
390 """Generic file drop target class. 391 392 Protocol: 393 Widgets being declared file drop targets 394 must provide the method: 395 396 add_filenames(filenames) 397 """ 398 #-----------------------------------------------
399 - def __init__(self, target):
400 wx.FileDropTarget.__init__(self) 401 self.target = target 402 _log.debug('setting up [%s] as file drop target', target)
403 #-----------------------------------------------
404 - def OnDropFiles(self, x, y, filenames):
405 self.target.add_filenames(filenames)
406 # ========================================================================
407 -def file2scaled_image(filename=None, height=100):
408 img_data = None 409 bitmap = None 410 rescaled_height = height 411 try: 412 img_data = wx.Image(filename, wx.BITMAP_TYPE_ANY) 413 current_width = img_data.GetWidth() 414 current_height = img_data.GetHeight() 415 # if current_width == 0: 416 # current_width = 1 417 # if current_height == 0: 418 # current_height = 1 419 rescaled_width = (float(current_width) / current_height) * rescaled_height 420 img_data.Rescale(rescaled_width, rescaled_height, quality = wx.IMAGE_QUALITY_HIGH) # w, h 421 bitmap = wx.BitmapFromImage(img_data) 422 del img_data 423 except StandardError: 424 _log.exception('cannot load image from [%s]', filename) 425 del img_data 426 del bitmap 427 return None 428 429 return bitmap
430 # ========================================================================
431 -def gm_show_error(aMessage = None, aTitle = None):
432 if aMessage is None: 433 aMessage = _('programmer forgot to specify error message') 434 435 aMessage += _("\n\nPlease consult the error log for all the gory details !") 436 437 if aTitle is None: 438 aTitle = _('generic error message') 439 440 dlg = wx.MessageDialog ( 441 parent = None, 442 message = aMessage, 443 caption = aTitle, 444 style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP 445 ) 446 dlg.ShowModal() 447 dlg.Destroy() 448 return True
449 #-------------------------------------------------------------------------
450 -def gm_show_info(aMessage = None, aTitle = None):
451 if aMessage is None: 452 aMessage = _('programmer forgot to specify info message') 453 454 if aTitle is None: 455 aTitle = _('generic info message') 456 457 dlg = wx.MessageDialog ( 458 parent = None, 459 message = aMessage, 460 caption = aTitle, 461 style = wx.OK | wx.ICON_INFORMATION | wx.STAY_ON_TOP 462 ) 463 dlg.ShowModal() 464 dlg.Destroy() 465 return True
466 #-------------------------------------------------------------------------
467 -def gm_show_warning(aMessage=None, aTitle=None):
468 if aMessage is None: 469 aMessage = _('programmer forgot to specify warning') 470 471 if aTitle is None: 472 aTitle = _('generic warning message') 473 474 dlg = wx.MessageDialog ( 475 parent = None, 476 message = aMessage, 477 caption = aTitle, 478 style = wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP 479 ) 480 dlg.ShowModal() 481 dlg.Destroy() 482 return True
483 #-------------------------------------------------------------------------
484 -def gm_show_question(aMessage='programmer forgot to specify question', aTitle='generic user question dialog', cancel_button=False, question=None, title=None):
485 if cancel_button: 486 style = wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION | wx.STAY_ON_TOP 487 else: 488 style = wx.YES_NO | wx.ICON_QUESTION | wx.STAY_ON_TOP 489 490 if question is None: 491 question = aMessage 492 if title is None: 493 title = aTitle 494 495 dlg = wx.MessageDialog(None, question, title, style) 496 btn_pressed = dlg.ShowModal() 497 dlg.Destroy() 498 499 if btn_pressed == wx.ID_YES: 500 return True 501 elif btn_pressed == wx.ID_NO: 502 return False 503 else: 504 return None
505 #====================================================================== 506 if __name__ == '__main__': 507 508 if len(sys.argv) < 2: 509 sys.exit() 510 511 if sys.argv[1] != 'test': 512 sys.exit() 513 514 from Gnumed.pycommon import gmI18N 515 gmI18N.activate_locale() 516 gmI18N.install_domain(domain='gnumed') 517 518 #------------------------------------------------------------------
519 - def test_scale_img():
520 app = wx.App() 521 img = file2scaled_image(filename = sys.argv[2]) 522 print img 523 print img.Height 524 print img.Width
525 #------------------------------------------------------------------
526 - def test_sql_logic_prw():
527 app = wx.PyWidgetTester(size = (200, 50)) 528 prw = cThreeValuedLogicPhraseWheel(parent = app.frame, id = -1) 529 app.frame.Show(True) 530 app.MainLoop() 531 532 return True
533 #------------------------------------------------------------------ 534 #test_scale_img() 535 test_sql_logic_prw() 536 537 #====================================================================== 538