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