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 self._TCTRL_text.SetFocus()
250 #-------------------------------------------------------- 251 # properties 252 #--------------------------------------------------------
253 - def _get_value(self):
254 return self._TCTRL_text.GetValue()
255 256 value = property(_get_value, lambda x:x) 257 #--------------------------------------------------------
258 - def _get_is_user_formatted(self):
259 return self._CHBOX_is_already_formatted.IsChecked()
260 261 is_user_formatted = property(_get_is_user_formatted, lambda x:x) 262 #--------------------------------------------------------
263 - def _set_enable_user_formatting(self, value):
264 self._CHBOX_is_already_formatted.Enable(value)
265 266 enable_user_formatting = property(lambda x:x, _set_enable_user_formatting) 267 #-------------------------------------------------------- 268 # event handlers 269 #--------------------------------------------------------
270 - def _on_save_button_pressed(self, evt):
271 272 if self.IsModal(): 273 self.EndModal(wx.ID_SAVE) 274 else: 275 self.Close()
276 #--------------------------------------------------------
277 - def _on_clear_button_pressed(self, evt):
278 self._TCTRL_text.SetValue(u'')
279 #--------------------------------------------------------
280 - def _on_restore_button_pressed(self, evt):
281 if self.original_text is not None: 282 self._TCTRL_text.SetValue(self.original_text)
283 # ======================================================================== 284 from Gnumed.business import gmSurgery 285 from Gnumed.wxGladeWidgets import wxgGreetingEditorDlg 286
287 -class cGreetingEditorDlg(wxgGreetingEditorDlg.wxgGreetingEditorDlg):
288
289 - def __init__(self, *args, **kwargs):
290 wxgGreetingEditorDlg.wxgGreetingEditorDlg.__init__(self, *args, **kwargs) 291 292 self.surgery = gmSurgery.gmCurrentPractice() 293 self._TCTRL_message.SetValue(self.surgery.db_logon_banner)
294 #-------------------------------------------------------- 295 # event handlers 296 #--------------------------------------------------------
297 - def _on_save_button_pressed(self, evt):
298 self.surgery.db_logon_banner = self._TCTRL_message.GetValue().strip() 299 if self.IsModal(): 300 self.EndModal(wx.ID_SAVE) 301 else: 302 self.Close()
303 # ========================================================================
304 -class cTreeExpansionHistoryMixin:
305 """TreeCtrl mixin class to record expansion history."""
306 - def __init__(self):
307 if not isinstance(self, wx.TreeCtrl): 308 raise TypeError('[%s]: mixin can only be applied to wx.TreeCtrl, not [%s]' % (cTreeExpansionHistoryMixin, self.__class__.__name__)) 309 self.expansion_state = {}
310 #-------------------------------------------------------- 311 # public API 312 #--------------------------------------------------------
313 - def snapshot_expansion(self):
314 self.__record_subtree_expansion(start_node_id = self.GetRootItem())
315 #--------------------------------------------------------
316 - def restore_expansion(self):
317 if len(self.expansion_state) == 0: 318 return True 319 self.__restore_subtree_expansion(start_node_id = self.GetRootItem())
320 #--------------------------------------------------------
321 - def print_expansion(self):
322 if len(self.expansion_state) == 0: 323 print "currently no expansion snapshot available" 324 return True 325 print "last snapshot of state of expansion" 326 print "-----------------------------------" 327 print "listing expanded nodes:" 328 for node_id in self.expansion_state.keys(): 329 print "node ID:", node_id 330 print " selected:", self.expansion_state[node_id]
331 #-------------------------------------------------------- 332 # internal API 333 #--------------------------------------------------------
334 - def __record_subtree_expansion(self, start_node_id=None):
335 """This records node expansion states based on the item label. 336 337 A side effect of this is that identically named items can 338 become unduly synchronized in their expand state after a 339 snapshot/restore cycle. 340 341 Better choices might be 342 343 id(item.GetPyData()) or 344 item.GetPyData().get_tree_uid() 345 346 where get_tree_uid(): 347 348 '[%s:%s]' % (self.__class__.__name__, id(self)) 349 350 or some such. This would survive renaming of the item. 351 352 For database items it may be useful to include the 353 primary key which would - contrary to id() - survive 354 reloads from the database. 355 """ 356 # protect against empty tree where not even 357 # a root node exists 358 if not start_node_id.IsOk(): 359 return True 360 361 if not self.IsExpanded(start_node_id): 362 return True 363 364 self.expansion_state[self.GetItemText(start_node_id)] = self.IsSelected(start_node_id) 365 366 child_id, cookie = self.GetFirstChild(start_node_id) 367 while child_id.IsOk(): 368 self.__record_subtree_expansion(start_node_id = child_id) 369 child_id, cookie = self.GetNextChild(start_node_id, cookie) 370 371 return
372 #--------------------------------------------------------
373 - def __restore_subtree_expansion(self, start_node_id=None):
374 start_node_label = self.GetItemText(start_node_id) 375 try: 376 node_selected = self.expansion_state[start_node_label] 377 except KeyError: 378 return 379 380 self.Expand(start_node_id) 381 if node_selected: 382 self.SelectItem(start_node_id) 383 384 child_id, cookie = self.GetFirstChild(start_node_id) 385 while child_id.IsOk(): 386 self.__restore_subtree_expansion(start_node_id = child_id) 387 child_id, cookie = self.GetNextChild(start_node_id, cookie) 388 389 return
390 # ========================================================================
391 -class cFileDropTarget(wx.FileDropTarget):
392 """Generic file drop target class. 393 394 Protocol: 395 Widgets being declared file drop targets 396 must provide the method: 397 398 add_filenames(filenames) 399 """ 400 #-----------------------------------------------
401 - def __init__(self, target):
402 wx.FileDropTarget.__init__(self) 403 self.target = target 404 _log.debug('setting up [%s] as file drop target', target)
405 #-----------------------------------------------
406 - def OnDropFiles(self, x, y, filenames):
407 self.target.add_filenames(filenames)
408 # ========================================================================
409 -def file2scaled_image(filename=None, height=100):
410 img_data = None 411 bitmap = None 412 rescaled_height = height 413 try: 414 img_data = wx.Image(filename, wx.BITMAP_TYPE_ANY) 415 current_width = img_data.GetWidth() 416 current_height = img_data.GetHeight() 417 # if current_width == 0: 418 # current_width = 1 419 # if current_height == 0: 420 # current_height = 1 421 rescaled_width = (float(current_width) / current_height) * rescaled_height 422 img_data.Rescale(rescaled_width, rescaled_height, quality = wx.IMAGE_QUALITY_HIGH) # w, h 423 bitmap = wx.BitmapFromImage(img_data) 424 del img_data 425 except StandardError: 426 _log.exception('cannot load image from [%s]', filename) 427 del img_data 428 del bitmap 429 return None 430 431 return bitmap
432 # ========================================================================
433 -def gm_show_error(aMessage = None, aTitle = None):
434 if aMessage is None: 435 aMessage = _('programmer forgot to specify error message') 436 437 aMessage += _("\n\nPlease consult the error log for all the gory details !") 438 439 if aTitle is None: 440 aTitle = _('generic error message') 441 442 dlg = wx.MessageDialog ( 443 parent = None, 444 message = aMessage, 445 caption = aTitle, 446 style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP 447 ) 448 dlg.ShowModal() 449 dlg.Destroy() 450 return True
451 #-------------------------------------------------------------------------
452 -def gm_show_info(aMessage = None, aTitle = None):
453 if aMessage is None: 454 aMessage = _('programmer forgot to specify info message') 455 456 if aTitle is None: 457 aTitle = _('generic info message') 458 459 dlg = wx.MessageDialog ( 460 parent = None, 461 message = aMessage, 462 caption = aTitle, 463 style = wx.OK | wx.ICON_INFORMATION | wx.STAY_ON_TOP 464 ) 465 dlg.ShowModal() 466 dlg.Destroy() 467 return True
468 #-------------------------------------------------------------------------
469 -def gm_show_warning(aMessage=None, aTitle=None):
470 if aMessage is None: 471 aMessage = _('programmer forgot to specify warning') 472 473 if aTitle is None: 474 aTitle = _('generic warning message') 475 476 dlg = wx.MessageDialog ( 477 parent = None, 478 message = aMessage, 479 caption = aTitle, 480 style = wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP 481 ) 482 dlg.ShowModal() 483 dlg.Destroy() 484 return True
485 #-------------------------------------------------------------------------
486 -def gm_show_question(aMessage='programmer forgot to specify question', aTitle='generic user question dialog', cancel_button=False, question=None, title=None):
487 if cancel_button: 488 style = wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION | wx.STAY_ON_TOP 489 else: 490 style = wx.YES_NO | wx.ICON_QUESTION | wx.STAY_ON_TOP 491 492 if question is None: 493 question = aMessage 494 if title is None: 495 title = aTitle 496 497 dlg = wx.MessageDialog(None, question, title, style) 498 btn_pressed = dlg.ShowModal() 499 dlg.Destroy() 500 501 if btn_pressed == wx.ID_YES: 502 return True 503 elif btn_pressed == wx.ID_NO: 504 return False 505 else: 506 return None
507 #====================================================================== 508 if __name__ == '__main__': 509 510 if len(sys.argv) < 2: 511 sys.exit() 512 513 if sys.argv[1] != 'test': 514 sys.exit() 515 516 from Gnumed.pycommon import gmI18N 517 gmI18N.activate_locale() 518 gmI18N.install_domain(domain='gnumed') 519 520 #------------------------------------------------------------------
521 - def test_scale_img():
522 app = wx.App() 523 img = file2scaled_image(filename = sys.argv[2]) 524 print img 525 print img.Height 526 print img.Width
527 #------------------------------------------------------------------
528 - def test_sql_logic_prw():
529 app = wx.PyWidgetTester(size = (200, 50)) 530 prw = cThreeValuedLogicPhraseWheel(parent = app.frame, id = -1) 531 app.frame.Show(True) 532 app.MainLoop() 533 534 return True
535 #------------------------------------------------------------------ 536 #test_scale_img() 537 test_sql_logic_prw() 538 539 #====================================================================== 540