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