| Home | Trees | Indices | Help |
|
|---|
|
|
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 # reminders
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 # dynamic hints
72 hints2aggregate = []
73 emr = pat.emr
74 hint_dlg = cDynamicHintDlg(wx.GetApp().GetTopWindow(), -1)
75 # single-hint popups
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.DestroyLater()
89 # aggregate popup
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.DestroyLater()
96
97 return
98
99 gmDispatcher.connect(signal = 'post_patient_selection', receiver = _display_clinical_reminders)
100
101 #================================================================
103
104 if parent is None:
105 parent = wx.GetApp().GetTopWindow()
106
107 ea = cAutoHintEAPnl(parent, -1)
108 ea.data = hint
109 ea.mode = gmTools.coalesce(hint, 'new', 'edit')
110 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry)
111 dlg.SetTitle(gmTools.coalesce(hint, _('Adding automatic dynamic hint'), _('Editing automatic dynamic hint')))
112 if dlg.ShowModal() == wx.ID_OK:
113 dlg.DestroyLater()
114 return True
115 dlg.DestroyLater()
116 return False
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 # left_extra_button = (
180 # _('(De)-Activate'),
181 # _('Toggle activation of the selected hint'),
182 # toggle_activation
183 # ),
184 # button to show DB schema
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
199
200 try:
201 self.__hint = kwargs['hint']
202 del kwargs['hint']
203 except KeyError:
204 self.__hint = None
205 wxgDynamicHintDlg.wxgDynamicHintDlg.__init__(self, *args, **kwargs)
206 self.__init_ui()
207 #------------------------------------------------------------
210
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 # internal helpers
224 #------------------------------------------------------------
226 self._TCTRL_rationale.add_callback_on_modified(callback = self._on_rationale_modified)
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 # event handlers
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
310
311 try:
312 self.__hints = kwargs['hints']
313 del kwargs['hints']
314 except KeyError:
315 self.__hints = None
316 wxgDynamicHintListDlg.wxgDynamicHintListDlg.__init__(self, *args, **kwargs)
317 self.__pk_encounter = None
318 self.__init_ui()
319
320 #------------------------------------------------------------
323
329
330 hints = property(_get_hints, _set_hints)
331
332 #------------------------------------------------------------
334 self.__pk_encounter = pk_encounter
335
336 pk_encounter = property(lambda x:x, _set_pk_encounter)
337
338 #------------------------------------------------------------
339 # internal helpers
340 #------------------------------------------------------------
342 self._LCTRL_hints.set_columns([_('Hint'), _('Source')])
343 self._LCTRL_hints.set_column_widths([wx.LIST_AUTOSIZE, wx.LIST_AUTOSIZE])
344 self._LCTRL_hints.set_resize_column(column = 0)
345 self._LCTRL_hints.select_callback = self._on_hint_selected
346 self._LCTRL_hints.deselect_callback = self._on_hint_deselected
347 self._TCTRL_rationale.add_callback_on_modified(callback = self._on_rationale_modified)
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 # event handlers
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
466
468
469 try:
470 data = kwargs['hint']
471 del kwargs['hint']
472 except KeyError:
473 data = None
474
475 wxgAutoHintEAPnl.wxgAutoHintEAPnl.__init__(self, *args, **kwargs)
476 gmEditArea.cGenericEditAreaMixin.__init__(self)
477
478 # Code using this mixin should set mode and data
479 # after instantiating the class:
480 self.mode = 'new'
481 self.data = data
482 if data is not None:
483 self.mode = 'edit'
484
485 #self.__init_ui()
486 #----------------------------------------------------------------
487 # def __init_ui(self):
488 # # adjust phrasewheels etc
489 #----------------------------------------------------------------
490 # generic Edit Area mixin API
491 #----------------------------------------------------------------
493
494 validity = True
495
496 if self._TCTRL_source.GetValue().strip() == '':
497 validity = False
498 self.display_tctrl_as_valid(tctrl = self._TCTRL_source, valid = False)
499 self.StatusText = _('No entry in field <Source>.')
500 self._TCTRL_source.SetFocus()
501 else:
502 self.display_tctrl_as_valid(tctrl = self._TCTRL_source, valid = True)
503
504 if self._TCTRL_query.GetValue().strip() == '':
505 validity = False
506 self.display_tctrl_as_valid(tctrl = self._TCTRL_query, valid = False)
507 self.StatusText = _('No entry in field <Conditions>.')
508 self._TCTRL_query.SetFocus()
509 else:
510 # FIXME: run SQL
511 self.display_tctrl_as_valid(tctrl = self._TCTRL_query, valid = True)
512
513 if self._TCTRL_hint.GetValue().strip() == '':
514 validity = False
515 self.display_tctrl_as_valid(tctrl = self._TCTRL_hint, valid = False)
516 self.StatusText = _('No entry in field <Description>.')
517 self._TCTRL_hint.SetFocus()
518 else:
519 self.display_tctrl_as_valid(tctrl = self._TCTRL_hint, valid = True)
520
521 if self._TCTRL_title.GetValue().strip() == '':
522 validity = False
523 self.display_tctrl_as_valid(tctrl = self._TCTRL_title, valid = False)
524 self.StatusText = _('No entry in field <Title>.')
525 self._TCTRL_title.SetFocus()
526 else:
527 self.display_tctrl_as_valid(tctrl = self._TCTRL_title, valid = True)
528
529 return validity
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, # it seems this MUST be a cursor or else the successfully created row will not show up -- but why ?!?
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 #----------------------------------------------------------------
596 self._TCTRL_title.SetValue('')
597 self._TCTRL_hint.SetValue('')
598 self._TCTRL_query.SetValue('')
599 self._TCTRL_recommendation_query.SetValue('')
600 self._TCTRL_source.SetValue('')
601 self._TCTRL_url.SetValue('')
602 self._CHBOX_is_active.SetValue(True)
603 self._CHBOX_highlight.SetValue(True)
604 self._RBTN_popup_single.SetValue(True)
605
606 self._TCTRL_title.SetFocus()
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 # event handlers
638 #----------------------------------------------------------------
647
648 #================================================================
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 # main
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 # def test_message_inbox():
722 # app = wx.PyWidgetTester(size = (800, 600))
723 # app.SetWidget(cProviderInboxPnl, -1)
724 # app.MainLoop()
725
726 # def test_msg_ea():
727 # app = wx.PyWidgetTester(size = (800, 600))
728 # app.SetWidget(cInboxMessageEAPnl, -1)
729 # app.MainLoop()
730
731 #test_message_inbox()
732 #test_msg_ea()
733
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Sat Feb 29 02:55:27 2020 | http://epydoc.sourceforge.net |