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  __author__  = "K. Hilbert <Karsten.Hilbert@gmx.net>" 
  9  __license__ = "GPL v2 or later (details at http://www.gnu.org)" 
 10   
 11  import os 
 12  import logging 
 13  import sys 
 14  import io 
 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.pycommon import gmExceptions 
 24  from Gnumed.pycommon import gmLog2 
 25  from Gnumed.pycommon import gmTools 
 26  from Gnumed.pycommon import gmDispatcher 
 27  from Gnumed.wxpython import gmPhraseWheel 
 28   
 29   
 30  _log = logging.getLogger('gm.main') 
 31  # ======================================================================== 
32 -class cThreeValuedLogicPhraseWheel(gmPhraseWheel.cPhraseWheel):
33
34 - def __init__(self, *args, **kwargs):
35 36 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 37 38 items = [ 39 {'list_label': _('Yes: + / ! / 1'), 'field_label': _('yes'), 'data': True, 'weight': 0}, 40 {'list_label': _('No: - / 0'), 'field_label': _('no'), 'data': False, 'weight': 1}, 41 {'list_label': _('Unknown: ?'), 'field_label': _('unknown'), 'data': None, 'weight': 2}, 42 ] 43 mp = gmMatchProvider.cMatchProvider_FixedList(items) 44 mp.setThresholds(1, 1, 2) 45 mp.word_separators = '[ :/]+' 46 mp.word_separators = None 47 mp.ignored_chars = r"[.'\\(){}\[\]<>~#*$%^_=&@\t23456]+" + r'"' 48 49 self.matcher = mp
50 # ======================================================================== 51 from Gnumed.wxGladeWidgets import wxg2ButtonQuestionDlg 52
53 -class c2ButtonQuestionDlg(wxg2ButtonQuestionDlg.wxg2ButtonQuestionDlg):
54
55 - def __init__(self, *args, **kwargs):
56 57 caption = kwargs['caption'] 58 question = kwargs['question'] 59 button_defs = kwargs['button_defs'][:2] 60 del kwargs['caption'] 61 del kwargs['question'] 62 del kwargs['button_defs'] 63 64 try: 65 show_checkbox = kwargs['show_checkbox'] 66 del kwargs['show_checkbox'] 67 except KeyError: 68 show_checkbox = False 69 70 try: 71 checkbox_msg = kwargs['checkbox_msg'] 72 del kwargs['checkbox_msg'] 73 except KeyError: 74 checkbox_msg = None 75 76 try: 77 checkbox_tooltip = kwargs['checkbox_tooltip'] 78 del kwargs['checkbox_tooltip'] 79 except KeyError: 80 checkbox_tooltip = None 81 82 wxg2ButtonQuestionDlg.wxg2ButtonQuestionDlg.__init__(self, *args, **kwargs) 83 84 if not caption.startswith('GMd: '): 85 caption = 'GMd: %s' % caption 86 self.SetTitle(title = caption) 87 self._LBL_question.SetLabel(label = question) 88 89 if not show_checkbox: 90 self._CHBOX_dont_ask_again.Hide() 91 else: 92 if checkbox_msg is not None: 93 self._CHBOX_dont_ask_again.SetLabel(checkbox_msg) 94 if checkbox_tooltip is not None: 95 self._CHBOX_dont_ask_again.SetToolTip(checkbox_tooltip) 96 97 buttons = [self._BTN_1, self._BTN_2] 98 for idx in range(len(button_defs)): 99 buttons[idx].SetLabel(label = button_defs[idx]['label']) 100 buttons[idx].SetToolTip(button_defs[idx]['tooltip']) 101 try: 102 if button_defs[idx]['default'] is True: 103 buttons[idx].SetDefault() 104 buttons[idx].SetFocus() 105 except KeyError: 106 pass 107 108 self.Fit()
109 #--------------------------------------------------------
110 - def checkbox_is_checked(self):
111 return self._CHBOX_dont_ask_again.IsChecked()
112 #-------------------------------------------------------- 113 # event handlers 114 #--------------------------------------------------------
115 - def _on_BTN_1_pressed(self, evt):
116 if self.IsModal(): 117 self.EndModal(wx.ID_YES) 118 else: 119 self.Close()
120 #--------------------------------------------------------
121 - def _on_BTN_2_pressed(self, evt):
122 if self.IsModal(): 123 self.EndModal(wx.ID_NO) 124 else: 125 self.Close()
126 127 # ======================================================================== 128 from Gnumed.wxGladeWidgets import wxg3ButtonQuestionDlg 129
130 -class c3ButtonQuestionDlg(wxg3ButtonQuestionDlg.wxg3ButtonQuestionDlg):
131
132 - def __init__(self, *args, **kwargs):
133 """Initialize. 134 135 button_defs = [ 136 # tooltip and default are optional 137 {'label': _(''), 'tooltip': _(''), 'default': True/False}, 138 {'label': _(''), 'tooltip': _(''), 'default': True/False}, 139 {'label': _(''), 'tooltip': _(''), 'default': True/False} 140 ] 141 """ 142 caption = kwargs['caption'] 143 question = kwargs['question'] 144 button_defs = kwargs['button_defs'][:3] 145 del kwargs['caption'] 146 del kwargs['question'] 147 del kwargs['button_defs'] 148 149 try: 150 show_checkbox = kwargs['show_checkbox'] 151 del kwargs['show_checkbox'] 152 except KeyError: 153 show_checkbox = False 154 155 try: 156 checkbox_msg = kwargs['checkbox_msg'] 157 del kwargs['checkbox_msg'] 158 except KeyError: 159 checkbox_msg = None 160 161 try: 162 checkbox_tooltip = kwargs['checkbox_tooltip'] 163 del kwargs['checkbox_tooltip'] 164 except KeyError: 165 checkbox_tooltip = None 166 167 wxg3ButtonQuestionDlg.wxg3ButtonQuestionDlg.__init__(self, *args, **kwargs) 168 169 if not caption.startswith('GMd: '): 170 caption = 'GMd: %s' % caption 171 self.SetTitle(title = caption) 172 self._LBL_question.SetLabel(label = question) 173 174 if not show_checkbox: 175 self._CHBOX_dont_ask_again.Hide() 176 else: 177 if checkbox_msg is not None: 178 self._CHBOX_dont_ask_again.SetLabel(checkbox_msg) 179 if checkbox_tooltip is not None: 180 self._CHBOX_dont_ask_again.SetToolTip(checkbox_tooltip) 181 182 buttons = [self._BTN_1, self._BTN_2, self._BTN_3] 183 for idx in range(len(button_defs)): 184 buttons[idx].SetLabel(label = button_defs[idx]['label']) 185 try: 186 buttons[idx].SetToolTip(button_defs[idx]['tooltip']) 187 except KeyError: 188 pass 189 try: 190 if button_defs[idx]['default'] is True: 191 buttons[idx].SetDefault() 192 buttons[idx].SetFocus() 193 except KeyError: 194 pass 195 196 self.Fit()
197 #--------------------------------------------------------
198 - def checkbox_is_checked(self):
199 return self._CHBOX_dont_ask_again.IsChecked()
200 201 #-------------------------------------------------------- 202 # event handlers 203 #--------------------------------------------------------
204 - def _on_BTN_1_pressed(self, evt):
205 if self.IsModal(): 206 self.EndModal(wx.ID_YES) 207 else: 208 self.Close()
209 210 #--------------------------------------------------------
211 - def _on_BTN_2_pressed(self, evt):
212 if self.IsModal(): 213 self.EndModal(wx.ID_NO) 214 else: 215 self.Close()
216 217 # ======================================================================== 218 from Gnumed.wxGladeWidgets import wxgMultilineTextEntryDlg 219
220 -class cMultilineTextEntryDlg(wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg):
221 """Editor for a bit of text.""" 222
223 - def __init__(self, *args, **kwargs):
224 225 try: 226 title = kwargs['title'] 227 del kwargs['title'] 228 except KeyError: 229 title = None 230 231 try: 232 msg = kwargs['msg'] 233 del kwargs['msg'] 234 except KeyError: 235 msg = None 236 237 try: 238 data = kwargs['data'] 239 del kwargs['data'] 240 except KeyError: 241 data = None 242 243 try: 244 self.original_text = kwargs['text'] 245 del kwargs['text'] 246 except KeyError: 247 self.original_text = None 248 249 wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg.__init__(self, *args, **kwargs) 250 251 if title is not None: 252 if not title.startswith('GMd: '): 253 title = 'GMd: %s' % title 254 self.SetTitle(title) 255 256 if self.original_text is not None: 257 self._TCTRL_text.SetValue(self.original_text) 258 self._BTN_restore.Enable(True) 259 260 if msg is None: 261 self._LBL_msg.Hide() 262 else: 263 self._LBL_msg.SetLabel(msg) 264 self.Layout() 265 self.Refresh() 266 267 if data is None: 268 self._TCTRL_data.Hide() 269 else: 270 self._TCTRL_data.SetValue(data) 271 self.Layout() 272 self.Refresh() 273 274 self._TCTRL_text.SetFocus()
275 #-------------------------------------------------------- 276 # properties 277 #--------------------------------------------------------
278 - def _get_value(self):
279 return self._TCTRL_text.GetValue()
280 281 value = property(_get_value, lambda x:x) 282 #--------------------------------------------------------
283 - def _get_is_user_formatted(self):
284 return self._CHBOX_is_already_formatted.IsChecked()
285 286 is_user_formatted = property(_get_is_user_formatted, lambda x:x) 287 #--------------------------------------------------------
288 - def _set_enable_user_formatting(self, value):
289 self._CHBOX_is_already_formatted.Enable(value)
290 291 enable_user_formatting = property(lambda x:x, _set_enable_user_formatting) 292 #-------------------------------------------------------- 293 # event handlers 294 #--------------------------------------------------------
295 - def _on_save_button_pressed(self, evt):
296 297 if self.IsModal(): 298 self.EndModal(wx.ID_SAVE) 299 else: 300 self.Close()
301 #--------------------------------------------------------
302 - def _on_clear_button_pressed(self, evt):
303 self._TCTRL_text.SetValue('')
304 #--------------------------------------------------------
305 - def _on_restore_button_pressed(self, evt):
306 if self.original_text is not None: 307 self._TCTRL_text.SetValue(self.original_text)
308 309 # ========================================================================
310 -def clipboard2text():
311 312 if wx.TheClipboard.IsOpened(): 313 return False 314 315 if not wx.TheClipboard.Open(): 316 return False 317 318 data_obj = wx.TextDataObject() 319 got_it = wx.TheClipboard.GetData(data_obj) 320 if got_it: 321 txt = data_obj.Text 322 wx.TheClipboard.Close() 323 return txt 324 325 wx.TheClipboard.Close() 326 return None
327 328 #-------------------------------------------------------------------------
329 -def clipboard2file(check_for_filename=False):
330 331 if wx.TheClipboard.IsOpened(): 332 return False 333 334 if not wx.TheClipboard.Open(): 335 return False 336 337 data_obj = wx.TextDataObject() 338 got_it = wx.TheClipboard.GetData(data_obj) 339 if got_it: 340 clipboard_text_content = data_obj.Text 341 wx.TheClipboard.Close() 342 if check_for_filename: 343 try: 344 io.open(clipboard_text_content).close() 345 return clipboard_text_content 346 except IOError: 347 _log.exception('clipboard does not seem to hold filename: %s', clipboard_text_content) 348 fname = gmTools.get_unique_filename(prefix = 'gm-clipboard-', suffix = '.txt') 349 target_file = io.open(fname, mode = 'wt', encoding = 'utf8') 350 target_file.write(clipboard_text_content) 351 target_file.close() 352 return fname 353 354 data_obj = wx.BitmapDataObject() 355 got_it = wx.TheClipboard.GetData(data_obj) 356 if got_it: 357 fname = gmTools.get_unique_filename(prefix = 'gm-clipboard-', suffix = '.png') 358 bmp = data_obj.Bitmap.SaveFile(fname, wx.BITMAP_TYPE_PNG) 359 wx.TheClipboard.Close() 360 return fname 361 362 wx.TheClipboard.Close() 363 return None
364 365 #-------------------------------------------------------------------------
366 -def text2clipboard(text=None, announce_result=False):
367 if wx.TheClipboard.IsOpened(): 368 return False 369 if not wx.TheClipboard.Open(): 370 return False 371 data_obj = wx.TextDataObject() 372 data_obj.SetText(text) 373 wx.TheClipboard.SetData(data_obj) 374 wx.TheClipboard.Close() 375 if announce_result: 376 gmDispatcher.send(signal = 'statustext', msg = _('The text has been copied into the clipboard.'), beep = False) 377 return True
378 379 #-------------------------------------------------------------------------
380 -def file2clipboard(filename=None, announce_result=False):
381 f = io.open(filename, mode = 'rt', encoding = 'utf8') 382 result = text2clipboard(text = f.read(), announce_result = False) 383 f.close() 384 if announce_result: 385 gm_show_info ( 386 title = _('file2clipboard'), 387 info = _('The file [%s] has been copied into the clipboard.') % filename 388 ) 389 return result
390 391 # ========================================================================
392 -class cFileDropTarget(wx.FileDropTarget):
393 """Generic file drop target class. 394 395 Protocol: 396 Widgets being declared file drop targets 397 must provide the method: 398 399 def _drop_target_consume_filenames(self, filenames) 400 401 or declare a callback during __init__() of this class. 402 """ 403 #-----------------------------------------------
404 - def __init__(self, target=None, on_drop_callback=None):
405 if target is not None: 406 try: 407 on_drop_callback = getattr(target, '_drop_target_consume_filenames') 408 except AttributeError: 409 _log.exception('[%s._drop_target_consume_filenames()] does not exist, cannot set as drop target callback', target) 410 raise 411 if not callable(on_drop_callback): 412 _log.error('[%s] not callable, cannot set as drop target callback', on_drop_callback) 413 raise AttributeError('[%s] not callable, cannot set as drop target callback', on_drop_callback) 414 self._on_drop_callback = on_drop_callback 415 wx.FileDropTarget.__init__(self) 416 _log.debug('setting up [%s] as file drop target', self._on_drop_callback)
417 418 #-----------------------------------------------
419 - def OnDropFiles(self, x, y, filenames):
420 self._on_drop_callback(filenames)
421 422 # ========================================================================
423 -def file2scaled_image(filename=None, height=100):
424 img_data = None 425 bitmap = None 426 rescaled_height = height 427 try: 428 img_data = wx.Image(filename, wx.BITMAP_TYPE_ANY) 429 current_width = img_data.GetWidth() 430 current_height = img_data.GetHeight() 431 # if current_width == 0: 432 # current_width = 1 433 # if current_height == 0: 434 # current_height = 1 435 rescaled_width = (float(current_width) / current_height) * rescaled_height 436 img_data.Rescale(rescaled_width, rescaled_height, quality = wx.IMAGE_QUALITY_HIGH) # w, h 437 bitmap = wx.Bitmap(img_data) 438 del img_data 439 except Exception: 440 _log.exception('cannot load image from [%s]', filename) 441 del img_data 442 del bitmap 443 return None 444 return bitmap
445 446 # ========================================================================
447 -def gm_show_error(aMessage=None, aTitle = None, error=None, title=None):
448 449 if error is None: 450 error = aMessage 451 if error is None: 452 error = _('programmer forgot to specify error message') 453 error += _("\n\nPlease consult the error log for all the gory details !") 454 455 if title is None: 456 title = aTitle 457 if title is None: 458 title = _('generic error message') 459 if not title.startswith('GMd: '): 460 title = 'GMd: %s' % title 461 462 dlg = wx.MessageDialog ( 463 parent = None, 464 message = error, 465 caption = title, 466 style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP 467 ) 468 dlg.ShowModal() 469 dlg.DestroyLater() 470 return True
471 472 #-------------------------------------------------------------------------
473 -def gm_show_info(aMessage=None, aTitle=None, info=None, title=None):
474 475 if info is None: 476 info = aMessage 477 if info is None: 478 info = _('programmer forgot to specify info message') 479 480 if title is None: 481 title = aTitle 482 if title is None: 483 title = _('generic info message') 484 if not title.startswith('GMd: '): 485 title = 'GMd: %s' % title 486 487 dlg = wx.MessageDialog ( 488 parent = None, 489 message = info, 490 caption = title, 491 style = wx.OK | wx.ICON_INFORMATION | wx.STAY_ON_TOP 492 ) 493 dlg.ShowModal() 494 dlg.DestroyLater() 495 return True
496 497 #-------------------------------------------------------------------------
498 -def gm_show_warning(aMessage=None, aTitle=None):
499 if aMessage is None: 500 aMessage = _('programmer forgot to specify warning') 501 502 if aTitle is None: 503 aTitle = _('generic warning message') 504 if not aTitle.startswith('GMd: '): 505 aTitle = 'GMd: %s' % aTitle 506 507 dlg = wx.MessageDialog ( 508 parent = None, 509 message = aMessage, 510 caption = aTitle, 511 style = wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP 512 ) 513 dlg.ShowModal() 514 dlg.DestroyLater() 515 return True
516 517 #-------------------------------------------------------------------------
518 -def gm_show_question(aMessage='programmer forgot to specify question', aTitle='generic user question dialog', cancel_button=False, question=None, title=None):
519 if cancel_button: 520 style = wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION | wx.STAY_ON_TOP 521 else: 522 style = wx.YES_NO | wx.ICON_QUESTION | wx.STAY_ON_TOP 523 524 if question is None: 525 question = aMessage 526 if title is None: 527 title = aTitle 528 if not title.startswith('GMd: '): 529 title = 'GMd: %s' % title 530 531 dlg = wx.MessageDialog(None, question, title, style) 532 btn_pressed = dlg.ShowModal() 533 dlg.DestroyLater() 534 535 if btn_pressed == wx.ID_YES: 536 return True 537 elif btn_pressed == wx.ID_NO: 538 return False 539 else: 540 return None
541 542 #====================================================================== 543 if __name__ == '__main__': 544 545 if len(sys.argv) < 2: 546 sys.exit() 547 548 if sys.argv[1] != 'test': 549 sys.exit() 550 551 from Gnumed.pycommon import gmI18N 552 gmI18N.activate_locale() 553 gmI18N.install_domain(domain='gnumed') 554 555 #------------------------------------------------------------------
556 - def test_scale_img():
557 app = wx.App() 558 img = file2scaled_image(filename = sys.argv[2]) 559 print(img) 560 print(img.Height) 561 print(img.Width)
562 #------------------------------------------------------------------
563 - def test_sql_logic_prw():
564 app = wx.PyWidgetTester(size = (200, 50)) 565 prw = cThreeValuedLogicPhraseWheel(app.frame, -1) 566 app.frame.Show(True) 567 app.MainLoop() 568 569 return True
570 #------------------------------------------------------------------
571 - def test_clipboard():
572 app = wx.PyWidgetTester(size = (200, 50)) 573 result = clipboard2file() 574 if result is False: 575 print("problem opening clipboard") 576 return 577 if result is None: 578 print("no data in clipboard") 579 return 580 print("file:", result)
581 #------------------------------------------------------------------ 582 #test_scale_img() 583 #test_sql_logic_prw() 584 test_clipboard() 585 586 #====================================================================== 587