Package Gnumed :: Package wxpython :: Module gmProviderInboxWidgets
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmProviderInboxWidgets

   1  """GNUmed provider inbox handling widgets. 
   2  """ 
   3  #================================================================ 
   4  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>" 
   5   
   6  import sys 
   7  import logging 
   8   
   9   
  10  import wx 
  11   
  12   
  13  if __name__ == '__main__': 
  14          sys.path.insert(0, '../../') 
  15  from Gnumed.pycommon import gmI18N 
  16  from Gnumed.pycommon import gmExceptions 
  17  from Gnumed.pycommon import gmPG2 
  18  from Gnumed.pycommon import gmCfg 
  19  from Gnumed.pycommon import gmTools 
  20  from Gnumed.pycommon import gmDispatcher 
  21  from Gnumed.pycommon import gmMatchProvider 
  22  from Gnumed.pycommon import gmDateTime 
  23  from Gnumed.pycommon import gmNetworkTools 
  24   
  25  from Gnumed.business import gmPerson 
  26  from Gnumed.business import gmStaff 
  27  from Gnumed.business import gmSurgery 
  28  from Gnumed.business import gmProviderInbox 
  29   
  30  from Gnumed.wxpython import gmGuiHelpers 
  31  from Gnumed.wxpython import gmListWidgets 
  32  from Gnumed.wxpython import gmPlugin 
  33  from Gnumed.wxpython import gmRegetMixin 
  34  from Gnumed.wxpython import gmPhraseWheel 
  35  from Gnumed.wxpython import gmEditArea 
  36  from Gnumed.wxpython import gmAuthWidgets 
  37  from Gnumed.wxpython import gmPatSearchWidgets 
  38  from Gnumed.wxpython import gmVaccWidgets 
  39  from Gnumed.wxpython import gmCfgWidgets 
  40  from Gnumed.wxpython import gmDataPackWidgets 
  41   
  42   
  43  _log = logging.getLogger('gm.ui') 
  44   
  45  _indicator = { 
  46          -1: '', 
  47          0: '', 
  48          1: '*!!*' 
  49  } 
  50  #============================================================ 
51 -def configure_fallback_primary_provider(parent=None):
52 53 if parent is None: 54 parent = wx.GetApp().GetTopWindow() 55 56 staff = gmStaff.get_staff_list() 57 choices = [ [ 58 s[u'short_alias'], 59 u'%s%s %s' % ( 60 gmTools.coalesce(s['title'], u'', u'%s '), 61 s['firstnames'], 62 s['lastnames'] 63 ), 64 s['l10n_role'], 65 gmTools.coalesce(s['comment'], u'') 66 ] 67 for s in staff 68 if s['is_active'] is True 69 ] 70 data = [ s['pk_staff'] for s in staff if s['is_active'] is True ] 71 72 gmCfgWidgets.configure_string_from_list_option ( 73 parent = parent, 74 message = _( 75 '\n' 76 'Please select the provider to fall back to in case\n' 77 'no primary provider is configured for a patient.\n' 78 ), 79 option = 'patient.fallback_primary_provider', 80 bias = 'user', 81 default_value = None, 82 choices = choices, 83 columns = [_('Alias'), _('Provider'), _('Role'), _('Comment')], 84 data = data, 85 caption = _('Configuring fallback primary provider') 86 )
87 #============================================================
88 -class cProviderPhraseWheel(gmPhraseWheel.cPhraseWheel):
89
90 - def __init__(self, *args, **kwargs):
91 92 gmPhraseWheel.cPhraseWheel.__init__ ( 93 self, 94 *args, 95 **kwargs 96 ) 97 self.matcher = gmPerson.cMatchProvider_Provider() 98 self.SetToolTipString(_('Select a healthcare provider.')) 99 self.selection_only = True
100 #============================================================ 101 # practice related widgets 102 #============================================================
103 -def show_audit_trail(parent=None):
104 105 if parent is None: 106 parent = wx.GetApp().GetTopWindow() 107 108 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('showing audit trail')) 109 if conn is None: 110 return False 111 112 #----------------------------------- 113 def refresh(lctrl): 114 cmd = u'SELECT * FROM audit.v_audit_trail ORDER BY audit_when_ts' 115 rows, idx = gmPG2.run_ro_queries(link_obj = conn, queries = [{'cmd': cmd}], get_col_idx = False) 116 lctrl.set_string_items ( 117 [ [ 118 r['event_when'], 119 r['event_by'], 120 u'%s %s %s' % ( 121 gmTools.coalesce(r['row_version_before'], gmTools.u_diameter), 122 gmTools.u_right_arrow, 123 gmTools.coalesce(r['row_version_after'], gmTools.u_diameter) 124 ), 125 r['event_table'], 126 r['event'], 127 r['pk_audit'] 128 ] for r in rows ] 129 )
130 #----------------------------------- 131 gmListWidgets.get_choices_from_list ( 132 parent = parent, 133 msg = u'', 134 caption = _('GNUmed database audit log ...'), 135 columns = [ _('When'), _('Who'), _('Revisions'), _('Table'), _('Event'), '#' ], 136 single_selection = True, 137 refresh_callback = refresh 138 ) 139 140 #============================================================ 141 # FIXME: this should be moved elsewhere ! 142 #------------------------------------------------------------
143 -def configure_workplace_plugins(parent=None):
144 145 if parent is None: 146 parent = wx.GetApp().GetTopWindow() 147 148 #----------------------------------- 149 def delete(workplace): 150 151 curr_workplace = gmSurgery.gmCurrentPractice().active_workplace 152 if workplace == curr_workplace: 153 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete the active workplace.'), beep = True) 154 return False 155 156 dlg = gmGuiHelpers.c2ButtonQuestionDlg ( 157 parent, 158 -1, 159 caption = _('Deleting workplace ...'), 160 question = _('Are you sure you want to delete this workplace ?\n\n "%s"\n') % workplace, 161 show_checkbox = True, 162 checkbox_msg = _('delete configuration, too'), 163 checkbox_tooltip = _( 164 'Check this if you want to delete all configuration items\n' 165 'for this workplace along with the workplace itself.' 166 ), 167 button_defs = [ 168 {'label': _('Delete'), 'tooltip': _('Yes, delete this workplace.'), 'default': True}, 169 {'label': _('Do NOT delete'), 'tooltip': _('No, do NOT delete this workplace'), 'default': False} 170 ] 171 ) 172 173 decision = dlg.ShowModal() 174 if decision != wx.ID_YES: 175 dlg.Destroy() 176 return False 177 178 include_cfg = dlg.checkbox_is_checked() 179 dlg.Destroy() 180 181 dbo_conn = gmAuthWidgets.get_dbowner_connection(procedure = _('delete workplace')) 182 if not dbo_conn: 183 return False 184 185 gmSurgery.delete_workplace(workplace = workplace, conn = dbo_conn, delete_config = include_cfg) 186 return True
187 #----------------------------------- 188 def edit(workplace=None): 189 190 dbcfg = gmCfg.cCfgSQL() 191 192 if workplace is None: 193 dlg = wx.TextEntryDialog ( 194 parent = parent, 195 message = _('Enter a descriptive name for the new workplace:'), 196 caption = _('Configuring GNUmed workplaces ...'), 197 defaultValue = u'', 198 style = wx.OK | wx.CENTRE 199 ) 200 dlg.ShowModal() 201 workplace = dlg.GetValue().strip() 202 if workplace == u'': 203 gmGuiHelpers.gm_show_error(_('Cannot save a new workplace without a name.'), _('Configuring GNUmed workplaces ...')) 204 return False 205 curr_plugins = [] 206 else: 207 curr_plugins = gmTools.coalesce(dbcfg.get2 ( 208 option = u'horstspace.notebook.plugin_load_order', 209 workplace = workplace, 210 bias = 'workplace' 211 ), [] 212 ) 213 214 msg = _( 215 'Pick the plugin(s) to be loaded the next time the client is restarted under the workplace:\n' 216 '\n' 217 ' [%s]\n' 218 ) % workplace 219 220 picker = gmListWidgets.cItemPickerDlg ( 221 parent, 222 -1, 223 title = _('Configuring workplace plugins ...'), 224 msg = msg 225 ) 226 picker.set_columns(['Available plugins'], ['Active plugins']) 227 available_plugins = gmPlugin.get_installed_plugins(plugin_dir = 'gui') 228 picker.set_choices(available_plugins) 229 picker.set_picks(picks = curr_plugins[:]) 230 btn_pressed = picker.ShowModal() 231 if btn_pressed != wx.ID_OK: 232 picker.Destroy() 233 return False 234 235 new_plugins = picker.get_picks() 236 picker.Destroy() 237 if new_plugins == curr_plugins: 238 return True 239 240 if new_plugins is None: 241 return True 242 243 dbcfg.set ( 244 option = u'horstspace.notebook.plugin_load_order', 245 value = new_plugins, 246 workplace = workplace 247 ) 248 249 return True 250 #----------------------------------- 251 def edit_old(workplace=None): 252 253 available_plugins = gmPlugin.get_installed_plugins(plugin_dir='gui') 254 255 dbcfg = gmCfg.cCfgSQL() 256 257 if workplace is None: 258 dlg = wx.TextEntryDialog ( 259 parent = parent, 260 message = _('Enter a descriptive name for the new workplace:'), 261 caption = _('Configuring GNUmed workplaces ...'), 262 defaultValue = u'', 263 style = wx.OK | wx.CENTRE 264 ) 265 dlg.ShowModal() 266 workplace = dlg.GetValue().strip() 267 if workplace == u'': 268 gmGuiHelpers.gm_show_error(_('Cannot save a new workplace without a name.'), _('Configuring GNUmed workplaces ...')) 269 return False 270 curr_plugins = [] 271 choices = available_plugins 272 else: 273 curr_plugins = gmTools.coalesce(dbcfg.get2 ( 274 option = u'horstspace.notebook.plugin_load_order', 275 workplace = workplace, 276 bias = 'workplace' 277 ), [] 278 ) 279 choices = curr_plugins[:] 280 for p in available_plugins: 281 if p not in choices: 282 choices.append(p) 283 284 sels = range(len(curr_plugins)) 285 new_plugins = gmListWidgets.get_choices_from_list ( 286 parent = parent, 287 msg = _( 288 '\n' 289 'Select the plugin(s) to be loaded the next time\n' 290 'the client is restarted under the workplace:\n' 291 '\n' 292 ' [%s]' 293 '\n' 294 ) % workplace, 295 caption = _('Configuring GNUmed workplaces ...'), 296 choices = choices, 297 selections = sels, 298 columns = [_('Plugins')], 299 single_selection = False 300 ) 301 302 if new_plugins == curr_plugins: 303 return True 304 305 if new_plugins is None: 306 return True 307 308 dbcfg.set ( 309 option = u'horstspace.notebook.plugin_load_order', 310 value = new_plugins, 311 workplace = workplace 312 ) 313 314 return True 315 #----------------------------------- 316 def clone(workplace=None): 317 if workplace is None: 318 return False 319 320 new_name = wx.GetTextFromUser ( 321 message = _('Enter a name for the new workplace !'), 322 caption = _('Cloning workplace'), 323 default_value = u'%s-2' % workplace, 324 parent = parent 325 ).strip() 326 327 if new_name == u'': 328 return False 329 330 dbcfg = gmCfg.cCfgSQL() 331 opt = u'horstspace.notebook.plugin_load_order' 332 333 plugins = dbcfg.get2 ( 334 option = opt, 335 workplace = workplace, 336 bias = 'workplace' 337 ) 338 339 dbcfg.set ( 340 option = opt, 341 value = plugins, 342 workplace = new_name 343 ) 344 345 # FIXME: clone cfg, too 346 347 return True 348 #----------------------------------- 349 def refresh(lctrl): 350 workplaces = gmSurgery.gmCurrentPractice().workplaces 351 curr_workplace = gmSurgery.gmCurrentPractice().active_workplace 352 try: 353 sels = [workplaces.index(curr_workplace)] 354 except ValueError: 355 sels = [] 356 357 lctrl.set_string_items(workplaces) 358 lctrl.set_selections(selections = sels) 359 #----------------------------------- 360 gmListWidgets.get_choices_from_list ( 361 parent = parent, 362 msg = _( 363 '\nSelect the workplace to configure below.\n' 364 '\n' 365 'The currently active workplace is preselected.\n' 366 ), 367 caption = _('Configuring GNUmed workplaces ...'), 368 columns = [_('Workplace')], 369 single_selection = True, 370 refresh_callback = refresh, 371 edit_callback = edit, 372 new_callback = edit, 373 delete_callback = delete, 374 left_extra_button = (_('Clone'), _('Clone the selected workplace'), clone) 375 ) 376 #====================================================================
377 -class cMessageTypePhraseWheel(gmPhraseWheel.cPhraseWheel):
378
379 - def __init__(self, *args, **kwargs):
380 381 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 382 383 query = u""" 384 SELECT DISTINCT ON (label) 385 pk_type, 386 (l10n_type || ' (' || l10n_category || ')') 387 AS label 388 FROM 389 dem.v_inbox_item_type 390 WHERE 391 l10n_type %(fragment_condition)s 392 OR 393 type %(fragment_condition)s 394 OR 395 l10n_category %(fragment_condition)s 396 OR 397 category %(fragment_condition)s 398 ORDER BY label 399 LIMIT 50""" 400 401 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 402 mp.setThresholds(1, 2, 4) 403 self.matcher = mp 404 self.SetToolTipString(_('Select a message type.'))
405 #----------------------------------------------------------------
406 - def _create_data(self):
407 if self.GetData() is not None: 408 return 409 410 val = self.GetValue().strip() 411 if val == u'': 412 return 413 414 self.SetText ( 415 value = val, 416 data = gmProviderInbox.create_inbox_item_type(message_type = val) 417 )
418 #====================================================================
419 -def _display_clinical_reminders():
420 wx.CallAfter(__display_clinical_reminders)
421 422 gmDispatcher.connect(signal = u'post_patient_selection', receiver = _display_clinical_reminders) 423
424 -def __display_clinical_reminders():
425 pat = gmPerson.gmCurrentPatient() 426 if not pat.connected: 427 return 428 for msg in pat.due_messages: 429 if msg['expiry_date'] is None: 430 exp = u'' 431 else: 432 exp = _(' - expires %s') % gmDateTime.pydt_strftime ( 433 msg['expiry_date'], 434 '%Y %b %d', 435 accuracy = gmDateTime.acc_days 436 ) 437 txt = _( 438 'Due for %s (since %s%s):\n' 439 '%s' 440 '%s' 441 '\n' 442 'Patient: %s\n' 443 'Reminder by: %s' 444 ) % ( 445 gmDateTime.format_interval_medically(msg['interval_due']), 446 gmDateTime.pydt_strftime(msg['due_date'], '%Y %b %d', accuracy = gmDateTime.acc_days), 447 exp, 448 gmTools.coalesce(msg['comment'], u'', u'\n%s\n'), 449 gmTools.coalesce(msg['data'], u'', u'\n%s\n'), 450 pat['description_gender'], 451 msg['modified_by'] 452 ) 453 gmGuiHelpers.gm_show_warning ( 454 aTitle = _('Clinical reminder'), 455 aMessage = txt 456 ) 457 for hint in pat.dynamic_hints: 458 txt = u'%s\n\n%s\n\n %s' % ( 459 hint['title'], 460 gmTools.wrap(hint['hint'], width = 50, initial_indent = u' ', subsequent_indent = u' '), 461 hint['source'] 462 ) 463 dlg = gmGuiHelpers.c2ButtonQuestionDlg ( 464 None, 465 -1, 466 caption = _('Clinical hint'), 467 question = txt, 468 button_defs = [ 469 {'label': _('OK'), 'tooltip': _('OK'), 'default': True}, 470 {'label': _('More info'), 'tooltip': _('Go to [%s]') % hint['url']} 471 ] 472 ) 473 button = dlg.ShowModal() 474 dlg.Destroy() 475 if button == wx.ID_NO: 476 gmNetworkTools.open_url_in_browser(hint['url'], autoraise = False) 477 478 return
479 #==================================================================== 480 from Gnumed.wxGladeWidgets import wxgInboxMessageEAPnl 481
482 -class cInboxMessageEAPnl(wxgInboxMessageEAPnl.wxgInboxMessageEAPnl, gmEditArea.cGenericEditAreaMixin):
483
484 - def __init__(self, *args, **kwargs):
485 486 try: 487 data = kwargs['message'] 488 del kwargs['message'] 489 except KeyError: 490 data = None 491 492 wxgInboxMessageEAPnl.wxgInboxMessageEAPnl.__init__(self, *args, **kwargs) 493 gmEditArea.cGenericEditAreaMixin.__init__(self) 494 495 # Code using this mixin should set mode and data 496 # after instantiating the class: 497 self.mode = 'new' 498 self.data = data 499 if data is not None: 500 self.mode = 'edit' 501 502 self.__init_ui()
503 #----------------------------------------------------------------
504 - def __init_ui(self):
505 if not gmPerson.gmCurrentPatient().connected: 506 self._CHBOX_active_patient.SetValue(False) 507 self._CHBOX_active_patient.Enable(False) 508 self._PRW_patient.Enable(True)
509 #---------------------------------------------------------------- 510 # generic Edit Area mixin API 511 #----------------------------------------------------------------
512 - def _valid_for_save(self):
513 validity = True 514 515 if self._TCTRL_subject.GetValue().strip() == u'': 516 validity = False 517 self.display_ctrl_as_valid(ctrl = self._TCTRL_subject, valid = False) 518 else: 519 self.display_ctrl_as_valid(ctrl = self._TCTRL_subject, valid = True) 520 521 if self._PRW_type.GetValue().strip() == u'': 522 validity = False 523 self._PRW_type.display_as_valid(False) 524 else: 525 self._PRW_type.display_as_valid(True) 526 527 missing_receiver = ( 528 (self._CHBOX_send_to_me.IsChecked() is False) 529 and 530 (self._PRW_receiver.GetData() is None) 531 ) 532 533 missing_patient = ( 534 (self._CHBOX_active_patient.IsChecked() is False) 535 and 536 (self._PRW_patient.person is None) 537 ) 538 539 if missing_receiver and missing_patient: 540 validity = False 541 self.display_ctrl_as_valid(ctrl = self._CHBOX_send_to_me, valid = False) 542 self._PRW_receiver.display_as_valid(False) 543 self.display_ctrl_as_valid(ctrl = self._CHBOX_active_patient, valid = False) 544 self.display_ctrl_as_valid(ctrl = self._PRW_patient, valid = False) 545 else: 546 self.display_ctrl_as_valid(ctrl = self._CHBOX_send_to_me, valid = True) 547 self._PRW_receiver.display_as_valid(True) 548 self.display_ctrl_as_valid(ctrl = self._CHBOX_active_patient, valid = True) 549 self.display_ctrl_as_valid(ctrl = self._PRW_patient, valid = True) 550 551 if self._PRW_due.is_valid_timestamp(): 552 if self._PRW_expiry.is_valid_timestamp(): 553 if not self._PRW_expiry.date > self._PRW_due.date: 554 validity = False 555 self._PRW_expiry.display_as_valid(False) 556 gmDispatcher.send(signal = 'statustext', msg = _('Message cannot expire before being due.')) 557 else: 558 self._PRW_expiry.display_as_valid(True) 559 else: 560 self._PRW_expiry.display_as_valid(True) 561 else: 562 self._PRW_expiry.display_as_valid(True) 563 564 return validity
565 #----------------------------------------------------------------
566 - def _save_as_new(self):
567 568 pat_id = None 569 if self._CHBOX_active_patient.GetValue() is True: 570 pat_id = gmPerson.gmCurrentPatient().ID 571 else: 572 if self._PRW_patient.person is not None: 573 pat_id = self._PRW_patient.person.ID 574 575 receiver = None 576 if self._CHBOX_send_to_me.IsChecked(): 577 receiver = gmStaff.gmCurrentProvider()['pk_staff'] 578 else: 579 if self._PRW_receiver.GetData() is not None: 580 receiver = self._PRW_receiver.GetData() 581 582 msg = gmProviderInbox.create_inbox_message ( 583 patient = pat_id, 584 staff = receiver, 585 message_type = self._PRW_type.GetData(can_create = True), 586 subject = self._TCTRL_subject.GetValue().strip() 587 ) 588 589 msg['data'] = self._TCTRL_message.GetValue().strip() 590 591 if self._PRW_due.is_valid_timestamp(): 592 msg['due_date'] = self._PRW_due.date 593 594 if self._PRW_expiry.is_valid_timestamp(): 595 msg['expiry_date'] = self._PRW_expiry.date 596 597 if self._RBTN_normal.GetValue() is True: 598 msg['importance'] = 0 599 elif self._RBTN_high.GetValue() is True: 600 msg['importance'] = 1 601 else: 602 msg['importance'] = -1 603 604 msg.save() 605 self.data = msg 606 return True
607 #----------------------------------------------------------------
608 - def _save_as_update(self):
609 610 self.data['comment'] = self._TCTRL_subject.GetValue().strip() 611 self.data['pk_type'] = self._PRW_type.GetData(can_create = True) 612 613 if self._CHBOX_send_to_me.IsChecked(): 614 self.data['pk_staff'] = gmStaff.gmCurrentProvider()['pk_staff'] 615 else: 616 self.data['pk_staff'] = self._PRW_receiver.GetData() 617 618 self.data['data'] = self._TCTRL_message.GetValue().strip() 619 620 if self._CHBOX_active_patient.GetValue() is True: 621 self.data['pk_patient'] = gmPerson.gmCurrentPatient().ID 622 else: 623 if self._PRW_patient.person is None: 624 self.data['pk_patient'] = None 625 else: 626 self.data['pk_patient'] = self._PRW_patient.person.ID 627 628 if self._PRW_due.is_valid_timestamp(): 629 self.data['due_date'] = self._PRW_due.date 630 631 if self._PRW_expiry.is_valid_timestamp(): 632 self.data['expiry_date'] = self._PRW_expiry.date 633 634 if self._RBTN_normal.GetValue() is True: 635 self.data['importance'] = 0 636 elif self._RBTN_high.GetValue() is True: 637 self.data['importance'] = 1 638 else: 639 self.data['importance'] = -1 640 641 self.data.save() 642 return True
643 #----------------------------------------------------------------
644 - def _refresh_as_new(self):
645 self._TCTRL_subject.SetValue(u'') 646 self._PRW_type.SetText(value = u'', data = None) 647 self._CHBOX_send_to_me.SetValue(True) 648 self._PRW_receiver.Enable(False) 649 self._PRW_receiver.SetData(data = gmStaff.gmCurrentProvider()['pk_staff']) 650 self._TCTRL_message.SetValue(u'') 651 self._PRW_due.SetText(data = None) 652 self._PRW_expiry.SetText(data = None) 653 self._RBTN_normal.SetValue(True) 654 self._RBTN_high.SetValue(False) 655 self._RBTN_low.SetValue(False) 656 657 self._PRW_patient.person = None 658 659 if gmPerson.gmCurrentPatient().connected: 660 self._CHBOX_active_patient.Enable(True) 661 self._CHBOX_active_patient.SetValue(True) 662 self._PRW_patient.Enable(False) 663 else: 664 self._CHBOX_active_patient.Enable(False) 665 self._CHBOX_active_patient.SetValue(False) 666 self._PRW_patient.Enable(True) 667 668 self._TCTRL_subject.SetFocus()
669 #----------------------------------------------------------------
671 self._refresh_as_new()
672 #----------------------------------------------------------------
673 - def _refresh_from_existing(self):
674 675 self._TCTRL_subject.SetValue(gmTools.coalesce(self.data['comment'], u'')) 676 self._PRW_type.SetData(data = self.data['pk_type']) 677 678 curr_prov = gmStaff.gmCurrentProvider() 679 curr_pat = gmPerson.gmCurrentPatient() 680 681 if curr_prov['pk_staff'] == self.data['pk_staff']: 682 self._CHBOX_send_to_me.SetValue(True) 683 self._PRW_receiver.Enable(False) 684 self._PRW_receiver.SetData(data = gmStaff.gmCurrentProvider()['pk_staff']) 685 else: 686 self._CHBOX_send_to_me.SetValue(False) 687 self._PRW_receiver.Enable(True) 688 self._PRW_receiver.SetData(data = self.data['pk_staff']) 689 690 self._TCTRL_message.SetValue(gmTools.coalesce(self.data['data'], u'')) 691 692 if curr_pat.connected: 693 self._CHBOX_active_patient.Enable(True) 694 if curr_pat.ID == self.data['pk_patient']: 695 self._CHBOX_active_patient.SetValue(True) 696 self._PRW_patient.Enable(False) 697 self._PRW_patient.person = None 698 else: 699 self._CHBOX_active_patient.SetValue(False) 700 self._PRW_patient.Enable(True) 701 if self.data['pk_patient'] is None: 702 self._PRW_patient.person = None 703 else: 704 self._PRW_patient.person = gmPerson.cIdentity(aPK_obj = self.data['pk_patient']) 705 else: 706 self._CHBOX_active_patient.Enable(False) 707 self._CHBOX_active_patient.SetValue(False) 708 self._PRW_patient.Enable(True) 709 if self.data['pk_patient'] is None: 710 self._PRW_patient.person = None 711 else: 712 self._PRW_patient.person = gmPerson.cIdentity(aPK_obj = self.data['pk_patient']) 713 714 self._PRW_due.SetText(data = self.data['due_date']) 715 self._PRW_expiry.SetText(data = self.data['expiry_date']) 716 717 self._RBTN_normal.SetValue(False) 718 self._RBTN_high.SetValue(False) 719 self._RBTN_low.SetValue(False) 720 { -1: self._RBTN_low, 721 0: self._RBTN_normal, 722 1: self._RBTN_high 723 }[self.data['importance']].SetValue(True) 724 725 self._TCTRL_subject.SetFocus()
726 #---------------------------------------------------------------- 727 # event handlers 728 #----------------------------------------------------------------
729 - def _on_active_patient_checked(self, event):
730 if self._CHBOX_active_patient.IsChecked(): 731 self._PRW_patient.Enable(False) 732 self._PRW_patient.person = None 733 else: 734 self._PRW_patient.Enable(True)
735 #----------------------------------------------------------------
736 - def _on_send_to_me_checked(self, event):
737 if self._CHBOX_send_to_me.IsChecked(): 738 self._PRW_receiver.Enable(False) 739 self._PRW_receiver.SetData(data = gmStaff.gmCurrentProvider()['pk_staff']) 740 else: 741 self._PRW_receiver.Enable(True) 742 self._PRW_receiver.SetText(value = u'', data = None)
743 #============================================================
744 -def edit_inbox_message(parent=None, message=None, single_entry=True):
745 746 if parent is None: 747 parent = wx.GetApp().GetTopWindow() 748 749 ea = cInboxMessageEAPnl(parent = parent, id = -1) 750 ea.data = message 751 ea.mode = gmTools.coalesce(message, 'new', 'edit') 752 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry) 753 dlg.SetTitle(gmTools.coalesce(message, _('Adding new inbox message'), _('Editing inbox message'))) 754 if dlg.ShowModal() == wx.ID_OK: 755 dlg.Destroy() 756 return True 757 dlg.Destroy() 758 return False
759 #============================================================ 760 from Gnumed.wxGladeWidgets import wxgProviderInboxPnl 761
762 -class cProviderInboxPnl(wxgProviderInboxPnl.wxgProviderInboxPnl, gmRegetMixin.cRegetOnPaintMixin):
763 764 _item_handlers = {} 765 766 #--------------------------------------------------------
767 - def __init__(self, *args, **kwds):
768 769 wxgProviderInboxPnl.wxgProviderInboxPnl.__init__(self, *args, **kwds) 770 gmRegetMixin.cRegetOnPaintMixin.__init__(self) 771 772 self.provider = gmStaff.gmCurrentProvider() 773 self.filter_mode = 'all' 774 self.__init_ui() 775 776 cProviderInboxPnl._item_handlers['clinical.review docs'] = self._goto_doc_review 777 cProviderInboxPnl._item_handlers['clinical.review results'] = self._goto_measurements_review 778 cProviderInboxPnl._item_handlers['clinical.review lab'] = self._goto_measurements_review 779 cProviderInboxPnl._item_handlers['clinical.review vaccs'] = self._goto_vaccination_review 780 781 self.__register_interests()
782 #-------------------------------------------------------- 783 # reget-on-paint API 784 #--------------------------------------------------------
785 - def _populate_with_data(self):
786 self.__populate_inbox() 787 return True
788 #-------------------------------------------------------- 789 # internal helpers 790 #--------------------------------------------------------
791 - def __register_interests(self):
792 gmDispatcher.connect(signal = u'message_inbox_generic_mod_db', receiver = self._on_message_inbox_mod_db) 793 gmDispatcher.connect(signal = u'message_inbox_mod_db', receiver = self._on_message_inbox_mod_db) 794 # FIXME: listen for results insertion/deletion 795 gmDispatcher.connect(signal = u'reviewed_test_results_mod_db', receiver = self._on_message_inbox_mod_db) 796 gmDispatcher.connect(signal = u'identity_mod_db', receiver = self._on_message_inbox_mod_db) 797 gmDispatcher.connect(signal = u'doc_mod_db', receiver = self._on_message_inbox_mod_db) 798 gmDispatcher.connect(signal = u'doc_obj_review_mod_db', receiver = self._on_message_inbox_mod_db) 799 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
800 #--------------------------------------------------------
801 - def __init_ui(self):
802 self._LCTRL_provider_inbox.set_columns([u'', _('Sent'), _('Category'), _('Type'), _('Message')]) 803 804 msg = _('\n Inbox of %(title)s %(lname)s.\n') % { 805 'title': gmTools.coalesce ( 806 self.provider['title'], 807 gmPerson.map_gender2salutation(self.provider['gender']) 808 ), 809 'lname': self.provider['lastnames'] 810 } 811 812 self._LCTRL_provider_inbox.item_tooltip_callback = self._get_msg_tooltip 813 814 self._msg_welcome.SetLabel(msg) 815 816 if gmPerson.gmCurrentPatient().connected: 817 self._RBTN_active_patient.Enable()
818 #--------------------------------------------------------
819 - def __populate_inbox(self):
820 self.__msgs = self.provider.inbox.messages 821 822 if self.filter_mode == 'active': 823 if gmPerson.gmCurrentPatient().connected: 824 curr_pat_id = gmPerson.gmCurrentPatient().ID 825 self.__msgs = [ m for m in self.__msgs if m['pk_patient'] == curr_pat_id ] 826 else: 827 self.__msgs = [] 828 829 items = [ 830 [ 831 _indicator[m['importance']], 832 m['received_when'].strftime('%Y-%m-%d'), 833 m['l10n_category'], 834 m['l10n_type'], 835 m['comment'] 836 ] for m in self.__msgs 837 ] 838 self._LCTRL_provider_inbox.set_string_items(items = items) 839 self._LCTRL_provider_inbox.set_data(data = self.__msgs) 840 self._LCTRL_provider_inbox.set_column_widths() 841 self._TXT_inbox_item_comment.SetValue(u'')
842 #-------------------------------------------------------- 843 # event handlers 844 #--------------------------------------------------------
845 - def _on_post_patient_selection(self):
846 wx.CallAfter(self._schedule_data_reget) 847 wx.CallAfter(self._RBTN_active_patient.Enable)
848 #--------------------------------------------------------
849 - def _on_message_inbox_mod_db(self, *args, **kwargs):
850 wx.CallAfter(self._schedule_data_reget) 851 gmDispatcher.send(signal = u'request_user_attention', msg = _('Please check your GNUmed Inbox !'))
852 #--------------------------------------------------------
853 - def _lst_item_activated(self, evt):
854 msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True) 855 if msg is None: 856 return 857 858 handler_key = '%s.%s' % (msg['category'], msg['type']) 859 try: 860 handle_item = cProviderInboxPnl._item_handlers[handler_key] 861 except KeyError: 862 if msg['pk_patient'] is None: 863 gmGuiHelpers.gm_show_warning ( 864 _('No double-click action pre-programmed into\n' 865 'GNUmed for message category and type:\n' 866 '\n' 867 ' [%s]\n' 868 ) % handler_key, 869 _('handling provider inbox item') 870 ) 871 return False 872 handle_item = self._goto_patient 873 874 if not handle_item(pk_context = msg['pk_context'], pk_patient = msg['pk_patient']): 875 _log.error('item handler returned <False>') 876 _log.error('handler key: [%s]', handler_key) 877 _log.error('message: %s', str(msg)) 878 return False 879 880 return True
881 #--------------------------------------------------------
882 - def _lst_item_focused(self, evt):
883 pass
884 #--------------------------------------------------------
885 - def _lst_item_selected(self, evt):
886 msg = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True) 887 if msg is None: 888 return 889 890 if msg['data'] is None: 891 tmp = _('Message: %s') % msg['comment'] 892 else: 893 tmp = _('Message: %s\nData: %s') % (msg['comment'], msg['data']) 894 895 self._TXT_inbox_item_comment.SetValue(tmp)
896 #--------------------------------------------------------
897 - def _lst_item_right_clicked(self, evt):
898 tmp = self._LCTRL_provider_inbox.get_selected_item_data(only_one = True) 899 if tmp is None: 900 return 901 self.__focussed_msg = tmp 902 903 # build menu 904 menu = wx.Menu(title = _('Inbox Message Actions:')) 905 906 if self.__focussed_msg['pk_patient'] is not None: 907 ID = wx.NewId() 908 menu.AppendItem(wx.MenuItem(menu, ID, _('Activate patient'))) 909 wx.EVT_MENU(menu, ID, self._on_goto_patient) 910 911 if not self.__focussed_msg['is_virtual']: 912 # - delete message 913 ID = wx.NewId() 914 menu.AppendItem(wx.MenuItem(menu, ID, _('Delete'))) 915 wx.EVT_MENU(menu, ID, self._on_delete_focussed_msg) 916 # - edit message 917 ID = wx.NewId() 918 menu.AppendItem(wx.MenuItem(menu, ID, _('Edit'))) 919 wx.EVT_MENU(menu, ID, self._on_edit_focussed_msg) 920 921 # if self.__focussed_msg['pk_staff'] is not None: 922 # # - distribute to other providers 923 # ID = wx.NewId() 924 # menu.AppendItem(wx.MenuItem(menu, ID, _('Distribute'))) 925 # wx.EVT_MENU(menu, ID, self._on_distribute_focussed_msg) 926 927 # show menu 928 self.PopupMenu(menu, wx.DefaultPosition) 929 menu.Destroy()
930 #--------------------------------------------------------
932 self.filter_mode = 'all' 933 self._TXT_inbox_item_comment.SetValue(u'') 934 self.__populate_inbox()
935 #--------------------------------------------------------
937 self.filter_mode = 'active' 938 self._TXT_inbox_item_comment.SetValue(u'') 939 self.__populate_inbox()
940 #--------------------------------------------------------
941 - def _on_add_button_pressed(self, event):
942 edit_inbox_message(parent = self, message = None, single_entry = False)
943 #--------------------------------------------------------
944 - def _get_msg_tooltip(self, msg):
945 return msg.format()
946 # tt = u'%s: %s%s\n' % ( 947 # msg['received_when'].strftime('%A, %Y %B %d, %H:%M').decode(gmI18N.get_encoding()), 948 # gmTools.bool2subst(msg['is_virtual'], _('virtual message'), _('message')), 949 # gmTools.coalesce(msg['pk_inbox_message'], u'', u' #%s ') 950 # ) 951 # 952 # tt += u'%s: %s\n' % ( 953 # msg['l10n_category'], 954 # msg['l10n_type'] 955 # ) 956 # 957 # tt += u'%s %s %s\n' % ( 958 # msg['modified_by'], 959 # gmTools.u_right_arrow, 960 # gmTools.coalesce(msg['provider'], _('everyone')) 961 # ) 962 # 963 # tt += u'\n%s%s%s\n\n' % ( 964 # gmTools.u_left_double_angle_quote, 965 # msg['comment'], 966 # gmTools.u_right_double_angle_quote 967 # ) 968 # 969 # tt += gmTools.coalesce ( 970 # msg['pk_patient'], 971 # u'', 972 # u'%s\n\n' % _('Patient #%s') 973 # ) 974 # 975 # if msg['data'] is not None: 976 # tt += msg['data'][:150] 977 # if len(msg['data']) > 150: 978 # tt += gmTools.u_ellipsis 979 # 980 # return tt 981 #-------------------------------------------------------- 982 # item handlers 983 #--------------------------------------------------------
984 - def _on_goto_patient(self, evt):
985 return self._goto_patient(pk_patient = self.__focussed_msg['pk_patient'])
986 #--------------------------------------------------------
987 - def _on_delete_focussed_msg(self, evt):
988 if self.__focussed_msg['is_virtual']: 989 gmDispatcher.send(signal = 'statustext', msg = _('You must deal with the reason for this message to remove it from your inbox.'), beep = True) 990 return False 991 992 if not self.provider.inbox.delete_message(self.__focussed_msg['pk_inbox_message']): 993 gmDispatcher.send(signal='statustext', msg=_('Problem removing message from Inbox.')) 994 return False 995 return True
996 #--------------------------------------------------------
997 - def _on_edit_focussed_msg(self, evt):
998 if self.__focussed_msg['is_virtual']: 999 gmDispatcher.send(signal = 'statustext', msg = _('This message cannot be edited because it is virtual.')) 1000 return False 1001 edit_inbox_message(parent = self, message = self.__focussed_msg, single_entry = True) 1002 return True
1003 #--------------------------------------------------------
1004 - def _on_distribute_focussed_msg(self, evt):
1005 if self.__focussed_msg['pk_staff'] is None: 1006 gmDispatcher.send(signal = 'statustext', msg = _('This message is already visible to all providers.')) 1007 return False 1008 print "now distributing" 1009 return True
1010 #--------------------------------------------------------
1011 - def _goto_patient(self, pk_context=None, pk_patient=None):
1012 1013 wx.BeginBusyCursor() 1014 1015 msg = _('There is a message about patient [%s].\n\n' 1016 'However, I cannot find that\n' 1017 'patient in the GNUmed database.' 1018 ) % pk_patient 1019 1020 try: 1021 pat = gmPerson.cIdentity(aPK_obj = pk_patient) 1022 except gmExceptions.ConstructorError: 1023 wx.EndBusyCursor() 1024 _log.exception('patient [%s] not found', pk_patient) 1025 gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item')) 1026 return False 1027 except: 1028 wx.EndBusyCursor() 1029 raise 1030 1031 success = gmPatSearchWidgets.set_active_patient(patient = pat) 1032 1033 wx.EndBusyCursor() 1034 1035 if not success: 1036 gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item')) 1037 return False 1038 1039 return True
1040 #--------------------------------------------------------
1041 - def _goto_doc_review(self, pk_context=None, pk_patient=None):
1042 1043 msg = _('Supposedly there are unreviewed documents\n' 1044 'for patient [%s]. However, I cannot find\n' 1045 'that patient in the GNUmed database.' 1046 ) % pk_patient 1047 1048 wx.BeginBusyCursor() 1049 1050 try: 1051 pat = gmPerson.cIdentity(aPK_obj = pk_patient) 1052 except gmExceptions.ConstructorError: 1053 wx.EndBusyCursor() 1054 _log.exception('patient [%s] not found', pk_patient) 1055 gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item')) 1056 return False 1057 1058 success = gmPatSearchWidgets.set_active_patient(patient = pat) 1059 1060 wx.EndBusyCursor() 1061 1062 if not success: 1063 gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item')) 1064 return False 1065 1066 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmShowMedDocs', sort_mode = 'review') 1067 return True
1068 #--------------------------------------------------------
1069 - def _goto_measurements_review(self, pk_context=None, pk_patient=None):
1070 1071 msg = _('Supposedly there are unreviewed results\n' 1072 'for patient [%s]. However, I cannot find\n' 1073 'that patient in the GNUmed database.' 1074 ) % pk_patient 1075 1076 wx.BeginBusyCursor() 1077 1078 try: 1079 pat = gmPerson.cIdentity(aPK_obj = pk_patient) 1080 except gmExceptions.ConstructorError: 1081 wx.EndBusyCursor() 1082 _log.exception('patient [%s] not found', pk_patient) 1083 gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item')) 1084 return False 1085 1086 success = gmPatSearchWidgets.set_active_patient(patient = pat) 1087 1088 wx.EndBusyCursor() 1089 1090 if not success: 1091 gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item')) 1092 return False 1093 1094 wx.CallAfter(gmDispatcher.send, signal = 'display_widget', name = 'gmMeasurementsGridPlugin') 1095 return True
1096 #--------------------------------------------------------
1097 - def _goto_vaccination_review(self, pk_context=None, pk_patient=None):
1098 1099 msg = _('Supposedly there are conflicting vaccinations\n' 1100 'for patient [%s]. However, I cannot find\n' 1101 'that patient in the GNUmed database.' 1102 ) % pk_patient 1103 1104 wx.BeginBusyCursor() 1105 1106 try: 1107 pat = gmPerson.cIdentity(aPK_obj = pk_patient) 1108 except gmExceptions.ConstructorError: 1109 wx.EndBusyCursor() 1110 _log.exception('patient [%s] not found', pk_patient) 1111 gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item')) 1112 return False 1113 1114 success = gmPatSearchWidgets.set_active_patient(patient = pat) 1115 1116 wx.EndBusyCursor() 1117 1118 if not success: 1119 gmGuiHelpers.gm_show_error(msg, _('handling provider inbox item')) 1120 return False 1121 1122 wx.CallAfter(gmVaccWidgets.manage_vaccinations) 1123 1124 return True
1125 #============================================================
1126 -def browse_dynamic_hints(parent=None):
1127 1128 if parent is None: 1129 parent = wx.GetApp().GetTopWindow() 1130 #------------------------------------------------------------ 1131 def get_tooltip(item): 1132 if item is None: 1133 return None 1134 return item.format()
1135 #------------------------------------------------------------ 1136 def switch_activation(item): 1137 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('Switching clinical hint activation')) 1138 if conn is None: 1139 return False 1140 item['is_active'] = not item['is_active'] 1141 return item.save(conn = conn) 1142 #------------------------------------------------------------ 1143 def manage_data_packs(item): 1144 gmDataPackWidgets.manage_data_packs(parent = parent) 1145 return True 1146 #------------------------------------------------------------ 1147 def refresh(lctrl): 1148 hints = gmProviderInbox.get_dynamic_hints(order_by = u'is_active DESC, source, hint') 1149 items = [ [ 1150 gmTools.bool2subst(h['is_active'], gmTools.u_checkmark_thin, u''), 1151 h['title'], 1152 h['source'][:30], 1153 h['hint'][:60], 1154 gmTools.coalesce(h['url'], u'')[:60], 1155 h['lang'], 1156 h['pk'] 1157 ] for h in hints ] 1158 lctrl.set_string_items(items) 1159 lctrl.set_data(hints) 1160 #------------------------------------------------------------ 1161 gmListWidgets.get_choices_from_list ( 1162 parent = parent, 1163 msg = _('\nDynamic hints registered with GNUmed.\n'), 1164 caption = _('Showing dynamic hints.'), 1165 columns = [ _('Active'), _('Title'), _('Source'), _('Hint'), u'URL', _('Language'), u'#' ], 1166 single_selection = True, 1167 refresh_callback = refresh, 1168 left_extra_button = ( 1169 _('(De)-Activate'), 1170 _('Switch activation of the selected hint'), 1171 switch_activation 1172 ), 1173 right_extra_button = ( 1174 _('Data packs'), 1175 _('Browse and install clinical hints data packs'), 1176 manage_data_packs 1177 ), 1178 list_tooltip_callback = get_tooltip 1179 ) 1180 1181 #============================================================ 1182 if __name__ == '__main__': 1183 1184 if len(sys.argv) < 2: 1185 sys.exit() 1186 1187 if sys.argv[1] != 'test': 1188 sys.exit() 1189 1190 gmI18N.activate_locale() 1191 gmI18N.install_domain(domain = 'gnumed') 1192
1193 - def test_configure_wp_plugins():
1194 app = wx.PyWidgetTester(size = (400, 300)) 1195 configure_workplace_plugins()
1196
1197 - def test_message_inbox():
1198 app = wx.PyWidgetTester(size = (800, 600)) 1199 app.SetWidget(cProviderInboxPnl, -1) 1200 app.MainLoop()
1201
1202 - def test_msg_ea():
1203 app = wx.PyWidgetTester(size = (800, 600)) 1204 app.SetWidget(cInboxMessageEAPnl, -1) 1205 app.MainLoop()
1206 1207 1208 #test_configure_wp_plugins() 1209 #test_message_inbox() 1210 test_msg_ea() 1211 1212 #============================================================ 1213