1 """GNUmed auto/dynamic hints widgets.
2 """
3
4 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
5 __license__ = "GPL v2 or later"
6
7 import sys
8 import logging
9
10
11 import wx
12
13
14 if __name__ == '__main__':
15 sys.path.insert(0, '../../')
16 from Gnumed.pycommon import gmTools
17 from Gnumed.pycommon import gmDispatcher
18 from Gnumed.pycommon import gmDateTime
19 from Gnumed.pycommon import gmNetworkTools
20
21 from Gnumed.business import gmPerson
22 from Gnumed.business import gmAutoHints
23
24 from Gnumed.wxpython import gmListWidgets
25 from Gnumed.wxpython import gmAuthWidgets
26 from Gnumed.wxpython import gmDataPackWidgets
27 from Gnumed.wxpython import gmGuiHelpers
28 from Gnumed.wxpython import gmEditArea
29
30
31 _log = logging.getLogger('gm.auto_hints')
32
33
35
36 pat = gmPerson.gmCurrentPatient()
37 if not pat.connected:
38 return
39
40
41 for msg in pat.overdue_messages:
42 if msg['expiry_date'] is None:
43 exp = ''
44 else:
45 exp = _(' - expires %s') % gmDateTime.pydt_strftime (
46 msg['expiry_date'],
47 '%Y %b %d',
48 accuracy = gmDateTime.acc_days
49 )
50 txt = _(
51 'Due for %s (since %s%s):\n'
52 '%s'
53 '%s'
54 '\n'
55 'Patient: %s\n'
56 'Reminder by: %s'
57 ) % (
58 gmDateTime.format_interval_medically(msg['interval_due']),
59 gmDateTime.pydt_strftime(msg['due_date'], '%Y %b %d', accuracy = gmDateTime.acc_days),
60 exp,
61 gmTools.coalesce(msg['comment'], '', '\n%s\n'),
62 gmTools.coalesce(msg['data'], '', '\n%s\n'),
63 pat['description_gender'],
64 msg['modified_by']
65 )
66 gmGuiHelpers.gm_show_warning (
67 aTitle = _('Clinical reminder'),
68 aMessage = txt
69 )
70
71
72 hints2aggregate = []
73 emr = pat.emr
74 hint_dlg = cDynamicHintDlg(wx.GetApp().GetTopWindow(), -1)
75
76 for hint in emr.dynamic_hints:
77 if hint['popup_type'] == 0:
78 continue
79 if hint['popup_type'] == 2:
80 hints2aggregate.append(hint)
81 continue
82 hint_dlg.hint = hint
83 if hint_dlg.ShowModal() == wx.ID_APPLY:
84 hint.suppress (
85 rationale = hint_dlg.rationale.strip(),
86 pk_encounter = emr.current_encounter['pk_encounter']
87 )
88 hint_dlg.Destroy()
89
90 if len(hints2aggregate) > 0:
91 hints_dlg = cDynamicHintListDlg(wx.GetApp().GetTopWindow(), -1)
92 hints_dlg.pk_encounter = emr.current_encounter['pk_encounter']
93 hints_dlg.hints = hints2aggregate
94 hints_dlg.ShowModal()
95 hints_dlg.Destroy()
96
97 return
98
99 gmDispatcher.connect(signal = 'post_patient_selection', receiver = _display_clinical_reminders)
100
101
117
118
120
121 if parent is None:
122 parent = wx.GetApp().GetTopWindow()
123
124 def get_tooltip(item):
125 if item is None:
126 return None
127 return item.format()
128
129 def manage_data_packs(item):
130 gmDataPackWidgets.manage_data_packs(parent = parent)
131 return True
132
133 def edit_hint(hint=None):
134 return edit_dynamic_hint(parent = parent, hint = hint, single_entry = (hint is not None))
135
136 def del_hint(hint=None):
137 if hint is None:
138 return False
139 really_delete = gmGuiHelpers.gm_show_question (
140 title = _('Deleting automatic dynamic hint'),
141 question = _('Really delete this dynamic hint ?\n\n [%s]') % hint['title']
142 )
143 if not really_delete:
144 return False
145
146 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('deleting a dynamic hint'))
147 if conn is None:
148 return False
149 gmAutoHints.delete_dynamic_hint(link_obj = conn, pk_hint = hint['pk_auto_hint'])
150 conn.commit()
151 conn.close()
152 return True
153
154 def refresh(lctrl):
155 hints = gmAutoHints.get_dynamic_hints(order_by = 'is_active DESC, source, hint')
156 items = [ [
157 gmTools.bool2subst(h['is_active'], gmTools.u_checkmark_thin, ''),
158 h['title'],
159 h['source'][:30],
160 h['hint'][:60],
161 gmTools.coalesce(h['url'], '')[:60],
162 h['lang'],
163 h['pk_auto_hint']
164 ] for h in hints ]
165 lctrl.set_string_items(items)
166 lctrl.set_data(hints)
167
168
169 gmListWidgets.get_choices_from_list (
170 parent = parent,
171 msg = _('\nDynamic hints registered with GNUmed.\n'),
172 caption = _('Showing dynamic hints.'),
173 columns = [ _('Active'), _('Title'), _('Source'), _('Hint'), 'URL', _('Language'), '#' ],
174 single_selection = True,
175 refresh_callback = refresh,
176 edit_callback = edit_hint,
177 new_callback = edit_hint,
178 delete_callback = del_hint,
179
180
181
182
183
184
185 right_extra_button = (
186 _('Data packs'),
187 _('Browse and install automatic dynamic hints data packs'),
188 manage_data_packs
189 ),
190 list_tooltip_callback = get_tooltip
191 )
192
193
194 from Gnumed.wxGladeWidgets import wxgDynamicHintDlg
195
197
207
210
212 self.__hint = hint
213 self.__refresh()
214
215 hint = property(_get_hint, _set_hint)
216
218 return self._TCTRL_rationale.GetValue().strip()
219
220 rationale = property(_get_rationale, lambda x:x)
221
222
223
224
227
228
230 if self.__hint is None:
231 self._TCTRL_title.SetValue('')
232 self._TCTRL_hint.SetValue('')
233 self._URL_info.SetURL('')
234 self._URL_info.Disable()
235 self._TCTRL_source.SetValue('')
236 self._LBL_previous_rationale.Hide()
237 self._TCTRL_previous_rationale.Hide()
238 else:
239 self._TCTRL_title.SetValue(self.__hint['title'])
240 self._TCTRL_hint.SetValue('%s%s' % (
241 self.__hint['hint'],
242 gmTools.coalesce(self.__hint['recommendation'], '', '\n\n%s')
243 ))
244 if self.__hint['url'] is None:
245 self._URL_info.SetURL('')
246 self._URL_info.Disable()
247 else:
248 self._URL_info.SetURL(self.__hint['url'])
249 self._URL_info.Enable()
250 self._TCTRL_source.SetValue(_('By: %s') % self.__hint['source'])
251 if self.__hint['rationale4suppression'] is None:
252 self._LBL_previous_rationale.Hide()
253 self._TCTRL_previous_rationale.Hide()
254 self._BTN_transfer_previous_rationale.Hide()
255 self._BTN_transfer_previous_rationale.Disable()
256 else:
257 self._LBL_previous_rationale.Show()
258 self._TCTRL_previous_rationale.Show()
259 self._TCTRL_previous_rationale.SetValue(self.__hint['rationale4suppression'])
260 self._BTN_transfer_previous_rationale.Show()
261 self._BTN_transfer_previous_rationale.Enable()
262
263 self._TCTRL_rationale.SetValue('')
264 self._BTN_suppress.Disable()
265 self._TCTRL_rationale.SetFocus()
266
267
268
269
271 if self._TCTRL_rationale.GetValue().strip() == '':
272 self._BTN_suppress.Disable()
273 self._BTN_OK.SetDefault()
274 else:
275 self._BTN_suppress.Enable()
276 self._BTN_suppress.SetDefault()
277
278
290
291
295
296
303
304
305 from Gnumed.wxGladeWidgets import wxgDynamicHintListDlg
306
308
319
320
323
325 if len(hints) == 0:
326 hints = None
327 self.__hints = hints
328 self.__refresh()
329
330 hints = property(_get_hints, _set_hints)
331
332
335
336 pk_encounter = property(lambda x:x, _set_pk_encounter)
337
338
339
340
348
349
351 if self.__hints is None:
352 self._LCTRL_hints.set_string_items()
353 self._TCTRL_hint.SetValue('')
354 self._URL_info.SetURL('')
355 self._URL_info.Disable()
356 self._TCTRL_source.SetValue('')
357 self._TCTRL_rationale.SetValue('')
358 self._BTN_suppress.Disable()
359 self._LBL_previous_rationale.Hide()
360 self._TCTRL_previous_rationale.Hide()
361 self._LCTRL_hints.SetFocus()
362 return
363
364 priority_hints = []
365 non_priority_hints = []
366 for hint in self.__hints:
367 if hint['highlight_as_priority']:
368 priority_hints.append(hint)
369 else:
370 non_priority_hints.append(hint)
371
372 ordered_hints = []
373 ordered_hints.extend(priority_hints)
374 ordered_hints.extend(non_priority_hints)
375
376 self._LCTRL_hints.set_string_items([ [h['title'], h['source']] for h in ordered_hints ])
377 self._LCTRL_hints.set_data(ordered_hints)
378 for idx in range(len(priority_hints)):
379 self._LCTRL_hints.SetItemTextColour(idx, wx.Colour('YELLOW'))
380 self._LCTRL_hints.Select(0)
381
382
384 hint = self._LCTRL_hints.get_selected_item_data(only_one = True)
385
386 self._TCTRL_hint.SetValue('%s%s' % (
387 hint['hint'],
388 gmTools.coalesce(hint['recommendation'], '', '\n\n%s')
389 ))
390 if hint['url'] is None:
391 self._URL_info.SetURL('')
392 self._URL_info.Disable()
393 else:
394 self._URL_info.SetURL(hint['url'])
395 self._URL_info.Enable()
396 self._TCTRL_source.SetValue(_('By: %s') % hint['source'])
397 self._TCTRL_rationale.SetValue('')
398 self._BTN_suppress.Disable()
399
400 if hint['rationale4suppression'] is None:
401 self._LBL_previous_rationale.Hide()
402 self._TCTRL_previous_rationale.Hide()
403 self._TCTRL_previous_rationale.SetValue('')
404 else:
405 self._LBL_previous_rationale.Show()
406 self._TCTRL_previous_rationale.SetValue(hint['rationale4suppression'])
407 self._TCTRL_previous_rationale.Show()
408
409 self._TCTRL_rationale.SetFocus()
410
411
413 self._TCTRL_hint.SetValue('')
414 self._URL_info.SetURL('')
415 self._URL_info.Disable()
416 self._TCTRL_source.SetValue('')
417 self._TCTRL_rationale.SetValue('')
418 self._LBL_previous_rationale.Hide()
419 self._TCTRL_previous_rationale.Hide()
420 self._TCTRL_previous_rationale.SetValue('')
421 self._BTN_suppress.Disable()
422
423
424
425
427 if self._TCTRL_rationale.GetValue().strip() == '':
428 self._BTN_suppress.Disable()
429 else:
430 self._BTN_suppress.Enable()
431
432
456
457
461
462
463 from Gnumed.wxGladeWidgets import wxgAutoHintEAPnl
464
465 -class cAutoHintEAPnl(wxgAutoHintEAPnl.wxgAutoHintEAPnl, gmEditArea.cGenericEditAreaMixin):
466
484
485
486
487
488
489
490
491
530
531
533 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('creating a new dynamic hint'))
534 if conn is None:
535 return False
536
537 curs = conn.cursor()
538 data = gmAutoHints.create_dynamic_hint (
539 link_obj = curs,
540 query = self._TCTRL_query.GetValue().strip(),
541 title = self._TCTRL_title.GetValue().strip(),
542 hint = self._TCTRL_hint.GetValue().strip(),
543 source = self._TCTRL_source.GetValue().strip()
544 )
545 curs.close()
546 data['url'] = self._TCTRL_url.GetValue().strip()
547 data['recommendation_query'] = self._TCTRL_recommendation_query.GetValue().strip()
548 data['is_active'] = self._CHBOX_is_active.GetValue()
549 data['highlight_as_priority'] = self._CHBOX_highlight.GetValue()
550 if self._RBTN_popup_none.GetValue() is True:
551 data['popup_type'] = 0
552 elif self._RBTN_popup_single.GetValue() is True:
553 data['popup_type'] = 1
554 elif self._RBTN_popup_multiple.GetValue() is True:
555 data['popup_type'] = 2
556 else:
557 raise ValueError('no popup type radio button selected - should be impossible')
558 data.save(conn = conn)
559 conn.commit()
560 conn.close()
561
562 self.data = data
563
564 return True
565
566
568 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('updating an existing dynamic hint'))
569 if conn is None:
570 return False
571
572 self.data['title'] = self._TCTRL_title.GetValue().strip()
573 self.data['hint'] = self._TCTRL_hint.GetValue().strip()
574 self.data['query'] = self._TCTRL_query.GetValue().strip()
575 self.data['source'] = self._TCTRL_source.GetValue().strip()
576 self.data['url'] = self._TCTRL_url.GetValue().strip()
577 self.data['recommendation_query'] = self._TCTRL_recommendation_query.GetValue().strip()
578 self.data['is_active'] = self._CHBOX_is_active.GetValue()
579 self.data['highlight_as_priority'] = self._CHBOX_highlight.GetValue()
580 if self._RBTN_popup_none.GetValue() is True:
581 self.data['popup_type'] = 0
582 elif self._RBTN_popup_single.GetValue() is True:
583 self.data['popup_type'] = 1
584 elif self._RBTN_popup_multiple.GetValue() is True:
585 self.data['popup_type'] = 2
586 else:
587 raise ValueError('no popup type radio button selected - should be impossible')
588 self.data.save(conn = conn)
589 conn.commit()
590 conn.close()
591
592 return True
593
594
607
608
610 self._refresh_as_new()
611 self._TCTRL_source.SetValue(self.data['source'])
612
613 self._TCTRL_title.SetFocus()
614
615
617 self._TCTRL_title.SetValue(self.data['title'])
618 self._TCTRL_hint.SetValue(self.data['hint'])
619 self._TCTRL_query.SetValue(self.data['query'])
620 self._TCTRL_recommendation_query.SetValue(gmTools.coalesce(self.data['recommendation_query'], ''))
621 self._TCTRL_source.SetValue(self.data['source'])
622 self._TCTRL_url.SetValue(gmTools.coalesce(self.data['url'], ''))
623 self._CHBOX_is_active.SetValue(self.data['is_active'])
624 self._CHBOX_highlight.SetValue(self.data['highlight_as_priority'])
625 if self.data['popup_type'] == 0:
626 self._RBTN_popup_none.SetValue(True)
627 elif self.data['popup_type'] == 1:
628 self._RBTN_popup_single.SetValue(True)
629 elif self.data['popup_type'] == 2:
630 self._RBTN_popup_multiple.SetValue(True)
631 else:
632 raise ValueError('invalid popup type value [%s] - should be impossible' % self.data['popup_type'])
633
634 self._TCTRL_query.SetFocus()
635
636
637
638
647
648
650
651 if parent is None:
652 parent = wx.GetApp().GetTopWindow()
653
654 def get_tooltip(item):
655 if item is None:
656 return None
657 return item.format()
658
659 def manage_hints(item):
660 manage_dynamic_hints(parent = parent)
661 return True
662
663 def del_hint(hint=None):
664 if hint is None:
665 return False
666 really_delete = gmGuiHelpers.gm_show_question (
667 title = _('Deleting suppressed dynamic hint'),
668 question = _('Really delete the suppression of this dynamic hint ?\n\n [%s]') % hint['title']
669 )
670 if not really_delete:
671 return False
672 gmAutoHints.delete_suppressed_hint(pk_suppressed_hint = hint['pk_suppressed_hint'])
673 return True
674
675 def refresh(lctrl):
676 hints = gmAutoHints.get_suppressed_hints(pk_identity = pk_identity, order_by = 'title')
677 items = [ [
678 h['title'],
679 gmDateTime.pydt_strftime(h['suppressed_when'], '%Y %b %d'),
680 h['suppressed_by'],
681 h['rationale'],
682 gmTools.bool2subst(h['is_active'], gmTools.u_checkmark_thin, ''),
683 h['source'][:30],
684 gmTools.coalesce(h['url'], '')[:60],
685 h['pk_hint']
686 ] for h in hints ]
687 lctrl.set_string_items(items)
688 lctrl.set_data(hints)
689
690 gmListWidgets.get_choices_from_list (
691 parent = parent,
692 msg = _('\nDynamic hints suppressed in this patient.\n'),
693 caption = _('Showing suppressed dynamic hints.'),
694 columns = [ _('Title'), _('When'), _('By'), _('Rationale'), _('Active'), _('Source'), 'URL', 'Hint #' ],
695 single_selection = True,
696 ignore_OK_button = True,
697 refresh_callback = refresh,
698 delete_callback = del_hint,
699 right_extra_button = (
700 _('Manage hints'),
701 _('Manage automatic dynamic hints'),
702 manage_hints
703 ),
704 list_tooltip_callback = get_tooltip
705 )
706
707
708
709
710 if __name__ == '__main__':
711
712 if len(sys.argv) < 2:
713 sys.exit()
714
715 if sys.argv[1] != 'test':
716 sys.exit()
717
718 gmI18N.activate_locale()
719 gmI18N.install_domain(domain = 'gnumed')
720
721
722
723
724
725
726
727
728
729
730
731
732
733