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 131 del kwargs['caption'] 132 del kwargs['question'] 133 del kwargs['button_defs'] 134 135 wxg3ButtonQuestionDlg.wxg3ButtonQuestionDlg.__init__(self, *args, **kwargs) 136 137 self.SetTitle(title = caption) 138 self._LBL_question.SetLabel(label = question) 139 140 buttons = [self._BTN_1, self._BTN_2, self._BTN_3] 141 for idx in range(len(button_defs)): 142 buttons[idx].SetLabel(label = button_defs[idx]['label']) 143 buttons[idx].SetToolTipString(button_defs[idx]['tooltip']) 144 try: 145 if button_defs[idx]['default'] is True: 146 buttons[idx].SetDefault() 147 buttons[idx].SetFocus() 148 except KeyError: 149 pass 150 151 self.Fit()
152 #-------------------------------------------------------- 153 # event handlers 154 #--------------------------------------------------------
155 - def _on_BTN_1_pressed(self, evt):
156 if self.IsModal(): 157 self.EndModal(wx.ID_YES) 158 else: 159 self.Close()
160 #--------------------------------------------------------
161 - def _on_BTN_2_pressed(self, evt):
162 if self.IsModal(): 163 self.EndModal(wx.ID_NO) 164 else: 165 self.Close()
166 # ======================================================================== 167 from Gnumed.wxGladeWidgets import wxgMultilineTextEntryDlg 168
169 -class cMultilineTextEntryDlg(wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg):
170 """Editor for a bit of text.""" 171
172 - def __init__(self, *args, **kwargs):
173 174 try: 175 title = kwargs['title'] 176 del kwargs['title'] 177 except KeyError: 178 title = None 179 180 try: 181 msg = kwargs['msg'] 182 del kwargs['msg'] 183 except KeyError: 184 msg = None 185 186 try: 187 data = kwargs['data'] 188 del kwargs['data'] 189 except KeyError: 190 data = None 191 192 try: 193 self.original_text = kwargs['text'] 194 del kwargs['text'] 195 except KeyError: 196 self.original_text = None 197 198 wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg.__init__(self, *args, **kwargs) 199 200 if title is not None: 201 self.SetTitle(title) 202 203 if self.original_text is not None: 204 self._TCTRL_text.SetValue(self.original_text) 205 self._BTN_restore.Enable(True) 206 207 if msg is None: 208 self._LBL_msg.Hide() 209 else: 210 self._LBL_msg.SetLabel(msg) 211 self.Layout() 212 self.Refresh() 213 214 if data is None: 215 self._TCTRL_data.Hide() 216 else: 217 self._TCTRL_data.SetValue(data) 218 self.Layout() 219 self.Refresh()
220 #-------------------------------------------------------- 221 # properties 222 #--------------------------------------------------------
223 - def _get_value(self):
224 return self._TCTRL_text.GetValue()
225 226 value = property(_get_value, lambda x:x) 227 #--------------------------------------------------------
228 - def _get_is_user_formatted(self):
229 return self._CHBOX_is_already_formatted.IsChecked()
230 231 is_user_formatted = property(_get_is_user_formatted, lambda x:x) 232 #--------------------------------------------------------
233 - def _set_enable_user_formatting(self, value):
234 self._CHBOX_is_already_formatted.Enable(value)
235 236 enable_user_formatting = property(lambda x:x, _set_enable_user_formatting) 237 #-------------------------------------------------------- 238 # event handlers 239 #--------------------------------------------------------
240 - def _on_save_button_pressed(self, evt):
241 242 if self.IsModal(): 243 self.EndModal(wx.ID_SAVE) 244 else: 245 self.Close()
246 #--------------------------------------------------------
247 - def _on_clear_button_pressed(self, evt):
248 self._TCTRL_text.SetValue(u'')
249 #--------------------------------------------------------
250 - def _on_restore_button_pressed(self, evt):
251 if self.original_text is not None: 252 self._TCTRL_text.SetValue(self.original_text)
253 # ======================================================================== 254 from Gnumed.business import gmSurgery 255 from Gnumed.wxGladeWidgets import wxgGreetingEditorDlg 256
257 -class cGreetingEditorDlg(wxgGreetingEditorDlg.wxgGreetingEditorDlg):
258
259 - def __init__(self, *args, **kwargs):
260 wxgGreetingEditorDlg.wxgGreetingEditorDlg.__init__(self, *args, **kwargs) 261 262 self.surgery = gmSurgery.gmCurrentPractice() 263 self._TCTRL_message.SetValue(self.surgery.db_logon_banner)
264 #-------------------------------------------------------- 265 # event handlers 266 #--------------------------------------------------------
267 - def _on_save_button_pressed(self, evt):
268 self.surgery.db_logon_banner = self._TCTRL_message.GetValue().strip() 269 if self.IsModal(): 270 self.EndModal(wx.ID_SAVE) 271 else: 272 self.Close()
273 # ========================================================================
274 -class cTreeExpansionHistoryMixin:
275 """TreeCtrl mixin class to record expansion history."""
276 - def __init__(self):
277 if not isinstance(self, wx.TreeCtrl): 278 raise TypeError('[%s]: mixin can only be applied to wx.TreeCtrl, not [%s]' % (cTreeExpansionHistoryMixin, self.__class__.__name__)) 279 self.expansion_state = {}
280 #-------------------------------------------------------- 281 # public API 282 #--------------------------------------------------------
283 - def snapshot_expansion(self):
284 self.__record_subtree_expansion(start_node_id = self.GetRootItem())
285 #--------------------------------------------------------
286 - def restore_expansion(self):
287 if len(self.expansion_state) == 0: 288 return True 289 self.__restore_subtree_expansion(start_node_id = self.GetRootItem())
290 #--------------------------------------------------------
291 - def print_expansion(self):
292 if len(self.expansion_state) == 0: 293 print "currently no expansion snapshot available" 294 return True 295 print "last snapshot of state of expansion" 296 print "-----------------------------------" 297 print "listing expanded nodes:" 298 for node_id in self.expansion_state.keys(): 299 print "node ID:", node_id 300 print " selected:", self.expansion_state[node_id]
301 #-------------------------------------------------------- 302 # internal API 303 #--------------------------------------------------------
304 - def __record_subtree_expansion(self, start_node_id=None):
305 """This records node expansion states based on the item label. 306 307 A side effect of this is that identically named items can 308 become unduly synchronized in their expand state after a 309 snapshot/restore cycle. 310 311 Better choices might be 312 313 id(item.GetPyData()) or 314 item.GetPyData().get_tree_uid() 315 316 where get_tree_uid(): 317 318 '[%s:%s]' % (self.__class__.__name__, id(self)) 319 320 or some such. This would survive renaming of the item. 321 322 For database items it may be useful to include the 323 primary key which would - contrary to id() - survive 324 reloads from the database. 325 """ 326 # protect against empty tree where not even 327 # a root node exists 328 if not start_node_id.IsOk(): 329 return True 330 331 if not self.IsExpanded(start_node_id): 332 return True 333 334 self.expansion_state[self.GetItemText(start_node_id)] = self.IsSelected(start_node_id) 335 336 child_id, cookie = self.GetFirstChild(start_node_id) 337 while child_id.IsOk(): 338 self.__record_subtree_expansion(start_node_id = child_id) 339 child_id, cookie = self.GetNextChild(start_node_id, cookie) 340 341 return
342 #--------------------------------------------------------
343 - def __restore_subtree_expansion(self, start_node_id=None):
344 start_node_label = self.GetItemText(start_node_id) 345 try: 346 node_selected = self.expansion_state[start_node_label] 347 except KeyError: 348 return 349 350 self.Expand(start_node_id) 351 if node_selected: 352 self.SelectItem(start_node_id) 353 354 child_id, cookie = self.GetFirstChild(start_node_id) 355 while child_id.IsOk(): 356 self.__restore_subtree_expansion(start_node_id = child_id) 357 child_id, cookie = self.GetNextChild(start_node_id, cookie) 358 359 return
360 # ========================================================================
361 -class cFileDropTarget(wx.FileDropTarget):
362 """Generic file drop target class. 363 364 Protocol: 365 Widgets being declared file drop targets 366 must provide the method: 367 368 add_filenames(filenames) 369 """ 370 #-----------------------------------------------
371 - def __init__(self, target):
372 wx.FileDropTarget.__init__(self) 373 self.target = target
374 #-----------------------------------------------
375 - def OnDropFiles(self, x, y, filenames):
376 self.target.add_filenames(filenames)
377 # ========================================================================
378 -def file2scaled_image(filename=None, height=100):
379 img_data = None 380 bitmap = None 381 rescaled_height = height 382 try: 383 img_data = wx.Image(filename, wx.BITMAP_TYPE_ANY) 384 current_width = img_data.GetWidth() 385 current_height = img_data.GetHeight() 386 # if current_width == 0: 387 # current_width = 1 388 # if current_height == 0: 389 # current_height = 1 390 rescaled_width = (float(current_width) / current_height) * rescaled_height 391 img_data.Rescale(rescaled_width, rescaled_height, quality = wx.IMAGE_QUALITY_HIGH) # w, h 392 bitmap = wx.BitmapFromImage(img_data) 393 del img_data 394 except StandardError: 395 _log.exception('cannot load image from [%s]', filename) 396 del img_data 397 del bitmap 398 return None 399 400 return bitmap
401 # ========================================================================
402 -def gm_show_error(aMessage = None, aTitle = None):
403 if aMessage is None: 404 aMessage = _('programmer forgot to specify error message') 405 406 aMessage += _("\n\nPlease consult the error log for all the gory details !") 407 408 if aTitle is None: 409 aTitle = _('generic error message') 410 411 dlg = wx.MessageDialog ( 412 parent = None, 413 message = aMessage, 414 caption = aTitle, 415 style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP 416 ) 417 dlg.ShowModal() 418 dlg.Destroy() 419 return True
420 #-------------------------------------------------------------------------
421 -def gm_show_info(aMessage = None, aTitle = None):
422 if aMessage is None: 423 aMessage = _('programmer forgot to specify info message') 424 425 if aTitle is None: 426 aTitle = _('generic info message') 427 428 dlg = wx.MessageDialog ( 429 parent = None, 430 message = aMessage, 431 caption = aTitle, 432 style = wx.OK | wx.ICON_INFORMATION | wx.STAY_ON_TOP 433 ) 434 dlg.ShowModal() 435 dlg.Destroy() 436 return True
437 #-------------------------------------------------------------------------
438 -def gm_show_warning(aMessage=None, aTitle=None):
439 if aMessage is None: 440 aMessage = _('programmer forgot to specify warning') 441 442 if aTitle is None: 443 aTitle = _('generic warning message') 444 445 dlg = wx.MessageDialog ( 446 parent = None, 447 message = aMessage, 448 caption = aTitle, 449 style = wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP 450 ) 451 dlg.ShowModal() 452 dlg.Destroy() 453 return True
454 #-------------------------------------------------------------------------
455 -def gm_show_question(aMessage='programmer forgot to specify question', aTitle='generic user question dialog', cancel_button=False):
456 if cancel_button: 457 style = wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION | wx.STAY_ON_TOP 458 else: 459 style = wx.YES_NO | wx.ICON_QUESTION | wx.STAY_ON_TOP 460 461 dlg = wx.MessageDialog ( 462 None, 463 aMessage, 464 aTitle, 465 style 466 ) 467 btn_pressed = dlg.ShowModal() 468 dlg.Destroy() 469 470 if btn_pressed == wx.ID_YES: 471 return True 472 elif btn_pressed == wx.ID_NO: 473 return False 474 else: 475 return None
476 #====================================================================== 477 if __name__ == '__main__': 478 479 if len(sys.argv) < 2: 480 sys.exit() 481 482 if sys.argv[1] != 'test': 483 sys.exit() 484 485 from Gnumed.pycommon import gmI18N 486 gmI18N.activate_locale() 487 gmI18N.install_domain(domain='gnumed') 488 489 #------------------------------------------------------------------
490 - def test_scale_img():
491 app = wx.App() 492 img = file2scaled_image(filename = sys.argv[2]) 493 print img 494 print img.Height 495 print img.Width
496 #------------------------------------------------------------------
497 - def test_sql_logic_prw():
498 app = wx.PyWidgetTester(size = (200, 50)) 499 prw = cThreeValuedLogicPhraseWheel(parent = app.frame, id = -1) 500 app.frame.Show(True) 501 app.MainLoop() 502 503 return True
504 #------------------------------------------------------------------ 505 #test_scale_img() 506 test_sql_logic_prw() 507 508 #====================================================================== 509