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