| Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf8 -*-
2 """GNUmed GUI client.
3
4 This contains the GUI application framework and main window
5 of the all signing all dancing GNUmed Python Reference
6 client. It relies on the <gnumed.py> launcher having set up
7 the non-GUI-related runtime environment.
8
9 This source code is protected by the GPL licensing scheme.
10 Details regarding the GPL are available at http://www.gnu.org
11 You may use and share it as long as you don't deny this right
12 to anybody else.
13
14 copyright: authors
15 """
16 #==============================================================================
17 # $Source: /cvsroot/gnumed/gnumed/gnumed/client/wxpython/gmGuiMain.py,v $
18 # $Id: gmGuiMain.py,v 1.491 2010/02/07 15:14:07 ncq Exp $
19 __version__ = "$Revision: 1.491 $"
20 __author__ = "H. Herb <hherb@gnumed.net>,\
21 K. Hilbert <Karsten.Hilbert@gmx.net>,\
22 I. Haywood <i.haywood@ugrad.unimelb.edu.au>"
23 __license__ = 'GPL (details at http://www.gnu.org)'
24
25 # stdlib
26 import sys, time, os, cPickle, zlib, locale, os.path, datetime as pyDT, webbrowser, shutil, logging, urllib2
27
28
29 # 3rd party libs
30 # wxpython version cannot be enforced inside py2exe and friends
31 if not hasattr(sys, 'frozen'):
32 import wxversion
33 wxversion.ensureMinimal('2.8-unicode', optionsRequired=True)
34
35 try:
36 import wx
37 import wx.lib.pubsub
38 except ImportError:
39 print "GNUmed startup: Cannot import wxPython library."
40 print "GNUmed startup: Make sure wxPython is installed."
41 print 'CRITICAL ERROR: Error importing wxPython. Halted.'
42 raise
43
44 # do this check just in case, so we can make sure
45 # py2exe and friends include the proper version, too
46 version = int(u'%s%s' % (wx.MAJOR_VERSION, wx.MINOR_VERSION))
47 if (version < 28) or ('unicode' not in wx.PlatformInfo):
48 print "GNUmed startup: Unsupported wxPython version (%s: %s)." % (wx.VERSION_STRING, wx.PlatformInfo)
49 print "GNUmed startup: wxPython 2.8+ with unicode support is required."
50 print 'CRITICAL ERROR: Proper wxPython version not found. Halted.'
51 raise ValueError('wxPython 2.8+ with unicode support not found')
52
53
54 # GNUmed libs
55 from Gnumed.pycommon import gmCfg, gmPG2, gmDispatcher, gmGuiBroker, gmI18N
56 from Gnumed.pycommon import gmExceptions, gmShellAPI, gmTools, gmDateTime
57 from Gnumed.pycommon import gmHooks, gmBackendListener, gmCfg2, gmLog2
58
59 from Gnumed.business import gmPerson, gmClinicalRecord, gmSurgery, gmEMRStructItems
60
61 from Gnumed.exporters import gmPatientExporter
62
63 from Gnumed.wxpython import gmGuiHelpers, gmHorstSpace, gmEMRBrowser, gmDemographicsWidgets, gmEMRStructWidgets
64 from Gnumed.wxpython import gmStaffWidgets, gmMedDocWidgets, gmPatSearchWidgets, gmAllergyWidgets, gmListWidgets
65 from Gnumed.wxpython import gmFormWidgets, gmSnellen, gmProviderInboxWidgets, gmCfgWidgets, gmExceptionHandlingWidgets
66 from Gnumed.wxpython import gmTimer, gmMeasurementWidgets, gmNarrativeWidgets, gmPhraseWheel, gmMedicationWidgets
67
68 try:
69 _('dummy-no-need-to-translate-but-make-epydoc-happy')
70 except NameError:
71 _ = lambda x:x
72
73 _cfg = gmCfg2.gmCfgData()
74 _provider = None
75 _scripting_listener = None
76
77 _log = logging.getLogger('gm.main')
78 _log.info(__version__)
79 _log.info('wxPython GUI framework: %s %s' % (wx.VERSION_STRING, wx.PlatformInfo))
80
81 #==============================================================================
82 icon_serpent = \
83 """x\xdae\x8f\xb1\x0e\x83 \x10\x86w\x9f\xe2\x92\x1blb\xf2\x07\x96\xeaH:0\xd6\
84 \xc1\x85\xd5\x98N5\xa5\xef?\xf5N\xd0\x8a\xdcA\xc2\xf7qw\x84\xdb\xfa\xb5\xcd\
85 \xd4\xda;\xc9\x1a\xc8\xb6\xcd<\xb5\xa0\x85\x1e\xeb\xbc\xbc7b!\xf6\xdeHl\x1c\
86 \x94\x073\xec<*\xf7\xbe\xf7\x99\x9d\xb21~\xe7.\xf5\x1f\x1c\xd3\xbdVlL\xc2\
87 \xcf\xf8ye\xd0\x00\x90\x0etH \x84\x80B\xaa\x8a\x88\x85\xc4(U\x9d$\xfeR;\xc5J\
88 \xa6\x01\xbbt9\xceR\xc8\x81e_$\x98\xb9\x9c\xa9\x8d,y\xa9t\xc8\xcf\x152\xe0x\
89 \xe9$\xf5\x07\x95\x0cD\x95t:\xb1\x92\xae\x9cI\xa8~\x84\x1f\xe0\xa3ec"""
90 #==============================================================================
92 """GNUmed client's main windows frame.
93
94 This is where it all happens. Avoid popping up any other windows.
95 Most user interaction should happen to and from widgets within this frame
96 """
97 #----------------------------------------------
99 """You'll have to browse the source to understand what the constructor does
100 """
101 wx.Frame.__init__(self, parent, id, title, size, style = wx.DEFAULT_FRAME_STYLE)
102
103 self.__gb = gmGuiBroker.GuiBroker()
104 self.__pre_exit_callbacks = []
105 self.bar_width = -1
106 self.menu_id2plugin = {}
107
108 _log.info('workplace is >>>%s<<<', gmSurgery.gmCurrentPractice().active_workplace)
109
110 self.__setup_main_menu()
111 self.setup_statusbar()
112 self.SetStatusText(_('You are logged in as %s%s.%s (%s). DB account <%s>.') % (
113 gmTools.coalesce(_provider['title'], ''),
114 _provider['firstnames'][:1],
115 _provider['lastnames'],
116 _provider['short_alias'],
117 _provider['db_user']
118 ))
119
120 self.__set_window_title_template()
121 self.__update_window_title()
122 self.__set_window_icon()
123
124 self.__register_events()
125
126 self.LayoutMgr = gmHorstSpace.cHorstSpaceLayoutMgr(self, -1)
127 self.vbox = wx.BoxSizer(wx.VERTICAL)
128 self.vbox.Add(self.LayoutMgr, 10, wx.EXPAND | wx.ALL, 1)
129
130 self.SetAutoLayout(True)
131 self.SetSizerAndFit(self.vbox)
132
133 # don't allow the window to get too small
134 # setsizehints only allows minimum size, therefore window can't become small enough
135 # effectively we need the font size to be configurable according to screen size
136 #self.vbox.SetSizeHints(self)
137 self.__set_GUI_size()
138 #----------------------------------------------
140 # set window icon
141 icon_bmp_data = wx.BitmapFromXPMData(cPickle.loads(zlib.decompress(icon_serpent)))
142 icon = wx.EmptyIcon()
143 icon.CopyFromBitmap(icon_bmp_data)
144 self.SetIcon(icon)
145 #----------------------------------------------
147 """Try to get previous window size from backend."""
148
149 cfg = gmCfg.cCfgSQL()
150
151 # width
152 width = int(cfg.get2 (
153 option = 'main.window.width',
154 workplace = gmSurgery.gmCurrentPractice().active_workplace,
155 bias = 'workplace',
156 default = 800
157 ))
158
159 # height
160 height = int(cfg.get2 (
161 option = 'main.window.height',
162 workplace = gmSurgery.gmCurrentPractice().active_workplace,
163 bias = 'workplace',
164 default = 600
165 ))
166
167 _log.debug('setting GUI size to [%s:%s]' % (width, height))
168 self.SetClientSize(wx.Size(width, height))
169 #----------------------------------------------
710 #----------------------------------------------
713 #----------------------------------------------
714 # event handling
715 #----------------------------------------------
717 """register events we want to react to"""
718
719 wx.EVT_CLOSE(self, self.OnClose)
720 wx.EVT_QUERY_END_SESSION(self, self._on_query_end_session)
721 wx.EVT_END_SESSION(self, self._on_end_session)
722
723 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
724 gmDispatcher.connect(signal = u'name_mod_db', receiver = self._on_pat_name_changed)
725 gmDispatcher.connect(signal = u'identity_mod_db', receiver = self._on_pat_name_changed)
726 gmDispatcher.connect(signal = u'statustext', receiver = self._on_set_statustext)
727 gmDispatcher.connect(signal = u'request_user_attention', receiver = self._on_request_user_attention)
728 gmDispatcher.connect(signal = u'db_maintenance_warning', receiver = self._on_db_maintenance_warning)
729 gmDispatcher.connect(signal = u'register_pre_exit_callback', receiver = self._register_pre_exit_callback)
730 gmDispatcher.connect(signal = u'plugin_loaded', receiver = self._on_plugin_loaded)
731
732 wx.lib.pubsub.Publisher().subscribe(listener = self._on_set_statustext_pubsub, topic = 'statustext')
733
734 gmPerson.gmCurrentPatient().register_pre_selection_callback(callback = self._pre_selection_callback)
735 #----------------------------------------------
736 - def _on_plugin_loaded(self, plugin_name=None, class_name=None, menu_name=None, menu_item_name=None, menu_help_string=None):
737
738 _log.debug('registering plugin with menu system')
739 _log.debug(' generic name: %s', plugin_name)
740 _log.debug(' class name: %s', class_name)
741 _log.debug(' specific menu: %s', menu_name)
742 _log.debug(' menu item: %s', menu_item_name)
743
744 # add to generic "go to plugin" menu
745 item = self.menu_plugins.Append(-1, plugin_name, _('Raise plugin [%s].') % plugin_name)
746 self.Bind(wx.EVT_MENU, self.__on_raise_a_plugin, item)
747 self.menu_id2plugin[item.Id] = class_name
748
749 # add to specific menu if so requested
750 if menu_name is not None:
751 menu = self.__gb['main.%smenu' % menu_name]
752 item = menu.Append(-1, menu_item_name, menu_help_string)
753 self.Bind(wx.EVT_MENU, self.__on_raise_a_plugin, item)
754 self.menu_id2plugin[item.Id] = class_name
755
756 return True
757 #----------------------------------------------
759 gmDispatcher.send (
760 signal = u'display_widget',
761 name = self.menu_id2plugin[evt.Id]
762 )
763 #----------------------------------------------
765 wx.Bell()
766 wx.Bell()
767 wx.Bell()
768 _log.warning('unhandled event detected: QUERY_END_SESSION')
769 _log.info('we should be saving ourselves from here')
770 gmLog2.flush()
771 print "unhandled event detected: QUERY_END_SESSION"
772 #----------------------------------------------
774 wx.Bell()
775 wx.Bell()
776 wx.Bell()
777 _log.warning('unhandled event detected: END_SESSION')
778 gmLog2.flush()
779 print "unhandled event detected: END_SESSION"
780 #-----------------------------------------------
782 if not callable(callback):
783 raise TypeError(u'callback [%s] not callable' % callback)
784
785 self.__pre_exit_callbacks.append(callback)
786 #-----------------------------------------------
788 msg = u'%s %s' % (gmDateTime.pydt_now_here().strftime('%H:%M'), context.data['msg'])
789 wx.CallAfter(self.SetStatusText, msg)
790
791 try:
792 if context.data['beep']:
793 wx.Bell()
794 except KeyError:
795 pass
796 #-----------------------------------------------
798
799 if msg is None:
800 msg = _('programmer forgot to specify status message')
801
802 if loglevel is not None:
803 _log.log(loglevel, msg.replace('\015', ' ').replace('\012', ' '))
804
805 msg = u'%s %s' % (gmDateTime.pydt_now_here().strftime('%H:%M'), msg)
806 wx.CallAfter(self.SetStatusText, msg)
807
808 if beep:
809 wx.Bell()
810 #-----------------------------------------------
813 #-----------------------------------------------
815
816 self.SetStatusText(_('The database will be shut down for maintenance in a few minutes.'))
817 wx.Bell()
818 if not wx.GetApp().IsActive():
819 self.RequestUserAttention(flags = wx.USER_ATTENTION_ERROR)
820
821 gmHooks.run_hook_script(hook = u'db_maintenance_warning')
822
823 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
824 None,
825 -1,
826 caption = _('Database shutdown warning'),
827 question = _(
828 'The database will be shut down for maintenance\n'
829 'in a few minutes.\n'
830 '\n'
831 'In order to not suffer any loss of data you\n'
832 'will need to save your current work and log\n'
833 'out of this GNUmed client.\n'
834 ),
835 button_defs = [
836 {
837 u'label': _('Close now'),
838 u'tooltip': _('Close this GNUmed client immediately.'),
839 u'default': False
840 },
841 {
842 u'label': _('Finish work'),
843 u'tooltip': _('Finish and save current work first, then manually close this GNUmed client.'),
844 u'default': True
845 }
846 ]
847 )
848 decision = dlg.ShowModal()
849 if decision == wx.ID_YES:
850 top_win = wx.GetApp().GetTopWindow()
851 wx.CallAfter(top_win.Close)
852 #-----------------------------------------------
855 #-----------------------------------------------
857 # already in the foreground ?
858 if not wx.GetApp().IsActive():
859 if urgent:
860 self.RequestUserAttention(flags = wx.USER_ATTENTION_ERROR)
861 else:
862 self.RequestUserAttention(flags = wx.USER_ATTENTION_INFO)
863
864 if msg is not None:
865 self.SetStatusText(msg)
866
867 if urgent:
868 wx.Bell()
869
870 gmHooks.run_hook_script(hook = u'request_user_attention')
871 #-----------------------------------------------
874 #-----------------------------------------------
877 #-----------------------------------------------
880 #----------------------------------------------
882 self.__update_window_title()
883 try:
884 gmHooks.run_hook_script(hook = u'post_patient_activation')
885 except:
886 gmDispatcher.send(signal = 'statustext', msg = _('Cannot run script after patient activation.'))
887 raise
888 #----------------------------------------------
891 #----------------------------------------------
893
894 dbcfg = gmCfg.cCfgSQL()
895 check_enc = bool(dbcfg.get2 (
896 option = 'encounter.show_editor_before_patient_change',
897 workplace = gmSurgery.gmCurrentPractice().active_workplace,
898 bias = 'user',
899 default = True # True: if needed, not always unconditionally
900 ))
901
902 if not check_enc:
903 return True
904
905 pat = gmPerson.gmCurrentPatient()
906 emr = pat.get_emr()
907 enc = emr.active_encounter
908
909 # did we add anything to the EMR ?
910 has_narr = enc.has_narrative()
911 has_docs = enc.has_documents()
912
913 if (not has_narr) and (not has_docs):
914 return True
915
916 empty_aoe = (gmTools.coalesce(enc['assessment_of_encounter'], '').strip() == u'')
917 zero_duration = (enc['last_affirmed'] == enc['started'])
918
919 # all is well anyway
920 if (not empty_aoe) and (not zero_duration):
921 return True
922
923 if zero_duration:
924 enc['last_affirmed'] = pyDT.datetime.now(tz=gmDateTime.gmCurrentLocalTimezone)
925
926 # no narrative, presumably only import of docs and done
927 if not has_narr:
928 if empty_aoe:
929 enc['assessment_of_encounter'] = _('only documents added')
930 enc['pk_type'] = gmEMRStructItems.get_encounter_type(description = 'chart review')[0]['pk']
931 # "last_affirmed" should be latest modified_at of relevant docs but that's a lot more involved
932 enc.save_payload()
933 return True
934
935 # does have narrative
936 if empty_aoe:
937 # - work out suitable default
938 epis = emr.get_episodes_by_encounter()
939 if len(epis) > 0:
940 enc_summary = ''
941 for epi in epis:
942 enc_summary += '%s; ' % epi['description']
943 enc['assessment_of_encounter'] = enc_summary
944
945 dlg = gmEMRStructWidgets.cEncounterEditAreaDlg(parent = self, encounter = enc)
946 dlg.ShowModal()
947
948 return True
949 #----------------------------------------------
950 # menu "paperwork"
951 #----------------------------------------------
954 #----------------------------------------------
956 pat = gmPerson.gmCurrentPatient()
957 if not pat.connected:
958 gmDispatcher.send(signal = 'statustext', msg = _('Cannot write letter. No active patient.'), beep = True)
959 return True
960 #gmFormWidgets.create_new_letter(parent = self)
961 gmFormWidgets.print_doc_from_template(parent = self, keep_a_copy = True, cleanup = _cfg.get(option = 'debug'))
962 #----------------------------------------------
965 #----------------------------------------------
966 # help menu
967 #----------------------------------------------
969 from Gnumed.wxpython import gmAbout
970 gmAbout = gmAbout.AboutFrame (
971 self,
972 -1,
973 _("About GNUmed"),
974 size=wx.Size(350, 300),
975 style = wx.MAXIMIZE_BOX,
976 version = _cfg.get(option = 'client_version')
977 )
978 gmAbout.Centre(wx.BOTH)
979 gmTopLevelFrame.otherWin = gmAbout
980 gmAbout.Show(True)
981 del gmAbout
982 #----------------------------------------------
984 praxis = gmSurgery.gmCurrentPractice()
985 msg = praxis.db_logon_banner
986
987 login = gmPG2.get_default_login()
988
989 auth = _(
990 '\n\n'
991 ' workplace: %s\n'
992 ' account: %s\n'
993 ' database: %s\n'
994 ' server: %s\n'
995 ) % (
996 praxis.active_workplace,
997 login.user,
998 login.database,
999 gmTools.coalesce(login.host, u'<localhost>')
1000 )
1001
1002 msg += auth
1003
1004 gmGuiHelpers.gm_show_info(msg, _('About database and server'))
1005 #----------------------------------------------
1007 from Gnumed.wxpython import gmAbout
1008 contribs = gmAbout.cContributorsDlg (
1009 parent = self,
1010 id = -1,
1011 title = _('GNUmed contributors'),
1012 size = wx.Size(400,600),
1013 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER
1014 )
1015 contribs.ShowModal()
1016 del contribs
1017 del gmAbout
1018 #----------------------------------------------
1019 # GNUmed menu
1020 #----------------------------------------------
1022 """Invoked from Menu GNUmed / Exit (which calls this ID_EXIT handler)."""
1023 _log.debug('gmTopLevelFrame._on_exit_gnumed() start')
1024 self.Close(True) # -> calls wx.EVT_CLOSE handler
1025 _log.debug('gmTopLevelFrame._on_exit_gnumed() end')
1026 #----------------------------------------------
1029 #----------------------------------------------
1031 send = gmGuiHelpers.gm_show_question (
1032 _('This will send a notification about database downtime\n'
1033 'to all GNUmed clients connected to your database.\n'
1034 '\n'
1035 'Do you want to send the notification ?\n'
1036 ),
1037 _('Announcing database maintenance downtime')
1038 )
1039 if not send:
1040 return
1041 gmPG2.send_maintenance_notification()
1042 #----------------------------------------------
1043 # submenu GNUmed / options / client
1044 #----------------------------------------------
1046
1047 cfg = gmCfg.cCfgSQL()
1048
1049 tmp_dir = gmTools.coalesce (
1050 cfg.get2 (
1051 option = "horstspace.tmp_dir",
1052 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1053 bias = 'workplace'
1054 ),
1055 os.path.expanduser(os.path.join('~', '.gnumed', 'tmp'))
1056 )
1057
1058 dlg = wx.DirDialog (
1059 parent = self,
1060 message = _('Choose temporary directory ...'),
1061 defaultPath = tmp_dir,
1062 style = wx.DD_DEFAULT_STYLE
1063 )
1064 result = dlg.ShowModal()
1065 tmp_dir = dlg.GetPath()
1066 dlg.Destroy()
1067
1068 if result != wx.ID_OK:
1069 return
1070
1071 cfg.set (
1072 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1073 option = "horstspace.tmp_dir",
1074 value = tmp_dir
1075 )
1076 #----------------------------------------------
1078
1079 def is_valid(value):
1080 try:
1081 i = int(value)
1082 except:
1083 return False, value
1084 if i < 0:
1085 return False, value
1086 if i > (1024 * 1024 * 1024 * 10): # 10 GB
1087 return False, value
1088 return True, i
1089
1090 gmCfgWidgets.configure_string_option (
1091 message = _(
1092 'Some network installations cannot cope with loading\n'
1093 'documents of arbitrary size in one piece from the\n'
1094 'database (mainly observed on older Windows versions)\n.'
1095 '\n'
1096 'Under such circumstances documents need to be retrieved\n'
1097 'in chunks and reassembled on the client.\n'
1098 '\n'
1099 'Here you can set the size (in Bytes) above which\n'
1100 'GNUmed will retrieve documents in chunks. Setting this\n'
1101 'value to 0 will disable the chunking protocol.'
1102 ),
1103 option = 'horstspace.blob_export_chunk_size',
1104 bias = 'workplace',
1105 default_value = 1024 * 1024,
1106 validator = is_valid
1107 )
1108 #----------------------------------------------
1109 # submenu GNUmed / database
1110 #----------------------------------------------
1112
1113 langs = gmPG2.get_translation_languages()
1114
1115 for lang in [
1116 gmI18N.system_locale_level['language'],
1117 gmI18N.system_locale_level['country'],
1118 gmI18N.system_locale_level['full']
1119 ]:
1120 if lang not in langs:
1121 langs.append(lang)
1122
1123 selected_lang = gmPG2.get_current_user_language()
1124 try:
1125 selections = [langs.index(selected_lang)]
1126 except ValueError:
1127 selections = None
1128
1129 language = gmListWidgets.get_choices_from_list (
1130 parent = self,
1131 msg = _(
1132 'Please select your database language from the list below.\n'
1133 '\n'
1134 'Your current setting is [%s].\n'
1135 '\n'
1136 'This setting will not affect the language the user interface\n'
1137 'is displayed in but rather that of the metadata returned\n'
1138 'from the database such as encounter types, document types,\n'
1139 'and EMR formatting.\n'
1140 '\n'
1141 'To switch back to the default English language unselect all\n'
1142 'pre-selected languages from the list below.'
1143 ) % gmTools.coalesce(selected_lang, _('not configured')),
1144 caption = _('Configuring database language'),
1145 choices = langs,
1146 selections = selections,
1147 columns = [_('Language')],
1148 data = langs,
1149 single_selection = True,
1150 can_return_empty = True
1151 )
1152
1153 if language is None:
1154 return
1155
1156 if language == []:
1157 language = None
1158
1159 try:
1160 _provider.get_staff().database_language = language
1161 return
1162 except ValueError:
1163 pass
1164
1165 force_language = gmGuiHelpers.gm_show_question (
1166 _('The database currently holds no translations for\n'
1167 'language [%s]. However, you can add translations\n'
1168 'for things like document or encounter types yourself.\n'
1169 '\n'
1170 'Do you want to force the language setting to [%s] ?'
1171 ) % (language, language),
1172 _('Configuring database language')
1173 )
1174 if not force_language:
1175 return
1176
1177 gmPG2.force_user_language(language = language)
1178 #----------------------------------------------
1182 #----------------------------------------------
1183 # submenu GNUmed - config - external tools
1184 #----------------------------------------------
1186
1187 def is_valid(value):
1188 try:
1189 return True, float(value)
1190 except:
1191 return False, value
1192
1193 gmCfgWidgets.configure_string_option (
1194 message = _(
1195 'When GNUmed cannot find an OpenOffice server it\n'
1196 'will try to start one. OpenOffice, however, needs\n'
1197 'some time to fully start up.\n'
1198 '\n'
1199 'Here you can set the time for GNUmed to wait for OOo.\n'
1200 ),
1201 option = 'external.ooo.startup_settle_time',
1202 bias = 'workplace',
1203 default_value = 2.0,
1204 validator = is_valid
1205 )
1206 #----------------------------------------------
1209 #----------------------------------------------
1211
1212 def is_valid(value):
1213 value = value.strip()
1214 if value == u'':
1215 return True, value
1216 try:
1217 urllib2.urlopen(value)
1218 return True, value
1219 except:
1220 return False, value
1221
1222 gmCfgWidgets.configure_string_option (
1223 message = _(
1224 'GNUmed will use this URL to access an encyclopedia of\n'
1225 'measurement/lab methods from within the measurments grid.\n'
1226 '\n'
1227 'You can leave this empty but to set it to a specific\n'
1228 'address the URL must be accessible now.'
1229 ),
1230 option = 'external.urls.measurements_encyclopedia',
1231 bias = 'user',
1232 default_value = u'http://www.laborlexikon.de',
1233 validator = is_valid
1234 )
1235 #----------------------------------------------
1237
1238 def is_valid(value):
1239 found, binary = gmShellAPI.detect_external_binary(value)
1240 if not found:
1241 gmDispatcher.send (
1242 signal = 'statustext',
1243 msg = _('The command [%s] is not found. This may or may not be a problem.') % value,
1244 beep = True
1245 )
1246 return False, value
1247 return True, binary
1248
1249 gmCfgWidgets.configure_string_option (
1250 message = _(
1251 'Enter the shell command with which to start the\n'
1252 'the ACS risk assessment calculator.\n'
1253 '\n'
1254 'GNUmed will try to verify the path which may,\n'
1255 'however, fail if you are using an emulator such\n'
1256 'as Wine. Nevertheless, starting the calculator\n'
1257 'will work as long as the shell command is correct\n'
1258 'despite the failing test.'
1259 ),
1260 option = 'external.tools.acs_risk_calculator_cmd',
1261 bias = 'user',
1262 validator = is_valid
1263 )
1264 #----------------------------------------------
1266
1267 def is_valid(value):
1268 found, binary = gmShellAPI.detect_external_binary(value)
1269 if not found:
1270 gmDispatcher.send (
1271 signal = 'statustext',
1272 msg = _('The command [%s] is not found. This may or may not be a problem.') % value,
1273 beep = True
1274 )
1275 return False, value
1276 return True, binary
1277
1278 gmCfgWidgets.configure_string_option (
1279 message = _(
1280 'Enter the shell command with which to start the\n'
1281 'the IFAP drug database.\n'
1282 '\n'
1283 'GNUmed will try to verify the path which may,\n'
1284 'however, fail if you are using an emulator such\n'
1285 'as Wine. Nevertheless, starting IFAP will work\n'
1286 'as long as the shell command is correct despite\n'
1287 'the failing test.'
1288 ),
1289 option = 'external.ifap-win.shell_command',
1290 bias = 'workplace',
1291 default_value = 'C:\Ifapwin\WIAMDB.EXE',
1292 validator = is_valid
1293 )
1294 #----------------------------------------------
1295 # submenu GNUmed / config / ui
1296 #----------------------------------------------
1298
1299 dbcfg = gmCfg.cCfgSQL()
1300 # get list of possible plugins
1301 plugin_list = gmTools.coalesce(dbcfg.get2 (
1302 option = u'horstspace.notebook.plugin_load_order',
1303 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1304 bias = 'user'
1305 ), [])
1306
1307 # get current setting
1308 initial_plugin = gmTools.coalesce(dbcfg.get2 (
1309 option = u'horstspace.plugin_to_raise_after_startup',
1310 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1311 bias = 'user'
1312 ), u'gmEMRBrowserPlugin')
1313 try:
1314 selections = [plugin_list.index(initial_plugin)]
1315 except ValueError:
1316 selections = None
1317
1318 # now let user decide
1319 plugin = gmListWidgets.get_choices_from_list (
1320 parent = self,
1321 msg = _(
1322 'Here you can choose which plugin you want\n'
1323 'GNUmed to display after initial startup.\n'
1324 '\n'
1325 'Note that the plugin must not require any\n'
1326 'patient to be activated.\n'
1327 '\n'
1328 'Select the desired plugin below:'
1329 ),
1330 caption = _('Configuration'),
1331 choices = plugin_list,
1332 selections = selections,
1333 columns = [_('GNUmed Plugin')],
1334 single_selection = True
1335 )
1336
1337 if plugin is None:
1338 return
1339
1340 dbcfg.set (
1341 option = u'patient_search.plugin_to_raise_after_startup',
1342 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1343 value = plugin
1344 )
1345 #----------------------------------------------
1346 # submenu GNUmed / config / ui / patient search
1347 #----------------------------------------------
1349 gmCfgWidgets.configure_boolean_option (
1350 parent = self,
1351 question = _(
1352 'If there is only one external patient\n'
1353 'source available do you want GNUmed\n'
1354 'to immediately go ahead and search for\n'
1355 'matching patient records ?\n\n'
1356 'If not GNUmed will let you confirm the source.'
1357 ),
1358 option = 'patient_search.external_sources.immediately_search_if_single_source',
1359 button_tooltips = [
1360 _('Yes, search for matches immediately.'),
1361 _('No, let me confirm the external patient first.')
1362 ]
1363 )
1364 #----------------------------------------------
1367 #----------------------------------------------
1370 #----------------------------------------------
1375
1376 gmCfgWidgets.configure_string_option (
1377 message = _(
1378 'When a patient is activated GNUmed checks the\n'
1379 "proximity of the patient's birthday.\n"
1380 '\n'
1381 'If the birthday falls within the range of\n'
1382 ' "today %s <the interval you set here>"\n'
1383 'GNUmed will remind you of the recent or\n'
1384 'imminent anniversary.'
1385 ) % u'\u2213',
1386 option = u'patient_search.dob_warn_interval',
1387 bias = 'user',
1388 default_value = '1 week',
1389 validator = is_valid
1390 )
1391 #----------------------------------------------
1393
1394 gmCfgWidgets.configure_boolean_option (
1395 parent = self,
1396 question = _(
1397 'When adding progress notes do you want to\n'
1398 'allow opening several unassociated, new\n'
1399 'episodes for a patient at once ?\n'
1400 '\n'
1401 'This can be particularly helpful when entering\n'
1402 'progress notes on entirely new patients presenting\n'
1403 'with a multitude of problems on their first visit.'
1404 ),
1405 option = u'horstspace.soap_editor.allow_same_episode_multiple_times',
1406 button_tooltips = [
1407 _('Yes, allow for multiple new episodes concurrently.'),
1408 _('No, only allow editing one new episode at a time.')
1409 ]
1410 )
1411 #----------------------------------------------
1413
1414 dbcfg = gmCfg.cCfgSQL()
1415 # get list of possible plugins
1416 plugin_list = gmTools.coalesce(dbcfg.get2 (
1417 option = u'horstspace.notebook.plugin_load_order',
1418 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1419 bias = 'user'
1420 ), [])
1421
1422 # get current setting
1423 initial_plugin = gmTools.coalesce(dbcfg.get2 (
1424 option = u'patient_search.plugin_to_raise_after_search',
1425 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1426 bias = 'user'
1427 ), u'gmEMRBrowserPlugin')
1428 try:
1429 selections = [plugin_list.index(initial_plugin)]
1430 except ValueError:
1431 selections = None
1432
1433 # now let user decide
1434 plugin = gmListWidgets.get_choices_from_list (
1435 parent = self,
1436 msg = _(
1437 'When a patient is activated GNUmed can\n'
1438 'be told to switch to a specific plugin.\n'
1439 '\n'
1440 'Select the desired plugin below:'
1441 ),
1442 caption = _('Configuration'),
1443 choices = plugin_list,
1444 selections = selections,
1445 columns = [_('GNUmed Plugin')],
1446 single_selection = True
1447 )
1448
1449 if plugin is None:
1450 return
1451
1452 dbcfg.set (
1453 option = u'patient_search.plugin_to_raise_after_search',
1454 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1455 value = plugin
1456 )
1457 #----------------------------------------------
1458 # submenu GNUmed / config / encounter
1459 #----------------------------------------------
1462 #----------------------------------------------
1464 enc_types = gmEMRStructItems.get_encounter_types()
1465
1466 gmCfgWidgets.configure_string_from_list_option (
1467 parent = self,
1468 message = _('Select the default type for new encounters.\n'),
1469 option = 'encounter.default_type',
1470 bias = 'user',
1471 default_value = u'in surgery',
1472 choices = [ e[0] for e in enc_types ],
1473 columns = [_('Encounter type')],
1474 data = [ e[1] for e in enc_types ]
1475 )
1476 #----------------------------------------------
1478 gmCfgWidgets.configure_boolean_option (
1479 parent = self,
1480 question = _(
1481 'Do you want GNUmed to show the encounter\n'
1482 'details editor when changing the active patient ?'
1483 ),
1484 option = 'encounter.show_editor_before_patient_change',
1485 button_tooltips = [
1486 _('Yes, show the encounter editor if it seems appropriate.'),
1487 _('No, never show the encounter editor even if it would seem useful.')
1488 ]
1489 )
1490 #----------------------------------------------
1495
1496 gmCfgWidgets.configure_string_option (
1497 message = _(
1498 'When a patient is activated GNUmed checks the\n'
1499 'chart for encounters lacking any entries.\n'
1500 '\n'
1501 'Any such encounters older than what you set\n'
1502 'here will be removed from the medical record.\n'
1503 '\n'
1504 'To effectively disable removal of such encounters\n'
1505 'set this option to an improbable value.\n'
1506 ),
1507 option = 'encounter.ttl_if_empty',
1508 bias = 'user',
1509 default_value = '1 week',
1510 validator = is_valid
1511 )
1512 #----------------------------------------------
1517
1518 gmCfgWidgets.configure_string_option (
1519 message = _(
1520 'When a patient is activated GNUmed checks the\n'
1521 'age of the most recent encounter.\n'
1522 '\n'
1523 'If that encounter is younger than this age\n'
1524 'the existing encounter will be continued.\n'
1525 '\n'
1526 '(If it is really old a new encounter is\n'
1527 ' started, or else GNUmed will ask you.)\n'
1528 ),
1529 option = 'encounter.minimum_ttl',
1530 bias = 'user',
1531 default_value = '1 hour 30 minutes',
1532 validator = is_valid
1533 )
1534 #----------------------------------------------
1539
1540 gmCfgWidgets.configure_string_option (
1541 message = _(
1542 'When a patient is activated GNUmed checks the\n'
1543 'age of the most recent encounter.\n'
1544 '\n'
1545 'If that encounter is older than this age\n'
1546 'GNUmed will always start a new encounter.\n'
1547 '\n'
1548 '(If it is very recent the existing encounter\n'
1549 ' is continued, or else GNUmed will ask you.)\n'
1550 ),
1551 option = 'encounter.maximum_ttl',
1552 bias = 'user',
1553 default_value = '6 hours',
1554 validator = is_valid
1555 )
1556 #----------------------------------------------
1558
1559 def is_valid(value):
1560 try:
1561 value = int(value)
1562 except:
1563 return False, value
1564 return gmPG2.is_pg_interval(candidate=value), value
1565
1566 gmCfgWidgets.configure_string_option (
1567 message = _(
1568 'At any time there can only be one open (ongoing)\n'
1569 'episode for each health issue.\n'
1570 '\n'
1571 'When you try to open (add data to) an episode on a health\n'
1572 'issue GNUmed will check for an existing open episode on\n'
1573 'that issue. If there is any it will check the age of that\n'
1574 'episode. The episode is closed if it has been dormant (no\n'
1575 'data added, that is) for the period of time (in days) you\n'
1576 'set here.\n'
1577 '\n'
1578 "If the existing episode hasn't been dormant long enough\n"
1579 'GNUmed will consult you what to do.\n'
1580 '\n'
1581 'Enter maximum episode dormancy in DAYS:'
1582 ),
1583 option = 'episode.ttl',
1584 bias = 'user',
1585 default_value = 60,
1586 validator = is_valid
1587 )
1588 #----------------------------------------------
1590 email = gmSurgery.gmCurrentPractice().user_email
1591
1592 dlg = wx.TextEntryDialog (
1593 parent = self,
1594 message = _(
1595 'This email address will be used when GNUmed\n'
1596 'is sending email on your behalf such as when\n'
1597 'reporting bugs or when you choose to contribute\n'
1598 'reference material to the GNUmed community.\n'
1599 '\n'
1600 'The developers will then be able to get back to you\n'
1601 'directly with advice. Otherwise you would have to\n'
1602 'follow the mailing list discussion for help.\n'
1603 '\n'
1604 'Leave this blank if you wish to stay anonymous.'
1605 ),
1606 caption = _('Please enter your email address.'),
1607 defaultValue = gmTools.coalesce(email, u''),
1608 style = wx.OK | wx.CANCEL | wx.CENTRE
1609 )
1610 decision = dlg.ShowModal()
1611 if decision == wx.ID_CANCEL:
1612 dlg.Destroy()
1613 return
1614
1615 email = dlg.GetValue().strip()
1616 gmSurgery.gmCurrentPractice().user_email = email
1617 gmExceptionHandlingWidgets.set_sender_email(email)
1618 dlg.Destroy()
1619 #----------------------------------------------
1622 #----------------------------------------------
1624 gmCfgWidgets.configure_boolean_option (
1625 question = _(
1626 'Do you want GNUmed to check for updates at startup ?\n'
1627 '\n'
1628 'You will still need your system administrator to\n'
1629 'actually install any updates for you.\n'
1630 ),
1631 option = u'horstspace.update.autocheck_at_startup',
1632 button_tooltips = [
1633 _('Yes, check for updates at startup.'),
1634 _('No, do not check for updates at startup.')
1635 ]
1636 )
1637 #----------------------------------------------
1639 gmCfgWidgets.configure_boolean_option (
1640 question = _(
1641 'When checking for updates do you want GNUmed to\n'
1642 'look for bug fix updates only or do you want to\n'
1643 'know about features updates, too ?\n'
1644 '\n'
1645 'Minor updates (x.y.z.a -> x.y.z.b) contain bug fixes\n'
1646 'only. They can usually be installed without much\n'
1647 'preparation. They never require a database upgrade.\n'
1648 '\n'
1649 'Major updates (x.y.a -> x..y.b or y.a -> x.b) come\n'
1650 'with new features. They need more preparation and\n'
1651 'often require a database upgrade.\n'
1652 '\n'
1653 'You will still need your system administrator to\n'
1654 'actually install any updates for you.\n'
1655 ),
1656 option = u'horstspace.update.consider_latest_branch',
1657 button_tooltips = [
1658 _('Yes, check for feature updates, too.'),
1659 _('No, check for bug-fix updates only.')
1660 ]
1661 )
1662 #----------------------------------------------
1664
1665 import urllib2 as url
1666
1667 def is_valid(value):
1668 try:
1669 url.urlopen(value)
1670 except:
1671 return False, value
1672
1673 return True, value
1674
1675 gmCfgWidgets.configure_string_option (
1676 message = _(
1677 'GNUmed can check for new releases being available. To do\n'
1678 'so it needs to load version information from an URL.\n'
1679 '\n'
1680 'The default URL is:\n'
1681 '\n'
1682 ' http://www.gnumed.de/downloads/gnumed-versions.txt\n'
1683 '\n'
1684 'but you can configure any other URL locally. Note\n'
1685 'that you must enter the location as a valid URL.\n'
1686 'Depending on the URL the client will need online\n'
1687 'access when checking for updates.'
1688 ),
1689 option = u'horstspace.update.url',
1690 bias = u'workplace',
1691 default_value = u'http://www.gnumed.de/downloads/gnumed-versions.txt',
1692 validator = is_valid
1693 )
1694 #----------------------------------------------
1696 gmCfgWidgets.configure_boolean_option (
1697 question = _(
1698 'Do you want to allow saving of new documents without\n'
1699 'any parts or do you want GNUmed to enforce that they\n'
1700 'contain at least one part before they can be saved ?\n'
1701 '\n'
1702 'Part-less documents can be useful if you want to build\n'
1703 'up an index of, say, archived documents but do not\n'
1704 'want to scan in all the pages contained therein.'
1705 ),
1706 option = u'horstspace.scan_index.allow_partless_documents',
1707 button_tooltips = [
1708 _('Yes, allow saving documents without any parts.'),
1709 _('No, require documents to have at least one part.')
1710 ]
1711 )
1712 #----------------------------------------------
1714 gmCfgWidgets.configure_boolean_option (
1715 question = _(
1716 'After importing a new document do you\n'
1717 'want GNUmed to display the unique ID\n'
1718 'it auto-generated for that document ?\n'
1719 '\n'
1720 'This can be useful if you want to label the\n'
1721 'originals with that ID for later identification.'
1722 ),
1723 option = u'horstspace.scan_index.show_doc_id',
1724 button_tooltips = [
1725 _('Yes, display the ID generated for the new document after importing.'),
1726 _('No, do not display the ID generated for the new document after importing.')
1727 ]
1728 )
1729 #----------------------------------------------
1731
1732 def is_valid(value):
1733 try:
1734 value = int(value)
1735 except:
1736 return False, value
1737 if value not in [0, 1, 2]:
1738 return False, value
1739 return True, value
1740
1741 gmCfgWidgets.configure_string_option (
1742 message = _(
1743 'GNUmed can show the document review dialog after\n'
1744 'calling the appropriate viewer for that document.\n'
1745 '\n'
1746 'Select the conditions under which you want\n'
1747 'GNUmed to do so:\n'
1748 '\n'
1749 ' 0: never display the review dialog\n'
1750 ' 1: always display the dialog\n'
1751 ' 2: only if there is no previous review by me\n'
1752 '\n'
1753 'Note that if a viewer is configured to not block\n'
1754 'GNUmed during document display the review dialog\n'
1755 'will actually appear in parallel to the viewer.'
1756 ),
1757 option = u'horstspace.document_viewer.review_after_display',
1758 bias = u'user',
1759 default_value = 2,
1760 validator = is_valid
1761 )
1762 #----------------------------------------------
1764
1765 if os.access('/Applications/OsiriX.app/Contents/MacOS/OsiriX', os.X_OK):
1766 gmShellAPI.run_command_in_shell('/Applications/OsiriX.app/Contents/MacOS/OsiriX', blocking=False)
1767 return
1768
1769 for viewer in ['aeskulap', 'amide', 'xmedcon']:
1770 found, cmd = gmShellAPI.detect_external_binary(binary = viewer)
1771 if found:
1772 gmShellAPI.run_command_in_shell(cmd, blocking=False)
1773 return
1774
1775 gmDispatcher.send(signal = 'statustext', msg = _('No DICOM viewer found.'), beep = True)
1776 #----------------------------------------------
1778
1779 dbcfg = gmCfg.cCfgSQL()
1780 cmd = dbcfg.get2 (
1781 option = u'external.tools.acs_risk_calculator_cmd',
1782 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1783 bias = 'user'
1784 )
1785
1786 if cmd is None:
1787 gmDispatcher.send(signal = u'statustext', msg = _('ACS risk assessment calculator not configured.'), beep = True)
1788 return
1789
1790 #found, cmd = gmShellAPI.detect_external_binary(binary = viewer)
1791 #if found:
1792 gmShellAPI.run_command_in_shell(cmd, blocking = False)
1793 #----------------------------------------------
1795 dlg = gmSnellen.cSnellenCfgDlg()
1796 if dlg.ShowModal() != wx.ID_OK:
1797 return
1798
1799 frame = gmSnellen.cSnellenChart (
1800 width = dlg.vals[0],
1801 height = dlg.vals[1],
1802 alpha = dlg.vals[2],
1803 mirr = dlg.vals[3],
1804 parent = None
1805 )
1806 frame.CentreOnScreen(wx.BOTH)
1807 # self.SetTopWindow(frame)
1808 # frame.Destroy = frame.DestroyWhenApp
1809 frame.Show(True)
1810 #----------------------------------------------
1811 #----------------------------------------------
1813 webbrowser.open (
1814 url = 'http://wiki.gnumed.de/bin/view/Gnumed/MedicalContentLinks#AnchorLocaleI%s' % gmI18N.system_locale_level['language'],
1815 new = False,
1816 autoraise = True
1817 )
1818 #----------------------------------------------
1821 #----------------------------------------------
1824 #----------------------------------------------
1826 webbrowser.open (
1827 url = 'http://www.kompendium.ch',
1828 new = False,
1829 autoraise = True
1830 )
1831 #----------------------------------------------
1832 # Help / Debugging
1833 #----------------------------------------------
1837 #----------------------------------------------
1839
1840 time.sleep(0.5)
1841
1842 rect = self.GetRect()
1843
1844 # adjust for window decoration on Linux
1845 if sys.platform == 'linux2':
1846 client_x, client_y = self.ClientToScreen((0, 0))
1847 border_width = client_x - rect.x
1848 title_bar_height = client_y - rect.y
1849 # If the window has a menu bar, remove it from the title bar height.
1850 if self.GetMenuBar():
1851 title_bar_height /= 2
1852 rect.width += (border_width * 2)
1853 rect.height += title_bar_height + border_width
1854
1855 wdc = wx.ScreenDC()
1856 mdc = wx.MemoryDC()
1857 img = wx.EmptyBitmap(rect.width, rect.height)
1858 mdc.SelectObject(img)
1859 mdc.Blit ( # copy ...
1860 0, 0, # ... to here in the target ...
1861 rect.width, rect.height, # ... that much from ...
1862 wdc, # ... the source ...
1863 rect.x, rect.y # ... starting here
1864 )
1865
1866 # FIXME: improve filename with patient/workplace/provider, allow user to select/change
1867 fname = os.path.expanduser(os.path.join('~', 'gnumed', 'export', 'gnumed-screenshot-%s.png')) % pyDT.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
1868 img.SaveFile(fname, wx.BITMAP_TYPE_PNG)
1869 gmDispatcher.send(signal = 'statustext', msg = _('Saved screenshot to file [%s].') % fname)
1870 #----------------------------------------------
1872 #import nonexistant_module
1873 raise ValueError('raised ValueError to test exception handling')
1874 #----------------------------------------------
1878 #----------------------------------------------
1880 webbrowser.open (
1881 url = 'https://bugs.launchpad.net/gnumed/',
1882 #url = 'http://savannah.gnu.org/bugs/?group=gnumed',
1883 new = False,
1884 autoraise = True
1885 )
1886 #----------------------------------------------
1888 webbrowser.open (
1889 url = 'http://wiki.gnumed.de',
1890 new = False,
1891 autoraise = True
1892 )
1893 #----------------------------------------------
1895 webbrowser.open (
1896 url = 'http://wiki.gnumed.de/bin/view/Gnumed/GnumedManual#UserGuideInManual',
1897 new = False,
1898 autoraise = True
1899 )
1900 #----------------------------------------------
1907 #----------------------------------------------
1909 found, cmd = gmShellAPI.detect_external_binary(binary = 'pgadmin3')
1910 if found:
1911 gmShellAPI.run_command_in_shell(cmd, blocking=False)
1912 return
1913 gmDispatcher.send(signal = 'statustext', msg = _('pgAdmin III not found.'), beep = True)
1914 #----------------------------------------------
1916 if not gmHooks.import_hook_module(reimport = True):
1917 gmDispatcher.send(signal = 'statustext', msg = _('Error reloading hook script.'))
1918 #----------------------------------------------
1921 #----------------------------------------------
1923 curr_pat = gmPerson.gmCurrentPatient()
1924 if curr_pat.locked:
1925 curr_pat.force_unlock()
1926 else:
1927 curr_pat.locked = True
1928 #----------------------------------------------
1930 from Gnumed.pycommon import gmMimeLib
1931 gmLog2.flush()
1932 gmMimeLib.call_viewer_on_file(gmLog2._logfile_name, block = False)
1933 #----------------------------------------------
1935 name = os.path.basename(gmLog2._logfile_name)
1936 name, ext = os.path.splitext(name)
1937 new_name = '%s_%s%s' % (name, pyDT.datetime.now().strftime('%Y-%m-%d_%H-%M-%S'), ext)
1938 new_path = os.path.expanduser(os.path.join('~', 'gnumed', 'logs'))
1939
1940 dlg = wx.FileDialog (
1941 parent = self,
1942 message = _("Save current log as..."),
1943 defaultDir = new_path,
1944 defaultFile = new_name,
1945 wildcard = "%s (*.log)|*.log" % _("log files"),
1946 style = wx.SAVE
1947 )
1948 choice = dlg.ShowModal()
1949 new_name = dlg.GetPath()
1950 dlg.Destroy()
1951 if choice != wx.ID_OK:
1952 return True
1953
1954 _log.warning('syncing log file for backup to [%s]', new_name)
1955 gmLog2.flush()
1956 shutil.copy2(gmLog2._logfile_name, new_name)
1957 gmDispatcher.send('statustext', msg = _('Log file backed up as [%s].') % new_name)
1958 #----------------------------------------------
1959 # GNUmed /
1960 #----------------------------------------------
1962 """This is the wx.EVT_CLOSE handler.
1963
1964 - framework still functional
1965 """
1966 _log.debug('gmTopLevelFrame.OnClose() start')
1967 self._clean_exit()
1968 self.Destroy()
1969 _log.debug('gmTopLevelFrame.OnClose() end')
1970 return True
1971 #----------------------------------------------
1973 """
1974 Export selected patient EMR to a file
1975 """
1976 gmEMRBrowser.export_emr_to_ascii(parent=self)
1977 #----------------------------------------------
1979 import Gnumed.wxpython.gmDermTool as DT
1980 frame = DT.DermToolDialog(None, -1)
1981 frame.Show(True)
1982 #----------------------------------------------
1984 pat = gmPerson.gmCurrentPatient()
1985 if not pat.connected:
1986 gmDispatcher.send(signal = 'statustext', msg = _('Cannot start new encounter. No active patient.'))
1987 return False
1988 emr = pat.get_emr()
1989 gmEMRStructWidgets.start_new_encounter(emr = emr)
1990 #----------------------------------------------
1992 pat = gmPerson.gmCurrentPatient()
1993 if not pat.connected:
1994 gmDispatcher.send(signal = 'statustext', msg = _('Cannot list encounters. No active patient.'))
1995 return False
1996 gmEMRStructWidgets.select_encounters()
1997 #----------------------------------------------
1999 pat = gmPerson.gmCurrentPatient()
2000 if not pat.connected:
2001 gmDispatcher.send(signal = 'statustext', msg = _('Cannot add health issue. No active patient.'))
2002 return False
2003 gmEMRStructWidgets.edit_health_issue(parent = self, issue = None)
2004 #----------------------------------------------
2006 pat = gmPerson.gmCurrentPatient()
2007 if not pat.connected:
2008 gmDispatcher.send(signal = 'statustext', msg = _('Cannot add medication. No active patient.'))
2009 return False
2010
2011 gmMedicationWidgets.jump_to_ifap(import_drugs = True)
2012
2013 evt.Skip()
2014 #----------------------------------------------
2016 pat = gmPerson.gmCurrentPatient()
2017 if not pat.connected:
2018 gmDispatcher.send(signal = 'statustext', msg = _('Cannot add allergy. No active patient.'))
2019 return False
2020 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent=self, id=-1)
2021 dlg.ShowModal()
2022 #----------------------------------------------
2024 pat = gmPerson.gmCurrentPatient()
2025 if not pat.connected:
2026 gmDispatcher.send(signal = 'statustext', msg = _('Cannot manage performed procedures. No active patient.'))
2027 return False
2028 gmEMRStructWidgets.manage_performed_procedures(parent = self)
2029 evt.Skip()
2030 #----------------------------------------------
2032 pat = gmPerson.gmCurrentPatient()
2033 if not pat.connected:
2034 gmDispatcher.send(signal = 'statustext', msg = _('Cannot manage hospital stays. No active patient.'))
2035 return False
2036 gmEMRStructWidgets.manage_hospital_stays(parent = self)
2037 evt.Skip()
2038 #----------------------------------------------
2040 pat = gmPerson.gmCurrentPatient()
2041 if not pat.connected:
2042 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit occupation. No active patient.'))
2043 return False
2044 gmDemographicsWidgets.edit_occupation()
2045 evt.Skip()
2046 #----------------------------------------------
2048 pat = gmPerson.gmCurrentPatient()
2049 if not pat.connected:
2050 gmDispatcher.send(signal = 'statustext', msg = _('Cannot add measurement. No active patient.'))
2051 return False
2052 gmMeasurementWidgets.edit_measurement(parent = self, measurement = None)
2053 evt.Skip()
2054 #----------------------------------------------
2056 pat = gmPerson.gmCurrentPatient()
2057 if not pat.connected:
2058 gmDispatcher.send(signal = 'statustext', msg = _('Cannot show EMR summary. No active patient.'))
2059 return False
2060
2061 emr = pat.get_emr()
2062 dlg = wx.MessageDialog (
2063 parent = self,
2064 message = emr.format_statistics(),
2065 caption = _('EMR Summary'),
2066 style = wx.OK | wx.STAY_ON_TOP
2067 )
2068 dlg.ShowModal()
2069 dlg.Destroy()
2070 return True
2071 #----------------------------------------------
2074 #----------------------------------------------
2077 #----------------------------------------------
2079 # sanity checks
2080 pat = gmPerson.gmCurrentPatient()
2081 if not pat.connected:
2082 gmDispatcher.send(signal = 'statustext', msg = _('Cannot export EMR journal. No active patient.'))
2083 return False
2084 # get file name
2085 aWildcard = "%s (*.txt)|*.txt|%s (*)|*" % (_("text files"), _("all files"))
2086 # FIXME: make configurable
2087 aDefDir = os.path.expanduser(os.path.join('~', 'gnumed', 'export', 'EMR', pat['dirname']))
2088 gmTools.mkdir(aDefDir)
2089 # FIXME: make configurable
2090 fname = '%s-%s_%s.txt' % (_('emr-journal'), pat['lastnames'], pat['firstnames'])
2091 dlg = wx.FileDialog (
2092 parent = self,
2093 message = _("Save patient's EMR journal as..."),
2094 defaultDir = aDefDir,
2095 defaultFile = fname,
2096 wildcard = aWildcard,
2097 style = wx.SAVE
2098 )
2099 choice = dlg.ShowModal()
2100 fname = dlg.GetPath()
2101 dlg.Destroy()
2102 if choice != wx.ID_OK:
2103 return True
2104
2105 _log.debug('exporting EMR journal to [%s]' % fname)
2106 # instantiate exporter
2107 exporter = gmPatientExporter.cEMRJournalExporter()
2108
2109 wx.BeginBusyCursor()
2110 try:
2111 fname = exporter.export_to_file(filename = fname)
2112 except:
2113 wx.EndBusyCursor()
2114 gmGuiHelpers.gm_show_error (
2115 _('Error exporting patient EMR as chronological journal.'),
2116 _('EMR journal export')
2117 )
2118 raise
2119 wx.EndBusyCursor()
2120
2121 gmDispatcher.send(signal = 'statustext', msg = _('Successfully exported EMR as chronological journal into file [%s].') % fname, beep=False)
2122
2123 return True
2124 #----------------------------------------------
2126 gmNarrativeWidgets.export_narrative_for_medistar_import (
2127 parent = self,
2128 soap_cats = u'soap',
2129 encounter = None # IOW, the current one
2130 )
2131 #----------------------------------------------
2133 dbcfg = gmCfg.cCfgSQL()
2134 search_immediately = bool(dbcfg.get2 (
2135 option = 'patient_search.external_sources.immediately_search_if_single_source',
2136 workplace = gmSurgery.gmCurrentPractice().active_workplace,
2137 bias = 'user',
2138 default = 0
2139 ))
2140 gmPatSearchWidgets.get_person_from_external_sources(parent=self, search_immediately=search_immediately, activate_immediately=True)
2141 #----------------------------------------------
2143 curr_pat = gmPerson.gmCurrentPatient()
2144 if not curr_pat.connected:
2145 gmDispatcher.send(signal = 'statustext', msg = _('Cannot export patient as GDT. No active patient.'))
2146 return False
2147 # FIXME: configurable
2148 enc = 'cp850'
2149 fname = os.path.expanduser(os.path.join('~', 'gnumed', 'export', 'xDT', 'current-patient.gdt'))
2150 curr_pat.export_as_gdt(filename = fname, encoding = enc)
2151 gmDispatcher.send(signal = 'statustext', msg = _('Exported demographics to GDT file [%s].') % fname)
2152 #----------------------------------------------
2155 #----------------------------------------------
2156 # def __on_create_patient(self, event):
2157 # """Launch create patient wizard.
2158 # """
2159 # wiz = gmDemographicsWidgets.cNewPatientWizard(parent=self)
2160 # wiz.RunWizard(activate=True)
2161 #----------------------------------------------
2163 pat = gmPerson.gmCurrentPatient()
2164 if not pat.connected:
2165 gmDispatcher.send(signal = 'statustext', msg = _('Cannot add staff member. No active patient.'))
2166 return False
2167 dlg = gmStaffWidgets.cAddPatientAsStaffDlg(parent=self, id=-1)
2168 dlg.ShowModal()
2169 #----------------------------------------------
2171 pat = gmPerson.gmCurrentPatient()
2172 if not pat.connected:
2173 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete patient. No patient active.'))
2174 return False
2175 gmDemographicsWidgets.disable_identity(identity=pat)
2176 return True
2177 #----------------------------------------------
2180 #----------------------------------------------
2182 """Create new person and add it as staff."""
2183 #wiz = gmDemographicsWidgets.cNewPatientWizard(parent=self)
2184 #if not wiz.RunWizard(activate=True):
2185 # return False
2186 gmDemographicsWidgets.create_new_person(parent = self, activate = True)
2187 dlg = gmStaffWidgets.cAddPatientAsStaffDlg(parent=self, id=-1)
2188 dlg.ShowModal()
2189 #----------------------------------------------
2193 #----------------------------------------------
2197 #----------------------------------------------
2200 #----------------------------------------------
2203 #----------------------------------------------
2206 #----------------------------------------------
2209 #----------------------------------------------
2212 #----------------------------------------------
2215 #----------------------------------------------
2218 #----------------------------------------------
2221 #----------------------------------------------
2224 #----------------------------------------------
2227 #----------------------------------------------
2230 #----------------------------------------------
2232 """Cleanup helper.
2233
2234 - should ALWAYS be called when this program is
2235 to be terminated
2236 - ANY code that should be executed before a
2237 regular shutdown should go in here
2238 - framework still functional
2239 """
2240 _log.debug('gmTopLevelFrame._clean_exit() start')
2241
2242 # shut down backend notifications listener
2243 listener = gmBackendListener.gmBackendListener()
2244 try:
2245 listener.shutdown()
2246 except:
2247 _log.exception('cannot stop backend notifications listener thread')
2248
2249 # shutdown application scripting listener
2250 if _scripting_listener is not None:
2251 try:
2252 _scripting_listener.shutdown()
2253 except:
2254 _log.exception('cannot stop scripting listener thread')
2255
2256 # shutdown timers
2257 self.clock_update_timer.Stop()
2258 gmTimer.shutdown()
2259 gmPhraseWheel.shutdown()
2260
2261 # run synchronous pre-exit callback
2262 for call_back in self.__pre_exit_callbacks:
2263 try:
2264 call_back()
2265 except:
2266 print "*** pre-exit callback failed ***"
2267 print call_back
2268 _log.exception('callback [%s] failed', call_back)
2269
2270 # signal imminent demise to plugins
2271 gmDispatcher.send(u'application_closing')
2272
2273 # do not show status line messages anymore
2274 gmDispatcher.disconnect(self._on_set_statustext, 'statustext')
2275
2276 # remember GUI size
2277 curr_width, curr_height = self.GetClientSizeTuple()
2278 _log.info('GUI size at shutdown: [%s:%s]' % (curr_width, curr_height))
2279 dbcfg = gmCfg.cCfgSQL()
2280 dbcfg.set (
2281 option = 'main.window.width',
2282 value = curr_width,
2283 workplace = gmSurgery.gmCurrentPractice().active_workplace
2284 )
2285 dbcfg.set (
2286 option = 'main.window.height',
2287 value = curr_height,
2288 workplace = gmSurgery.gmCurrentPractice().active_workplace
2289 )
2290
2291 if _cfg.get(option = 'debug'):
2292 print '---=== GNUmed shutdown ===---'
2293 print _('You have to manually close this window to finalize shutting down GNUmed.')
2294 print _('This is so that you can inspect the console output at your leisure.')
2295 print '---=== GNUmed shutdown ===---'
2296
2297 # shutdown GUI exception handling
2298 gmExceptionHandlingWidgets.uninstall_wx_exception_handler()
2299
2300 # are we clean ?
2301 import threading
2302 _log.debug("%s active threads", threading.activeCount())
2303 for t in threading.enumerate():
2304 _log.debug('thread %s', t)
2305
2306 _log.debug('gmTopLevelFrame._clean_exit() end')
2307 #----------------------------------------------
2308 # internal API
2309 #----------------------------------------------
2311
2312 if _cfg.get(option = 'slave'):
2313 self.__title_template = u'GMdS: %%(pat)s [%%(prov)s@%%(wp)s] (%s:%s)' % (
2314 _cfg.get(option = 'slave personality'),
2315 _cfg.get(option = 'xml-rpc port')
2316 )
2317 else:
2318 self.__title_template = u'GMd: %(pat)s [%(prov)s@%(wp)s]'
2319 #----------------------------------------------
2321 """Update title of main window based on template.
2322
2323 This gives nice tooltips on iconified GNUmed instances.
2324
2325 User research indicates that in the title bar people want
2326 the date of birth, not the age, so please stick to this
2327 convention.
2328 """
2329 args = {}
2330
2331 pat = gmPerson.gmCurrentPatient()
2332 if pat.connected:
2333 # title = pat['title']
2334 # if title is None:
2335 # title = ''
2336 # else:
2337 # title = title[:4]
2338
2339 args['pat'] = u'%s %s %s (%s) #%d' % (
2340 gmTools.coalesce(pat['title'], u'', u'%.4s'),
2341 #title,
2342 pat['firstnames'],
2343 pat['lastnames'],
2344 pat.get_formatted_dob(format = '%x', encoding = gmI18N.get_encoding()),
2345 pat['pk_identity']
2346 )
2347 else:
2348 args['pat'] = _('no patient')
2349
2350 args['prov'] = u'%s%s.%s' % (
2351 gmTools.coalesce(_provider['title'], u'', u'%s '),
2352 _provider['firstnames'][:1],
2353 _provider['lastnames']
2354 )
2355
2356 args['wp'] = gmSurgery.gmCurrentPractice().active_workplace
2357
2358 self.SetTitle(self.__title_template % args)
2359 #----------------------------------------------
2360 #----------------------------------------------
2362 sb = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
2363 sb.SetStatusWidths([-1, 225])
2364 # add time and date display to the right corner of the status bar
2365 self.clock_update_timer = wx.PyTimer(self._cb_update_clock)
2366 self._cb_update_clock()
2367 # update every second
2368 self.clock_update_timer.Start(milliseconds = 1000)
2369 #----------------------------------------------
2371 """Displays date and local time in the second slot of the status bar"""
2372 t = time.localtime(time.time())
2373 st = time.strftime('%c', t).decode(gmI18N.get_encoding())
2374 self.SetStatusText(st,1)
2375 #------------------------------------------------
2377 """Lock GNUmed client against unauthorized access"""
2378 # FIXME
2379 # for i in range(1, self.nb.GetPageCount()):
2380 # self.nb.GetPage(i).Enable(False)
2381 return
2382 #----------------------------------------------
2384 """Unlock the main notebook widgets
2385 As long as we are not logged into the database backend,
2386 all pages but the 'login' page of the main notebook widget
2387 are locked; i.e. not accessible by the user
2388 """
2389 #unlock notebook pages
2390 # for i in range(1, self.nb.GetPageCount()):
2391 # self.nb.GetPage(i).Enable(True)
2392 # go straight to patient selection
2393 # self.nb.AdvanceSelection()
2394 return
2395 #-----------------------------------------------
2398 #==============================================================================
2400
2402
2403 self.__starting_up = True
2404
2405 gmExceptionHandlingWidgets.install_wx_exception_handler()
2406 gmExceptionHandlingWidgets.set_client_version(_cfg.get(option = 'client_version'))
2407
2408 _log.info('display: %s:%s' % (wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X), wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)))
2409
2410 # set this so things like "wx.StandardPaths.GetDataDir()" work as expected
2411 self.SetAppName(u'gnumed')
2412 self.SetVendorName(u'The GNUmed Development Community.')
2413 paths = gmTools.gmPaths(app_name = u'gnumed', wx = wx)
2414 paths.init_paths(wx = wx, app_name = u'gnumed')
2415
2416 if not self.__setup_prefs_file():
2417 return False
2418
2419 gmExceptionHandlingWidgets.set_sender_email(gmSurgery.gmCurrentPractice().user_email)
2420
2421 self.__guibroker = gmGuiBroker.GuiBroker()
2422 self.__setup_platform()
2423
2424 if not self.__establish_backend_connection():
2425 return False
2426
2427 if not _cfg.get(option = 'skip-update-check'):
2428 self.__check_for_updates()
2429
2430 if _cfg.get(option = 'slave'):
2431 if not self.__setup_scripting_listener():
2432 return False
2433
2434 # FIXME: load last position from backend
2435 frame = gmTopLevelFrame(None, -1, _('GNUmed client'), (640,440))
2436 frame.CentreOnScreen(wx.BOTH)
2437 self.SetTopWindow(frame)
2438 frame.Show(True)
2439
2440 if _cfg.get(option = 'debug'):
2441 self.RedirectStdio()
2442 self.SetOutputWindowAttributes(title = _('GNUmed stdout/stderr window'))
2443 # print this so people know what this window is for
2444 # and don't get suprised when it pops up later
2445 print '---=== GNUmed startup ===---'
2446 print _('redirecting STDOUT/STDERR to this log window')
2447 print '---=== GNUmed startup ===---'
2448
2449 self.__setup_user_activity_timer()
2450 self.__register_events()
2451
2452 wx.CallAfter(self._do_after_init)
2453
2454 return True
2455 #----------------------------------------------
2457 """Called internally by wxPython after EVT_CLOSE has been handled on last frame.
2458
2459 - after destroying all application windows and controls
2460 - before wx.Windows internal cleanup
2461 """
2462 _log.debug('gmApp.OnExit() start')
2463
2464 self.__shutdown_user_activity_timer()
2465
2466 if _cfg.get(option = 'debug'):
2467 self.RestoreStdio()
2468 sys.stdin = sys.__stdin__
2469 sys.stdout = sys.__stdout__
2470 sys.stderr = sys.__stderr__
2471
2472 _log.debug('gmApp.OnExit() end')
2473 #----------------------------------------------
2475 wx.Bell()
2476 wx.Bell()
2477 wx.Bell()
2478 _log.warning('unhandled event detected: QUERY_END_SESSION')
2479 _log.info('we should be saving ourselves from here')
2480 gmLog2.flush()
2481 print "unhandled event detected: QUERY_END_SESSION"
2482 #----------------------------------------------
2484 wx.Bell()
2485 wx.Bell()
2486 wx.Bell()
2487 _log.warning('unhandled event detected: END_SESSION')
2488 gmLog2.flush()
2489 print "unhandled event detected: END_SESSION"
2490 #----------------------------------------------
2492 if evt.GetActive():
2493 if self.__starting_up:
2494 gmHooks.run_hook_script(hook = u'app_activated_startup')
2495 else:
2496 gmHooks.run_hook_script(hook = u'app_activated')
2497 else:
2498 gmHooks.run_hook_script(hook = u'app_deactivated')
2499
2500 evt.Skip()
2501 #----------------------------------------------
2505 #----------------------------------------------
2507
2508 if self.user_activity_detected:
2509 self.elapsed_inactivity_slices = 0
2510 self.user_activity_detected = False
2511 self.elapsed_inactivity_slices += 1
2512 else:
2513 if self.elapsed_inactivity_slices >= self.max_user_inactivity_slices:
2514 # print "User was inactive for 30 seconds."
2515 pass
2516
2517 self.user_activity_timer.Start(oneShot = True)
2518 #----------------------------------------------
2519 # internal helpers
2520 #----------------------------------------------
2522 try:
2523 kwargs['originated_in_database']
2524 print '==> got notification from database "%s":' % kwargs['signal']
2525 except KeyError:
2526 print '==> received signal from client: "%s"' % kwargs['signal']
2527
2528 del kwargs['signal']
2529 for key in kwargs.keys():
2530 print ' [%s]: %s' % (key, kwargs[key])
2531 #----------------------------------------------
2536 #----------------------------------------------
2538 self.__starting_up = False
2539 gmClinicalRecord.set_func_ask_user(a_func = gmEMRStructWidgets.ask_for_encounter_continuation)
2540 self.__guibroker['horstspace.top_panel'].patient_selector.SetFocus()
2541 gmHooks.run_hook_script(hook = u'startup-after-GUI-init')
2542 #----------------------------------------------
2544 self.user_activity_detected = True
2545 self.elapsed_inactivity_slices = 0
2546 # FIXME: make configurable
2547 self.max_user_inactivity_slices = 15 # 15 * 2000ms == 30 seconds
2548 self.user_activity_timer = gmTimer.cTimer (
2549 callback = self._on_user_activity_timer_expired,
2550 delay = 2000 # hence a minimum of 2 and max of 3.999... seconds after which inactivity is detected
2551 )
2552 self.user_activity_timer.Start(oneShot=True)
2553 #----------------------------------------------
2555 try:
2556 self.user_activity_timer.Stop()
2557 del self.user_activity_timer
2558 except:
2559 pass
2560 #----------------------------------------------
2562 wx.EVT_QUERY_END_SESSION(self, self._on_query_end_session)
2563 wx.EVT_END_SESSION(self, self._on_end_session)
2564
2565 # You can bind your app to wx.EVT_ACTIVATE_APP which will fire when your
2566 # app gets/looses focus, or you can wx.EVT_ACTIVATE with any of your
2567 # toplevel windows and call evt.GetActive() in the handler to see whether
2568 # it is gaining or loosing focus.
2569 self.Bind(wx.EVT_ACTIVATE_APP, self._on_app_activated)
2570
2571 self.Bind(wx.EVT_MOUSE_EVENTS, self._on_user_activity)
2572 self.Bind(wx.EVT_KEY_DOWN, self._on_user_activity)
2573
2574 # if _cfg.get(option = 'debug'):
2575 # gmDispatcher.connect(receiver = self._signal_debugging_monitor)
2576 # _log.debug('connected old signal monitor')
2577 # wx.lib.pubsub.Publisher().subscribe (
2578 # listener = self._signal_debugging_monitor_pubsub,
2579 # topic = wx.lib.pubsub.getStrAllTopics()
2580 # )
2581 # _log.debug('connected wx.lib.pubsub based signal monitor for all topics: [%s]', wx.lib.pubsub.getStrAllTopics())
2582 #----------------------------------------------
2584
2585 dbcfg = gmCfg.cCfgSQL()
2586
2587 do_check = bool(dbcfg.get2 (
2588 option = u'horstspace.update.autocheck_at_startup',
2589 workplace = gmSurgery.gmCurrentPractice().active_workplace,
2590 bias = 'workplace',
2591 default = True
2592 ))
2593
2594 if not do_check:
2595 return
2596
2597 gmCfgWidgets.check_for_updates()
2598 #----------------------------------------------
2600 """Handle all the database related tasks necessary for startup."""
2601
2602 # log on
2603 override = _cfg.get(option = '--override-schema-check', source_order = [('cli', 'return')])
2604
2605 from Gnumed.wxpython import gmAuthWidgets
2606 connected = gmAuthWidgets.connect_to_database (
2607 expected_version = gmPG2.map_client_branch2required_db_version[_cfg.get(option = 'client_branch')],
2608 require_version = not override
2609 )
2610 if not connected:
2611 _log.warning("Login attempt unsuccessful. Can't run GNUmed without database connection")
2612 return False
2613
2614 # check account <-> staff member association
2615 try:
2616 global _provider
2617 _provider = gmPerson.gmCurrentProvider(provider = gmPerson.cStaff())
2618 except ValueError:
2619 account = gmPG2.get_current_user()
2620 _log.exception('DB account [%s] cannot be used as a GNUmed staff login', account)
2621 msg = _(
2622 'The database account [%s] cannot be used as a\n'
2623 'staff member login for GNUmed. There was an\n'
2624 'error retrieving staff details for it.\n\n'
2625 'Please ask your administrator for help.\n'
2626 ) % account
2627 gmGuiHelpers.gm_show_error(msg, _('Checking access permissions'))
2628 return False
2629
2630 # improve exception handler setup
2631 tmp = '%s%s %s (%s = %s)' % (
2632 gmTools.coalesce(_provider['title'], ''),
2633 _provider['firstnames'],
2634 _provider['lastnames'],
2635 _provider['short_alias'],
2636 _provider['db_user']
2637 )
2638 gmExceptionHandlingWidgets.set_staff_name(staff_name = tmp)
2639
2640 # display database banner
2641 surgery = gmSurgery.gmCurrentPractice()
2642 msg = surgery.db_logon_banner
2643 if msg.strip() != u'':
2644
2645 login = gmPG2.get_default_login()
2646 auth = u'\n%s\n\n' % (_('Database <%s> on <%s>') % (
2647 login.database,
2648 gmTools.coalesce(login.host, u'localhost')
2649 ))
2650 msg = auth + msg + u'\n\n'
2651
2652 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
2653 None,
2654 -1,
2655 caption = _('Verifying database'),
2656 question = gmTools.wrap(msg, 60, initial_indent = u' ', subsequent_indent = u' '),
2657 button_defs = [
2658 {'label': _('Connect'), 'tooltip': _('Yes, connect to this database.'), 'default': True},
2659 {'label': _('Disconnect'), 'tooltip': _('No, do not connect to this database.'), 'default': False}
2660 ]
2661 )
2662 go_on = dlg.ShowModal()
2663 dlg.Destroy()
2664 if go_on != wx.ID_YES:
2665 _log.info('user decided to not connect to this database')
2666 return False
2667
2668 # check database language settings
2669 self.__check_db_lang()
2670
2671 return True
2672 #----------------------------------------------
2674 """Setup access to a config file for storing preferences."""
2675
2676 paths = gmTools.gmPaths(app_name = u'gnumed', wx = wx)
2677
2678 candidates = []
2679 explicit_file = _cfg.get(option = '--conf-file', source_order = [('cli', 'return')])
2680 if explicit_file is not None:
2681 candidates.append(explicit_file)
2682 # provide a few fallbacks in the event the --conf-file isn't writable
2683 candidates.append(os.path.join(paths.user_config_dir, 'gnumed.conf'))
2684 candidates.append(os.path.join(paths.local_base_dir, 'gnumed.conf'))
2685 candidates.append(os.path.join(paths.working_dir, 'gnumed.conf'))
2686
2687 prefs_file = None
2688 for candidate in candidates:
2689 try:
2690 open(candidate, 'a+').close()
2691 prefs_file = candidate
2692 break
2693 except IOError:
2694 continue
2695
2696 if prefs_file is None:
2697 msg = _(
2698 'Cannot find configuration file in any of:\n'
2699 '\n'
2700 ' %s\n'
2701 'You may need to use the comand line option\n'
2702 '\n'
2703 ' --conf-file=<FILE>'
2704 ) % '\n '.join(candidates)
2705 gmGuiHelpers.gm_show_error(msg, _('Checking configuration files'))
2706 return False
2707
2708 _cfg.set_option(option = u'user_preferences_file', value = prefs_file)
2709 _log.info('user preferences file: %s', prefs_file)
2710
2711 return True
2712 #----------------------------------------------
2714
2715 from socket import error as SocketError
2716 from Gnumed.pycommon import gmScriptingListener
2717 from Gnumed.wxpython import gmMacro
2718
2719 slave_personality = gmTools.coalesce (
2720 _cfg.get (
2721 group = u'workplace',
2722 option = u'slave personality',
2723 source_order = [
2724 ('explicit', 'return'),
2725 ('workbase', 'return'),
2726 ('user', 'return'),
2727 ('system', 'return')
2728 ]
2729 ),
2730 u'gnumed-client'
2731 )
2732 _cfg.set_option(option = 'slave personality', value = slave_personality)
2733
2734 # FIXME: handle port via /var/run/
2735 port = int (
2736 gmTools.coalesce (
2737 _cfg.get (
2738 group = u'workplace',
2739 option = u'xml-rpc port',
2740 source_order = [
2741 ('explicit', 'return'),
2742 ('workbase', 'return'),
2743 ('user', 'return'),
2744 ('system', 'return')
2745 ]
2746 ),
2747 9999
2748 )
2749 )
2750 _cfg.set_option(option = 'xml-rpc port', value = port)
2751
2752 macro_executor = gmMacro.cMacroPrimitives(personality = slave_personality)
2753 global _scripting_listener
2754 try:
2755 _scripting_listener = gmScriptingListener.cScriptingListener(port = port, macro_executor = macro_executor)
2756 except SocketError, e:
2757 _log.exception('cannot start GNUmed XML-RPC server')
2758 gmGuiHelpers.gm_show_error (
2759 aMessage = (
2760 'Cannot start the GNUmed server:\n'
2761 '\n'
2762 ' [%s]'
2763 ) % e,
2764 aTitle = _('GNUmed startup')
2765 )
2766 return False
2767
2768 return True
2769 #----------------------------------------------
2771
2772 import wx.lib.colourdb
2773 wx.lib.colourdb.updateColourDB()
2774
2775 traits = self.GetTraits()
2776 try:
2777 _log.info('desktop environment: [%s]', traits.GetDesktopEnvironment())
2778 except:
2779 pass
2780
2781 if wx.Platform == '__WXMSW__':
2782 _log.info('running on MS Windows')
2783 elif wx.Platform == '__WXGTK__':
2784 _log.info('running on GTK (probably Linux)')
2785 elif wx.Platform == '__WXMAC__':
2786 _log.info('running on Mac OS')
2787 else:
2788 _log.info('running on an unknown platform (%s)' % wx.Platform)
2789 #----------------------------------------------
2791 if gmI18N.system_locale is None or gmI18N.system_locale == '':
2792 _log.warning("system locale is undefined (probably meaning 'C')")
2793 return True
2794
2795 # get current database locale
2796 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': u"select i18n.get_curr_lang() as lang"}])
2797 db_lang = rows[0]['lang']
2798
2799 if db_lang is None:
2800 _log.debug("database locale currently not set")
2801 msg = _(
2802 "There is no language selected in the database for user [%s].\n"
2803 "Your system language is currently set to [%s].\n\n"
2804 "Do you want to set the database language to '%s' ?\n\n"
2805 ) % (_provider['db_user'], gmI18N.system_locale, gmI18N.system_locale)
2806 checkbox_msg = _('Remember to ignore missing language')
2807 else:
2808 _log.debug("current database locale: [%s]" % db_lang)
2809 msg = _(
2810 "The currently selected database language ('%s') does\n"
2811 "not match the current system language ('%s').\n"
2812 "\n"
2813 "Do you want to set the database language to '%s' ?\n"
2814 ) % (db_lang, gmI18N.system_locale, gmI18N.system_locale)
2815 checkbox_msg = _('Remember to ignore language mismatch')
2816
2817 # check if we can match up system and db language somehow
2818 if db_lang == gmI18N.system_locale_level['full']:
2819 _log.debug('Database locale (%s) up to date.' % db_lang)
2820 return True
2821 if db_lang == gmI18N.system_locale_level['country']:
2822 _log.debug('Database locale (%s) matches system locale (%s) at country level.' % (db_lang, gmI18N.system_locale))
2823 return True
2824 if db_lang == gmI18N.system_locale_level['language']:
2825 _log.debug('Database locale (%s) matches system locale (%s) at language level.' % (db_lang, gmI18N.system_locale))
2826 return True
2827 # no match
2828 _log.warning('database locale [%s] does not match system locale [%s]' % (db_lang, gmI18N.system_locale))
2829
2830 # returns either None or a locale string
2831 ignored_sys_lang = _cfg.get (
2832 group = u'backend',
2833 option = u'ignored mismatching system locale',
2834 source_order = [('explicit', 'return'), ('local', 'return'), ('user', 'return'), ('system', 'return')]
2835 )
2836
2837 # are we to ignore *this* mismatch ?
2838 if gmI18N.system_locale == ignored_sys_lang:
2839 _log.info('configured to ignore system-to-database locale mismatch')
2840 return True
2841
2842 # no, so ask user
2843 dlg = gmGuiHelpers.c2ButtonQuestionDlg (
2844 None,
2845 -1,
2846 caption = _('Checking database language settings'),
2847 question = msg,
2848 button_defs = [
2849 {'label': _('Set'), 'tooltip': _('Set your database language to [%s].') % gmI18N.system_locale, 'default': True},
2850 {'label': _("Don't set"), 'tooltip': _('Do not set your database language now.'), 'default': False}
2851 ],
2852 show_checkbox = True,
2853 checkbox_msg = checkbox_msg,
2854 checkbox_tooltip = _(
2855 'Checking this will make GNUmed remember your decision\n'
2856 'until the system language is changed.\n'
2857 '\n'
2858 'You can also reactivate this inquiry by removing the\n'
2859 'corresponding "ignore" option from the configuration file\n'
2860 '\n'
2861 ' [%s]'
2862 ) % _cfg.get(option = 'user_preferences_file')
2863 )
2864 decision = dlg.ShowModal()
2865 remember_ignoring_problem = dlg._CHBOX_dont_ask_again.GetValue()
2866 dlg.Destroy()
2867
2868 if decision == wx.ID_NO:
2869 if not remember_ignoring_problem:
2870 return True
2871 _log.info('User did not want to set database locale. Ignoring mismatch next time.')
2872 gmCfg2.set_option_in_INI_file (
2873 filename = _cfg.get(option = 'user_preferences_file'),
2874 group = 'backend',
2875 option = 'ignored mismatching system locale',
2876 value = gmI18N.system_locale
2877 )
2878 return True
2879
2880 # try setting database language (only possible if translation exists)
2881 for lang in [gmI18N.system_locale_level['full'], gmI18N.system_locale_level['country'], gmI18N.system_locale_level['language']]:
2882 if len(lang) > 0:
2883 # users are getting confused, so don't show these "errors",
2884 # they really are just notices about us being nice
2885 rows, idx = gmPG2.run_rw_queries (
2886 link_obj = None,
2887 queries = [{'cmd': u'select i18n.set_curr_lang(%s)', 'args': [lang]}],
2888 return_data = True
2889 )
2890 if rows[0][0]:
2891 _log.debug("Successfully set database language to [%s]." % lang)
2892 else:
2893 _log.error('Cannot set database language to [%s].' % lang)
2894 continue
2895 return True
2896
2897 # no match found but user wanted to set language anyways, so force it
2898 _log.info('forcing database language to [%s]', gmI18N.system_locale_level['country'])
2899 gmPG2.run_rw_queries(queries = [{
2900 'cmd': u'select i18n.force_curr_lang(%s)',
2901 'args': [gmI18N.system_locale_level['country']]
2902 }])
2903
2904 return True
2905 #==============================================================================
2907 try:
2908 kwargs['originated_in_database']
2909 print '==> got notification from database "%s":' % kwargs['signal']
2910 except KeyError:
2911 print '==> received signal from client: "%s"' % kwargs['signal']
2912
2913 del kwargs['signal']
2914 for key in kwargs.keys():
2915 # careful because of possibly limited console output encoding
2916 try: print ' [%s]: %s' % (key, kwargs[key])
2917 except: print 'cannot print signal information'
2918 #------------------------------------------------------------------------------
2920 # careful because of possibly limited console output encoding
2921 try:
2922 print '==> received wx.lib.pubsub message: "%s"' % msg.topic
2923 print ' data: %s' % msg.data
2924 print msg
2925 except: print 'problem printing pubsub message information'
2926 #==============================================================================
2928
2929 if _cfg.get(option = 'debug'):
2930 gmDispatcher.connect(receiver = _signal_debugging_monitor)
2931 _log.debug('gmDispatcher signal monitor activated')
2932 wx.lib.pubsub.Publisher().subscribe (
2933 listener = _signal_debugging_monitor_pubsub,
2934 topic = wx.lib.pubsub.getStrAllTopics()
2935 )
2936 _log.debug('wx.lib.pubsub signal monitor activated')
2937
2938 # create an instance of our GNUmed main application
2939 # - do not redirect stdio (yet)
2940 # - allow signals to be delivered
2941 app = gmApp(redirect = False, clearSigInt = False)
2942 app.MainLoop()
2943 #==============================================================================
2944 # Main
2945 #==============================================================================
2946 if __name__ == '__main__':
2947
2948 from GNUmed.pycommon import gmI18N
2949 gmI18N.activate_locale()
2950 gmI18N.install_domain()
2951
2952 _log.info('Starting up as main module.')
2953 main()
2954
2955 #==============================================================================
2956 # $Log: gmGuiMain.py,v $
2957 # Revision 1.491 2010/02/07 15:14:07 ncq
2958 # - comment out some deprecated code
2959 # - root out a forgotten use of the old new-patient wizard (found by Jim)
2960 #
2961 # Revision 1.490 2010/02/06 21:06:59 ncq
2962 # - add time to status line messages
2963 #
2964 # Revision 1.489 2010/02/02 13:54:41 ncq
2965 # - tidy up master data management
2966 # - add managing diagnostic orgs
2967 #
2968 # Revision 1.488 2010/01/31 18:16:35 ncq
2969 # - access to default region/country setting
2970 #
2971 # Revision 1.487 2010/01/11 19:46:19 ncq
2972 # - cleanup
2973 #
2974 # Revision 1.486 2010/01/10 17:27:16 ncq
2975 # - check-for-updates now in cfg widgets
2976 #
2977 # Revision 1.485 2010/01/08 13:54:50 ncq
2978 # - retire old-style new-patient
2979 #
2980 # Revision 1.484 2010/01/06 14:40:51 ncq
2981 # - tie docs printing cleanup to --debug
2982 #
2983 # Revision 1.483 2010/01/01 21:21:24 ncq
2984 # - improved window title as per list
2985 # - make writing letters generic so LaTeX templates can be used, too
2986 #
2987 # Revision 1.482 2009/12/25 21:45:28 ncq
2988 # - configure meds list template
2989 # - manage form templates
2990 #
2991 # Revision 1.481 2009/12/21 15:06:45 ncq
2992 # - factor out check-for-updates
2993 # - support --skip-update-check
2994 #
2995 # Revision 1.480 2009/12/01 21:52:40 ncq
2996 # - improved menu items
2997 # - remove current medication menu item
2998 #
2999 # Revision 1.479 2009/11/28 18:29:33 ncq
3000 # - more master data management: drug brands and components thereof
3001 #
3002 # Revision 1.478 2009/11/15 01:06:49 ncq
3003 # - better start of new encounter
3004 #
3005 # Revision 1.477 2009/11/08 20:43:50 ncq
3006 # - search across all EMRs
3007 #
3008 # Revision 1.476 2009/11/06 15:18:27 ncq
3009 # - reanimate emr summary under show as ...
3010 #
3011 # Revision 1.475 2009/10/21 21:42:56 ncq
3012 # - fix faulty GUI string
3013 #
3014 # Revision 1.474 2009/10/21 08:56:40 ncq
3015 # - manage substances
3016 # - jump to drug db
3017 #
3018 # Revision 1.473 2009/10/20 10:26:50 ncq
3019 # - support drug data source configuration
3020 #
3021 # Revision 1.472 2009/09/29 13:16:03 ncq
3022 # - cleanup of code layout
3023 # - _set_ -> _configure_
3024 # - start drug data source selection
3025 #
3026 # Revision 1.471 2009/09/17 21:53:41 ncq
3027 # - start support for managing performed procedures
3028 #
3029 # Revision 1.470 2009/09/13 18:45:25 ncq
3030 # - no more get-active-encounter()
3031 #
3032 # Revision 1.469 2009/09/01 22:32:42 ncq
3033 # - use edit-health-issue
3034 #
3035 # Revision 1.468 2009/08/03 20:48:29 ncq
3036 # - cleanup
3037 #
3038 # Revision 1.467 2009/07/23 16:40:55 ncq
3039 # - patient -> person
3040 # - staff -> user
3041 # - improved database language selection: pre-select current language
3042 #
3043 # Revision 1.466 2009/07/17 09:29:14 ncq
3044 # - some cleanup
3045 # - Destroy dangling dialog from startup sequence which prevented
3046 # proper closing
3047 # - improved plugin registration with menu system
3048 #
3049 # Revision 1.465 2009/07/15 12:22:13 ncq
3050 # - improved window title if running in slave mode
3051 # - some more room for the bottom-right time display
3052 #
3053 # Revision 1.464 2009/07/09 16:47:10 ncq
3054 # - go to plugins now with active letter
3055 # - if not lang is set it returns none, not zero rows
3056 #
3057 # Revision 1.463 2009/07/02 20:53:24 ncq
3058 # - flush log during close
3059 # - slightly safer shutdown
3060 #
3061 # Revision 1.462 2009/07/01 17:16:06 ncq
3062 # - somewhat improved menu layout as per list
3063 # - use improved plugin names on loading
3064 #
3065 # Revision 1.461 2009/06/29 15:32:02 ncq
3066 # - fix typo
3067 #
3068 # Revision 1.460 2009/06/29 15:16:27 ncq
3069 # - reorder menus as per list discussion
3070 #
3071 # Revision 1.459 2009/06/20 22:36:08 ncq
3072 # - move IFAP handling to proper file
3073 # - better wording of uptodate client message
3074 # - improved menu item wording as per list discussion
3075 # - show backend details in startup welcome message
3076 #
3077 # Revision 1.458 2009/06/11 12:47:44 ncq
3078 # - be more careful and more verbose about exiting
3079 #
3080 # Revision 1.457 2009/06/11 11:08:47 ncq
3081 # - better wrapping for database welcome message
3082 #
3083 # Revision 1.456 2009/06/10 21:03:17 ncq
3084 # - add menu item for updating ATC
3085 #
3086 # Revision 1.455 2009/06/04 16:13:11 ncq
3087 # - re-adjust to dob-less person
3088 # - update LOINC
3089 # - better about database
3090 #
3091 # Revision 1.455 2009/05/28 10:55:47 ncq
3092 # - adjust to DOB less persons
3093 #
3094 # Revision 1.454 2009/05/24 16:28:46 ncq
3095 # - list (meta) test types
3096 #
3097 # Revision 1.453 2009/05/18 15:32:05 ncq
3098 # - improved stdio message
3099 #
3100 # Revision 1.452 2009/05/13 12:19:58 ncq
3101 # - make moving narrative accessible from menu
3102 # - make new style new patient entry the default
3103 #
3104 # Revision 1.451 2009/05/08 08:00:32 ncq
3105 # - set true client version in exception handling earlier
3106 #
3107 # Revision 1.450 2009/04/21 17:00:41 ncq
3108 # - give access to new new-pat EA
3109 #
3110 # Revision 1.449 2009/04/20 11:40:45 ncq
3111 # - add MI/stroke risk calculator access
3112 #
3113 # Revision 1.448 2009/04/19 22:29:15 ncq
3114 # - implement editing url for hyperlink in upper left corner of measurements grid
3115 #
3116 # Revision 1.447 2009/04/16 12:49:05 ncq
3117 # - improved pubsub monitor output
3118 #
3119 # Revision 1.446 2009/04/14 18:37:30 ncq
3120 # - set vendor name
3121 # - add message monitor for pubsub
3122 # - move signal debugging monitors up to the module level
3123 #
3124 # Revision 1.445 2009/04/13 10:54:37 ncq
3125 # - support listing encounters
3126 #
3127 # Revision 1.444 2009/04/03 09:49:55 ncq
3128 # - user level access to hospital stay handling
3129 # - pubsub based listening for statustext
3130 # - explicit phrasewheel shutdown (timers)
3131 #
3132 # Revision 1.443 2009/02/17 11:49:45 ncq
3133 # - manage workplaces under master data now
3134 #
3135 # Revision 1.442 2009/02/17 08:34:58 ncq
3136 # - save screenshot now also supports window decorations
3137 #
3138 # Revision 1.441 2009/02/05 21:10:59 ncq
3139 # - rapid plugin access
3140 #
3141 # Revision 1.440 2009/02/05 13:03:38 ncq
3142 # - cleanup
3143 #
3144 # Revision 1.439 2009/02/04 12:34:55 ncq
3145 # - cleanup frame init
3146 #
3147 # Revision 1.438 2009/01/15 11:38:44 ncq
3148 # - better logging, cleanup
3149 # - fix logic error in xml-rpc port detection
3150 # - display personality/port in window title if enslaved
3151 #
3152 # Revision 1.437 2008/12/26 16:03:36 ncq
3153 # - properly dispose of user activity timer
3154 #
3155 # Revision 1.436 2008/12/25 23:32:50 ncq
3156 # - shutdown timers as early as possible during application shutdown
3157 #
3158 # Revision 1.435 2008/12/25 16:54:56 ncq
3159 # - support unsetting DB language
3160 #
3161 # Revision 1.434 2008/12/17 21:58:23 ncq
3162 # - add merging two patients
3163 #
3164 # Revision 1.433 2008/12/09 23:31:18 ncq
3165 # - help menu: show log file
3166 #
3167 # Revision 1.432 2008/10/26 01:22:30 ncq
3168 # - factor out searching EMR for narrative
3169 #
3170 # Revision 1.431 2008/10/22 12:20:32 ncq
3171 # - version handling for client, branch and db is now handled
3172 # in gnumed.py and gmPG2.py
3173 #
3174 # Revision 1.430 2008/10/12 16:48:13 ncq
3175 # - bump version
3176 # - derive db version via gmPG2 mapping
3177 # - no more "consultation" or "foundational"
3178 # - fix setting db lang
3179 # - apply wx.CallAfter to taking screenshot
3180 # - cleanup
3181 # - set client version for exception handling
3182 #
3183 # Revision 1.429 2008/09/02 20:21:48 ncq
3184 # - menu item to announce maintenance downtime
3185 #
3186 # Revision 1.428 2008/08/31 18:02:45 ncq
3187 # - add "Menu reference" menu item
3188 #
3189 # Revision 1.427 2008/08/31 16:16:27 ncq
3190 # - comment
3191 #
3192 # Revision 1.426 2008/08/23 14:47:54 ncq
3193 # - bump RC version
3194 #
3195 # Revision 1.425 2008/08/21 13:29:18 ncq
3196 # - add pgAdmin III to debug menu
3197 #
3198 # Revision 1.424 2008/08/17 10:31:38 ncq
3199 # - add "About database"
3200 #
3201 # Revision 1.423 2008/08/15 16:02:16 ncq
3202 # - do not GDT-export w/o active patient
3203 # - manage provinces
3204 #
3205 # Revision 1.422 2008/08/08 13:31:37 ncq
3206 # - a bit of cleanup
3207 # - support pre-exit sync callbacks
3208 #
3209 # Revision 1.421 2008/08/06 13:27:16 ncq
3210 # - include system locale in list when setting db lang
3211 # - allow forcing db lang
3212 # - improve startup db lang check
3213 #
3214 # Revision 1.420 2008/08/05 16:45:12 ncq
3215 # - add wxAppTraits querying
3216 #
3217 # Revision 1.419 2008/07/28 20:41:58 ncq
3218 # - support version in about box
3219 #
3220 # Revision 1.418 2008/07/28 15:52:29 ncq
3221 # - no more initial startup plugin, do with hook if wanted
3222 # - properly set sender email in exception handler after option was modified and client startup
3223 # - factor out Medistar export
3224 #
3225 # Revision 1.417 2008/07/24 14:02:03 ncq
3226 # - some menu reorg/renaming
3227 # - invoke encounter type managment
3228 #
3229 # Revision 1.416 2008/07/16 11:12:01 ncq
3230 # - cleanup
3231 # - enable user email configuration and use it
3232 #
3233 # Revision 1.415 2008/07/15 15:24:54 ncq
3234 # - check for wxp2.8
3235 # - set current branch to 0.3
3236 #
3237 # Revision 1.414 2008/07/14 13:47:15 ncq
3238 # - some menu reorg
3239 # - do synced encounter sanity check on patient change :-)
3240 #
3241 # Revision 1.413 2008/07/13 16:10:31 ncq
3242 # - master data menu
3243 # - manage text expansions
3244 # - add_new_measurement -> edit_measurement(measurement = None)
3245 # - cleanly shutdown timers
3246 #
3247 # Revision 1.412 2008/07/10 20:52:55 ncq
3248 # - better to call path detection with app name and wx
3249 #
3250 # Revision 1.411 2008/07/07 13:43:17 ncq
3251 # - current patient .connected
3252 #
3253 # Revision 1.410 2008/06/28 22:34:46 ncq
3254 # - add option on progress notes editor handling
3255 #
3256 # Revision 1.409 2008/06/28 18:26:50 ncq
3257 # - enable temp dir configuration
3258 # - link to kompendium.ch
3259 # - some menu reorg
3260 #
3261 # Revision 1.408 2008/06/26 17:01:57 ncq
3262 # - be extra careful about returning distinct results from cfg
3263 #
3264 # Revision 1.407 2008/06/16 21:35:12 ncq
3265 # - put "add measurements" under "observations" in emr menu
3266 #
3267 # Revision 1.406 2008/06/09 15:34:57 ncq
3268 # - "add measurement" from menu
3269 #
3270 # Revision 1.405 2008/05/29 13:28:37 ncq
3271 # - improved logging of EVT(_QUERY)_END_SESSION
3272 #
3273 # Revision 1.404 2008/05/26 13:31:34 ncq
3274 # - "properly" set current branch
3275 #
3276 # Revision 1.403 2008/05/26 12:09:37 ncq
3277 # - some cleanup
3278 # - check_for_updates and call that from menu item
3279 # and startup process
3280 # - menu items for configuring update check
3281 #
3282 # Revision 1.402 2008/05/21 15:53:06 ncq
3283 # - add initial support for update notifier
3284 #
3285 # Revision 1.401 2008/05/20 16:44:44 ncq
3286 # - clean up OnInit
3287 # - start listening to user inactivity
3288 #
3289 # Revision 1.400 2008/05/19 16:24:07 ncq
3290 # - let EMR format its summary itself
3291 #
3292 # Revision 1.399 2008/05/13 14:12:55 ncq
3293 # - exc handling adjustments
3294 #
3295 # Revision 1.398 2008/04/29 18:30:42 ncq
3296 # - promote workplace logging to info
3297 #
3298 # Revision 1.397 2008/04/28 13:32:39 ncq
3299 # - take approprate action on db maintenance warning
3300 #
3301 # Revision 1.396 2008/04/26 21:36:42 ncq
3302 # - fix faulty variable
3303 # - when debugging explicitely print into log window
3304 # immediately after creation so focus isn't taken
3305 # away at a later and inconvenient time
3306 #
3307 # Revision 1.395 2008/04/16 20:39:39 ncq
3308 # - working versions of the wxGlade code and use it, too
3309 # - show client version in login dialog
3310 #
3311 # Revision 1.394 2008/04/11 12:28:30 ncq
3312 # - abort if there's no user preferences config file whatsoever
3313 #
3314 # Revision 1.393 2008/03/29 16:09:53 ncq
3315 # - improved comments
3316 # - wx version checking for faulty
3317 # - enhance color db
3318 # - make sure at least one user preferences file candidate is writable
3319 #
3320 # Revision 1.392 2008/03/09 20:16:14 ncq
3321 # - load_patient_* -> get_person_*
3322 #
3323 # Revision 1.391 2008/03/06 18:34:08 ncq
3324 # - better error handling around IFAP access
3325 #
3326 # Revision 1.390 2008/03/05 22:38:26 ncq
3327 # - set encounter type to chart review on docs-only encounters
3328 #
3329 # Revision 1.389 2008/02/29 23:46:59 ncq
3330 # - new debugging option: widget inspector (needs 2.8)
3331 #
3332 # Revision 1.388 2008/02/25 17:37:16 ncq
3333 # - use new-style logging
3334 #
3335 # Revision 1.387 2008/01/30 14:07:49 ncq
3336 # - improved wording of partless document option
3337 #
3338 # Revision 1.386 2008/01/27 21:15:20 ncq
3339 # - configure partless docs
3340 # - label changes
3341 # - use gmCfg2 for setting options
3342 #
3343 # Revision 1.385 2008/01/22 12:23:39 ncq
3344 # - reorder menus as per list discussion
3345 # - wiki link/online user manual link in help menu
3346 #
3347 # Revision 1.384 2008/01/16 19:40:22 ncq
3348 # - menu item renaming "Upper lower" per Jim
3349 # - more config options
3350 # - add Aeskulap to DICOM viewers and better detection of those
3351 #
3352 # Revision 1.383 2008/01/13 01:19:11 ncq
3353 # - don't crash on inaccessible IFAP transfer file
3354 # - doc management configuration
3355 # - restore Stdio on exit
3356 # - set staff name for exception handling
3357 #
3358 # Revision 1.382 2008/01/07 19:53:00 ncq
3359 # - misspelled variable fix
3360 #
3361 # Revision 1.381 2008/01/05 22:30:30 ncq
3362 # - some wording cleanup for menu items
3363 #
3364 # Revision 1.380 2007/12/26 22:45:46 ncq
3365 # - tuples separate by , not :
3366 #
3367 # Revision 1.379 2007/12/23 22:03:59 ncq
3368 # - no more gmCLI
3369 #
3370 # Revision 1.378 2007/12/23 20:28:44 ncq
3371 # - use gmCfg2, less gmCLI use
3372 # - cleanup
3373 # - less guibroker use
3374 #
3375 # Revision 1.377 2007/12/12 16:24:32 ncq
3376 # - cleanup
3377 #
3378 # Revision 1.376 2007/12/11 12:49:26 ncq
3379 # - explicit signal handling
3380 #
3381 # Revision 1.375 2007/12/06 10:47:14 ncq
3382 # - submenu EMR -> History Taking
3383 #
3384 # Revision 1.374 2007/12/04 18:38:04 ncq
3385 # - edit occupation via menu
3386 #
3387 # Revision 1.373 2007/12/04 16:16:27 ncq
3388 # - use gmAuthWidgets
3389 #
3390 # Revision 1.372 2007/12/04 15:20:31 ncq
3391 # - assume default slave personality "gnumed-client" if not set
3392 #
3393 # Revision 1.371 2007/12/03 21:06:00 ncq
3394 # - streamline OnInit()
3395 #
3396 # Revision 1.370 2007/11/28 22:36:40 ncq
3397 # - listen on identity/name changes for current patient
3398 #
3399 # Revision 1.369 2007/11/23 23:33:50 ncq
3400 # - can now configure workplace plugins
3401 #
3402 # Revision 1.368 2007/11/03 17:57:19 ncq
3403 # - call hook on request_user_attention and app window actication/deactivation
3404 # - call hook on client init startup
3405 # - hence no more hardcoded checking external sources on startup
3406 # as users can do it from the hook if needed, hook example
3407 # updated thusly
3408 # - hence to check-sources-on-startup configuration needed
3409 # anymore
3410 #
3411 # Revision 1.367 2007/11/02 13:59:04 ncq
3412 # - teach client about its own version
3413 # - log client/db version
3414 # - a bunch of config options
3415 # - listen to request_user_attention
3416 # - listen to APP activation/deactivation
3417 #
3418 # Revision 1.366 2007/10/25 20:11:29 ncq
3419 # - configure initial plugin after patient search
3420 #
3421 # Revision 1.365 2007/10/25 16:41:04 ncq
3422 # - a whole bunch of config options
3423 #
3424 # Revision 1.364 2007/10/25 12:20:36 ncq
3425 # - improve db origination detection for signals in signal monitor
3426 #
3427 # Revision 1.363 2007/10/23 21:41:42 ncq
3428 # - on --debug monitor signals
3429 #
3430 # Revision 1.362 2007/10/23 21:25:32 ncq
3431 # - shutdown backend notification listener on exit
3432 #
3433 # Revision 1.361 2007/10/21 20:19:26 ncq
3434 # - add more config options
3435 #
3436 # Revision 1.360 2007/10/19 21:20:17 ncq
3437 # - init *all* image handler
3438 #
3439 # Revision 1.359 2007/10/19 12:51:39 ncq
3440 # - configure/do quick external patient search
3441 # - add Snellen chart
3442 #
3443 # Revision 1.358 2007/10/11 12:10:52 ncq
3444 # - add initial updateTitle() call
3445 # - reorganize menus a bit
3446 # - add gnumed / config / emr / encounter / edit-before-patient-change
3447 # - improve logic in encounter editor showing before patient change
3448 #
3449 # Revision 1.357 2007/10/08 12:49:48 ncq
3450 # - active_workplace now property of gmPractice
3451 # - rearrange options manage
3452 # - allow editing ifap startup command
3453 #
3454 # Revision 1.356 2007/09/20 21:30:39 ncq
3455 # - cleanup
3456 # - allow setting db logon banner
3457 #
3458 # Revision 1.355 2007/09/20 19:35:14 ncq
3459 # - somewhat cleanup exit code
3460 #
3461 # Revision 1.354 2007/09/17 21:46:51 ncq
3462 # - comment out unimplemented menu item
3463 #
3464 # Revision 1.353 2007/09/10 12:35:32 ncq
3465 # - cleanup
3466 #
3467 # Revision 1.352 2007/09/04 23:29:03 ncq
3468 # - slave mode now set via --slave inside login dialog
3469 #
3470 # Revision 1.351 2007/09/03 11:03:59 ncq
3471 # - enhanced error handling testing
3472 #
3473 # Revision 1.350 2007/08/31 23:04:40 ncq
3474 # - feedback on failing to write letter w/o active patient
3475 #
3476 # Revision 1.349 2007/08/29 14:40:41 ncq
3477 # - remove "activity" part from window title - we never started using it
3478 # - add menu item for managing paperwork templates
3479 # - no more singular get_choice_from_list()
3480 # - feedback on starting new encounter
3481 #
3482 # Revision 1.348 2007/08/12 00:09:07 ncq
3483 # - no more gmSignals.py
3484 #
3485 # Revision 1.347 2007/08/07 21:42:40 ncq
3486 # - cPaths -> gmPaths
3487 #
3488 # Revision 1.346 2007/07/22 10:47:48 ncq
3489 # - fix typo
3490 #
3491 # Revision 1.345 2007/07/22 10:04:49 ncq
3492 # - only allow new letter from menu if patient active
3493 #
3494 # Revision 1.344 2007/07/22 09:25:59 ncq
3495 # - support AMIDE DICOM viewer if installed
3496 # - menu "correspondence" with item "write letter"
3497 # - adjust to new get_choice_from_list()
3498 #
3499 # Revision 1.343 2007/07/17 21:43:50 ncq
3500 # - use refcounted patient lock
3501 #
3502 # Revision 1.342 2007/07/17 15:52:57 ncq
3503 # - display proper error message when starting the XML RPC server fails
3504 #
3505 # Revision 1.341 2007/07/17 13:52:12 ncq
3506 # - fix SQL query for db welcome message
3507 #
3508 # Revision 1.340 2007/07/17 13:42:13 ncq
3509 # - make displaying welcome message optional
3510 #
3511 # Revision 1.339 2007/07/11 21:09:05 ncq
3512 # - add lock/unlock patient
3513 #
3514 # Revision 1.338 2007/07/09 12:44:06 ncq
3515 # - make office menu accessible to plugins
3516 #
3517 # Revision 1.337 2007/06/28 12:37:22 ncq
3518 # - show proper title in caption line of main window
3519 # - improved menus
3520 # - allow signals to be delivered
3521 #
3522 # Revision 1.336 2007/06/11 20:30:46 ncq
3523 # - set expected database version to "devel"
3524 #
3525 # Revision 1.335 2007/06/10 10:18:37 ncq
3526 # - fix setting database language
3527 #
3528 # Revision 1.334 2007/05/21 14:48:58 ncq
3529 # - use export/EMR/pat['dirname']
3530 #
3531 # Revision 1.333 2007/05/21 13:05:25 ncq
3532 # - catch-all wildcard on UNIX must be *, not *.*
3533 #
3534 # Revision 1.332 2007/05/18 10:14:50 ncq
3535 # - revert testing
3536 #
3537 # Revision 1.331 2007/05/18 10:14:22 ncq
3538 # - support OsiriX dicom viewer if available
3539 # - only enable dicom viewer menu item if a (known) viewer is available
3540 # (does not affect viewing from document system)
3541 #
3542 # Revision 1.330 2007/05/11 14:18:04 ncq
3543 # - put debugging stuff into submenue
3544 #
3545 # Revision 1.329 2007/05/08 16:06:03 ncq
3546 # - cleanup menu layout
3547 # - link to bug tracker on Savannah
3548 # - add exception handler test
3549 # - install/uninstall wxPython based exception display handler at appropriate times
3550 #
3551 # Revision 1.328 2007/05/08 11:15:41 ncq
3552 # - redirect stdio when debugging is enabled
3553 #
3554 # Revision 1.327 2007/05/07 12:35:20 ncq
3555 # - improve use of gmTools.cPaths()
3556 #
3557 # Revision 1.326 2007/05/07 08:04:13 ncq
3558 # - rename menu admin to office
3559 #
3560 # Revision 1.325 2007/04/27 13:29:08 ncq
3561 # - bump expected db version
3562 #
3563 # Revision 1.324 2007/04/25 22:01:25 ncq
3564 # - add database language configurator
3565 #
3566 # Revision 1.323 2007/04/19 13:12:51 ncq
3567 # - use gmTools.cPaths to use proper user prefs file
3568 #
3569 # Revision 1.322 2007/04/11 20:43:51 ncq
3570 # - cleanup
3571 #
3572 # Revision 1.321 2007/04/11 14:51:55 ncq
3573 # - use SetAppName() on App instance
3574 #
3575 # Revision 1.320 2007/04/02 18:40:58 ncq
3576 # - add menu item to start new encounter
3577 #
3578 # Revision 1.319 2007/04/01 15:28:14 ncq
3579 # - safely get_encoding()
3580 #
3581 # Revision 1.318 2007/03/26 16:09:50 ncq
3582 # - lots of statustext signal fixes
3583 #
3584 # Revision 1.317 2007/03/26 14:44:20 ncq
3585 # - eventually support flushing/backing up the log file
3586 # - add hook startup-after-GUI-init
3587 #
3588 # Revision 1.316 2007/03/23 16:42:46 ncq
3589 # - upon initial startup set focus to patient selector as requested by user ;-)
3590 #
3591 # Revision 1.315 2007/03/18 14:08:39 ncq
3592 # - add allergy handling
3593 # - disconnect statustext handler on shutdown
3594 # - run_hook_script() now in gmHooks.py
3595 #
3596 # Revision 1.314 2007/03/10 15:15:18 ncq
3597 # - anchor medical content links based on locale
3598 #
3599 # Revision 1.313 2007/03/09 16:58:13 ncq
3600 # - do not include encoding in GDT file name anymore, we now put it into the file itself
3601 #
3602 # Revision 1.312 2007/03/08 16:20:28 ncq
3603 # - typo fix
3604 #
3605 # Revision 1.311 2007/03/08 11:40:38 ncq
3606 # - setting client encoding now done directly from login function
3607 # - user preferences file now gnumed.conf again
3608 #
3609 # Revision 1.310 2007/03/02 15:40:42 ncq
3610 # - make ourselves a listener for gmSignals.statustext()
3611 # - decode() strftime() output to u''
3612 #
3613 # Revision 1.309 2007/02/22 17:35:22 ncq
3614 # - add export as GDT
3615 #
3616 # Revision 1.308 2007/02/19 16:14:06 ncq
3617 # - use gmGuiHelpers.run_hook_script()
3618 #
3619 # Revision 1.307 2007/02/17 14:13:11 ncq
3620 # - gmPerson.gmCurrentProvider().workplace now property
3621 #
3622 # Revision 1.306 2007/02/09 15:01:14 ncq
3623 # - show consultation editor just before patient change if
3624 # either assessment of encounter is empty or the duration is zero
3625 # - if the duration is zero, then set last_affirmed to now()
3626 #
3627 # Revision 1.305 2007/02/04 17:30:08 ncq
3628 # - need to expand ~/ appropriately
3629 #
3630 # Revision 1.304 2007/01/30 17:53:29 ncq
3631 # - improved doc string
3632 # - cleanup
3633 # - use user preferences file for saving locale mismatch ignoring
3634 #
3635 # Revision 1.303 2007/01/24 11:04:53 ncq
3636 # - use global expected_db_ver and set it to "v5"
3637 #
3638 # Revision 1.302 2007/01/20 22:04:50 ncq
3639 # - run user script after patient activation
3640 #
3641 # Revision 1.301 2007/01/17 13:39:10 ncq
3642 # - show encounter summary editor before patient change
3643 # only if actually entered any data
3644 #
3645 # Revision 1.300 2007/01/15 13:06:49 ncq
3646 # - if we can "import webbrowser" we really shouldn't "gmShellAPI.run_command_in_shell('firefox')"
3647 #
3648 # Revision 1.299 2007/01/13 22:21:58 ncq
3649 # - try capturing the title bar, too, in snapshot()
3650 #
3651 # Revision 1.298 2007/01/09 18:02:46 ncq
3652 # - add jump_to_ifap() ready for being factored out
3653 #
3654 # Revision 1.297 2007/01/09 13:00:09 ncq
3655 # - wx.CallAfter(self._do_after_init) in OnInit() so we can properly order things
3656 # to do after init: we already check external patient sources
3657 #
3658 # Revision 1.296 2007/01/04 22:52:01 ncq
3659 # - accelerator key for "health issue" in EMR menu
3660 #
3661 # Revision 1.295 2006/12/27 16:44:02 ncq
3662 # - delay looking up of external patients on startup so we don't
3663 # fail the entire application if there's an error in that code
3664 #
3665 # Revision 1.294 2006/12/25 22:54:28 ncq
3666 # - add comment on prospective DICOM viewer behaviour
3667 # - link to firefox with URL of medical content links wiki page from knowledge menu
3668 #
3669 # Revision 1.293 2006/12/23 15:25:40 ncq
3670 # - use gmShellAPI
3671 #
3672 # Revision 1.292 2006/12/21 17:54:23 ncq
3673 # - cleanup
3674 #
3675 # Revision 1.291 2006/12/21 17:19:49 ncq
3676 # - need to do *something* in setup_platform, and be it "pass"
3677 #
3678 # Revision 1.290 2006/12/21 16:53:59 ncq
3679 # - init image handlers once for good
3680 #
3681 # Revision 1.289 2006/12/21 11:04:29 ncq
3682 # - ensureMinimal() is the proper way to go about ensuring a minimum wxPython version
3683 # - only set gmPG2 module global encoding if explicitely set by config file
3684 # - use more predefined wx.ID_*s and do away with module global wx.NewId() constants
3685 # - fix standalone startup to init gmI18N
3686 #
3687 # Revision 1.288 2006/12/18 12:59:24 ncq
3688 # - properly ensure minimum wxPython version, including unicode,
3689 # should now allow for 2.7, 2.8, gtk2, mac, msw
3690 #
3691 # Revision 1.287 2006/12/17 22:20:33 ncq
3692 # - accept wxPython > 2.6
3693 #
3694 # Revision 1.286 2006/12/15 15:26:21 ncq
3695 # - cleanup
3696 #
3697 # Revision 1.285 2006/12/15 15:25:01 ncq
3698 # - delete checking of database version to gmLogin.py where it belongs
3699 #
3700 # Revision 1.284 2006/12/13 15:01:35 ncq
3701 # - on_add_medication does not work yet
3702 #
3703 # Revision 1.283 2006/12/13 15:00:38 ncq
3704 # - import datetime
3705 # - we already have _provider so no need for on-the-spot gmPerson.gmCurrentProvider()
3706 # - improve menu item labels
3707 # - make transfer file and shell command configurable for ifap call
3708 # - snapshot name includes timestamp
3709 #
3710 # Revision 1.282 2006/12/06 16:08:44 ncq
3711 # - improved __on_ifap() to display return values in message box
3712 #
3713 # Revision 1.281 2006/12/05 14:00:16 ncq
3714 # - define expected db schema version
3715 # - improve schema hash checking
3716 # - add IFAP drug db link under "Knowledge" menu
3717 #
3718 # Revision 1.280 2006/12/01 13:58:12 ncq
3719 # - add screenshot function
3720 #
3721 # Revision 1.279 2006/11/24 14:22:57 ncq
3722 # - use shiny new health issue edit area
3723 #
3724 # Revision 1.278 2006/11/24 10:01:31 ncq
3725 # - gm_beep_statustext() -> gm_statustext()
3726 #
3727 # Revision 1.277 2006/11/20 17:26:46 ncq
3728 # - missing self.
3729 #
3730 # Revision 1.276 2006/11/20 16:04:08 ncq
3731 # - translate Help menu title
3732 # - move unlock mouse to tools menu
3733 # - comment out dermatology module from tools menu as there is no maintainer
3734 #
3735 # Revision 1.275 2006/11/19 11:15:13 ncq
3736 # - cannot wx.CallAfter() __on_pre_patient_selection() since
3737 # patient would have changed underhand
3738 #
3739 # Revision 1.274 2006/11/07 00:31:23 ncq
3740 # - remove some cruft
3741 #
3742 # Revision 1.273 2006/11/06 12:53:09 ncq
3743 # - lower severity of verbose part of "incompatible database warning" message
3744 #
3745 # Revision 1.272 2006/11/05 16:04:29 ncq
3746 # - add menu item GNUmed/Unlock mouse
3747 #
3748 # Revision 1.271 2006/10/31 12:39:54 ncq
3749 # - remove traces of gmPG
3750 #
3751 # Revision 1.270 2006/10/28 13:03:58 ncq
3752 # - check patient before calling wxCallAfter() in _pre_patient_selection
3753 # - strftime() doesn't take u''
3754 #
3755 # Revision 1.269 2006/10/25 07:46:44 ncq
3756 # - Format() -> strftime() since datetime.datetime does not have .Format()
3757 #
3758 # Revision 1.268 2006/10/25 07:26:42 ncq
3759 # - make do without gmPG
3760 #
3761 # Revision 1.267 2006/10/24 13:24:12 ncq
3762 # - now use gmLogin.connect_to_database()
3763 #
3764 # Revision 1.266 2006/10/09 12:25:21 ncq
3765 # - almost entirely convert over to gmPG2
3766 # - rip out layout manager selection code
3767 # - better use of db level cfg
3768 # - default size now 800x600
3769 #
3770 # Revision 1.265 2006/08/11 13:10:08 ncq
3771 # - even if we cannot find wxversion still test for 2.6.x/unicode after
3772 # the fact and make very unhappy noises before drifting off into coma
3773 #
3774 # Revision 1.264 2006/08/06 20:04:02 ncq
3775 # - improve wxPython version checking and related messages
3776 #
3777 # Revision 1.263 2006/08/01 22:04:32 ncq
3778 # - call disable_identity()
3779 #
3780 # Revision 1.262 2006/07/30 18:47:19 ncq
3781 # - add load ext pat to patient menu
3782 # - prepare patient "deletion" from menu
3783 #
3784 # Revision 1.261 2006/07/24 11:30:02 ncq
3785 # - must set parent when loading external patients
3786 #
3787 # Revision 1.260 2006/07/21 21:34:58 ncq
3788 # - check for minimum required version/type of wxPython
3789 #
3790 # Revision 1.259 2006/07/18 21:17:21 ncq
3791 # - use gmPatSearchWidgets.load_patient_from_external_sources()
3792 #
3793 # Revision 1.258 2006/07/17 21:07:59 ncq
3794 # - create new patient from BDT file if not found
3795 #
3796 # Revision 1.257 2006/07/17 18:50:11 ncq
3797 # - upon startup activate patient read from xDT file if patient exists
3798 #
3799 # Revision 1.256 2006/07/17 10:53:50 ncq
3800 # - don't die on missing bdt file on startup
3801 #
3802 # Revision 1.255 2006/07/13 21:01:26 ncq
3803 # - display external patient on startup if XDT file available
3804 #
3805 # Revision 1.254 2006/07/07 12:09:00 ncq
3806 # - cleanup
3807 # - add document type editing to administrative menu
3808 #
3809 # Revision 1.253 2006/07/01 15:12:02 ncq
3810 # - set_curr_lang() failure has been downgraded to warning
3811 #
3812 # Revision 1.252 2006/07/01 11:32:13 ncq
3813 # - setting up database connection encoding now requires two encoding names
3814 #
3815 # Revision 1.251 2006/06/28 10:18:02 ncq
3816 # - only set gmPG default client encoding if actually set in the config file
3817 #
3818 # Revision 1.250 2006/06/13 20:35:46 ncq
3819 # - use localized date/time format taken from datetime library
3820 #
3821 # Revision 1.249 2006/06/10 05:12:42 ncq
3822 # - edit staff list
3823 #
3824 # Revision 1.248 2006/06/07 21:04:19 ncq
3825 # - fix re-setting DB lang to en_GB on failure to set preferred lang
3826 #
3827 # Revision 1.247 2006/06/06 20:48:31 ncq
3828 # - actually implement delisting staff member
3829 #
3830 # Revision 1.246 2006/06/06 10:22:23 ncq
3831 # - menu_office -> menu_administration
3832 # - menu_reference -> menu_knowledge
3833 # - cleanup
3834 #
3835 # Revision 1.245 2006/05/20 18:36:45 ncq
3836 # - reset DB language to EN on failing to set it to the user's locale
3837 #
3838 # Revision 1.244 2006/05/15 13:36:00 ncq
3839 # - signal cleanup:
3840 # - activating_patient -> pre_patient_selection
3841 # - patient_selected -> post_patient_selection
3842 #
3843 # Revision 1.243 2006/05/14 21:44:22 ncq
3844 # - add get_workplace() to gmPerson.gmCurrentProvider and make use thereof
3845 # - remove use of gmWhoAmI.py
3846 #
3847 # Revision 1.242 2006/05/14 18:09:05 ncq
3848 # - db_account -> db_user
3849 #
3850 # Revision 1.241 2006/05/12 12:20:38 ncq
3851 # - use gmCurrentProvider
3852 # - whoami -> whereami
3853 #
3854 # Revision 1.240 2006/05/10 13:08:37 ncq
3855 # - properly log physical screen size
3856 #
3857 # Revision 1.239 2006/05/06 18:50:43 ncq
3858 # - improve summary display after user complaint
3859 #
3860 # Revision 1.238 2006/05/04 17:52:04 ncq
3861 # - mark EMR summary for translation
3862 #
3863 # Revision 1.237 2006/05/04 09:49:20 ncq
3864 # - get_clinical_record() -> get_emr()
3865 # - adjust to changes in set_active_patient()
3866 # - need explicit set_active_patient() after ask_for_patient() if wanted
3867 #
3868 # Revision 1.236 2006/04/23 16:49:41 ncq
3869 # - add "Show EMR summary" as per list discussion
3870 #
3871 # Revision 1.235 2006/03/14 21:37:18 ncq
3872 # - add menu "Office"
3873 # - add menu item "add staff member" under "Office" serially calling new patient wizard and add staff dialog
3874 # - fix encounter summary
3875 #
3876 # Revision 1.234 2006/03/09 21:12:44 ncq
3877 # - allow current patient to be enlisted as staff from the main menu
3878 #
3879 # Revision 1.233 2006/02/27 22:38:36 ncq
3880 # - spell out rfe/aoe as per Richard's request
3881 #
3882 # Revision 1.232 2006/01/24 21:09:45 ncq
3883 # - use whoami.get_short_alias
3884 #
3885 # Revision 1.231 2006/01/15 14:29:44 ncq
3886 # - cleanup
3887 #
3888 # Revision 1.230 2006/01/09 20:27:04 ncq
3889 # - set_curr_lang() is in schema i18n, too
3890 #
3891 # Revision 1.229 2006/01/09 20:19:06 ncq
3892 # - adjust to i18n schema
3893 #
3894 # Revision 1.228 2006/01/03 12:12:03 ncq
3895 # - make epydoc happy re _()
3896 #
3897 # Revision 1.227 2005/12/27 18:54:50 ncq
3898 # - -> GNUmed
3899 # - enlarge About
3900 # - verify database on startup
3901 # - display database banner if it exists
3902 #
3903 # Revision 1.226 2005/12/14 17:01:51 ncq
3904 # - use improved db cfg option getting
3905 #
3906 # Revision 1.225 2005/11/29 18:59:41 ncq
3907 # - cleanup
3908 #
3909 # Revision 1.224 2005/11/27 20:20:46 ncq
3910 # - slave mode cfg return is string, not integer
3911 #
3912 # Revision 1.223 2005/11/18 15:23:23 ncq
3913 # - enable simple EMR search
3914 #
3915 # Revision 1.222 2005/11/06 11:10:42 ihaywood
3916 # dermtool proof-of-concept
3917 # Access from Tools|Dermatology menu item
3918 # A small range of derm pictures using free-as-in-speech sources are included.
3919 #
3920 # CVm: ----------------------------------------------------------------------
3921 #
3922 # Revision 1.221 2005/10/12 22:32:22 ncq
3923 # - encounter['description'] -> encounter['aoe']
3924 #
3925 # Revision 1.220 2005/10/08 12:37:25 sjtan
3926 # enc['description'] can return None
3927 #
3928 # Revision 1.219 2005/09/28 21:27:30 ncq
3929 # - a lot of wx2.6-ification
3930 #
3931 # Revision 1.218 2005/09/28 15:57:48 ncq
3932 # - a whole bunch of wx.Foo -> wx.Foo
3933 #
3934 # Revision 1.217 2005/09/27 20:44:58 ncq
3935 # - wx.wx* -> wx.*
3936 #
3937 # Revision 1.216 2005/09/26 18:01:50 ncq
3938 # - use proper way to import wx26 vs wx2.4
3939 # - note: THIS WILL BREAK RUNNING THE CLIENT IN SOME PLACES
3940 # - time for fixup
3941 #
3942 # Revision 1.215 2005/09/24 09:17:28 ncq
3943 # - some wx2.6 compatibility fixes
3944 #
3945 # Revision 1.214 2005/09/11 17:34:10 ncq
3946 # - support consultation summary generation just before
3947 # switching to the next patient
3948 #
3949 # Revision 1.213 2005/09/04 07:30:24 ncq
3950 # - comment out search-patient menu item for now
3951 #
3952 # Revision 1.212 2005/07/24 18:57:48 ncq
3953 # - add "search" to "patient" menu - all it does is focus the search box ...
3954 #
3955 # Revision 1.211 2005/07/24 11:35:59 ncq
3956 # - use robustified gmTimer.Start() interface
3957 #
3958 # Revision 1.210 2005/07/11 09:05:31 ncq
3959 # - be more careful about failing to import wxPython
3960 # - make contributors list accessible from main menu
3961 #
3962 # Revision 1.209 2005/07/02 18:21:36 ncq
3963 # - GnuMed -> GNUmed
3964 #
3965 # Revision 1.208 2005/06/30 10:21:01 cfmoro
3966 # String corrections
3967 #
3968 # Revision 1.207 2005/06/30 10:10:08 cfmoro
3969 # String corrections
3970 #
3971 # Revision 1.206 2005/06/29 20:03:45 ncq
3972 # - cleanup
3973 #
3974 # Revision 1.205 2005/06/29 18:28:33 cfmoro
3975 # Minor fix
3976 #
3977 # Revision 1.204 2005/06/29 15:08:47 ncq
3978 # - some cleanup
3979 # - allow adding past history item from EMR menu
3980 #
3981 # Revision 1.203 2005/06/28 16:48:45 cfmoro
3982 # File dialog for journal and medistar EMR export
3983 #
3984 # Revision 1.202 2005/06/23 15:00:11 ncq
3985 # - cleanup
3986 #
3987 # Revision 1.201 2005/06/21 04:59:40 rterry
3988 # Fix to allow running gmAbout.py under wxpython26 wx.Size > wx.Size
3989 #
3990 # Revision 1.200 2005/06/19 16:38:03 ncq
3991 # - set encoding of gmGuiMain.py to latin1
3992 #
3993 # Revision 1.199 2005/06/13 21:41:29 ncq
3994 # - add missing function
3995 #
3996 # Revision 1.198 2005/06/12 22:16:22 ncq
3997 # - allow for explicitely setting timezone via config file
3998 # - cleanup, prepare for EMR search
3999 #
4000 # Revision 1.197 2005/06/07 20:52:49 ncq
4001 # - improved EMR menu structure
4002 #
4003 # Revision 1.196 2005/05/24 19:50:26 ncq
4004 # - make "patient" menu available globally
4005 #
4006 # Revision 1.195 2005/05/14 14:57:37 ncq
4007 # - activate new patient after creation
4008 #
4009 # Revision 1.194 2005/05/12 15:11:08 ncq
4010 # - add Medistar export menu item
4011 #
4012 # Revision 1.193 2005/04/28 21:29:58 ncq
4013 # - improve status bar
4014 #
4015 # Revision 1.192 2005/04/26 20:02:20 ncq
4016 # - proper call cNewPatientWizard
4017 #
4018 # Revision 1.191 2005/04/17 16:30:34 ncq
4019 # - improve menu structure
4020 #
4021 # Revision 1.190 2005/04/14 08:54:48 ncq
4022 # - comment out a display logging change that just might crash Richard
4023 # - add missing wx. prefix
4024 #
4025 # Revision 1.189 2005/04/12 18:33:29 cfmoro
4026 # typo fix
4027 #
4028 # Revision 1.188 2005/04/12 10:03:20 ncq
4029 # - slightly rearrange main menu
4030 # - add journal export function
4031 # - move to wx.* use
4032 #
4033 # Revision 1.187 2005/04/10 17:12:09 cfmoro
4034 # Added create patient menu option
4035 #
4036 # Revision 1.186 2005/04/03 20:12:12 ncq
4037 # - better wording in status line
4038 # - add menu "EMR" with "export" item and use gmEMRBrowser.export_emr_to_ascii()
4039 #
4040 # Revision 1.185 2005/04/02 20:45:12 cfmoro
4041 # Implementated exporting emr from gui client
4042 #
4043 # Revision 1.184 2005/03/29 07:27:54 ncq
4044 # - just silly cleanup
4045 #
4046 # Revision 1.183 2005/03/14 14:37:19 ncq
4047 # - attempt to log display settings
4048 #
4049 # Revision 1.182 2005/03/08 16:45:55 ncq
4050 # - properly handle title
4051 #
4052 # Revision 1.181 2005/03/06 14:50:45 ncq
4053 # - 'demographic record' -> get_identity()
4054 #
4055 # Revision 1.180 2005/02/13 15:28:07 ncq
4056 # - v_basic_person.i_pk -> pk_identity
4057 #
4058 # Revision 1.179 2005/02/12 13:58:20 ncq
4059 # - v_basic_person.i_id -> i_pk
4060 #
4061 # Revision 1.178 2005/02/03 20:19:16 ncq
4062 # - get_demographic_record() -> get_identity()
4063 #
4064 # Revision 1.177 2005/02/01 10:16:07 ihaywood
4065 # refactoring of gmDemographicRecord and follow-on changes as discussed.
4066 #
4067 # gmTopPanel moves to gmHorstSpace
4068 # gmRichardSpace added -- example code at present, haven't even run it myself
4069 # (waiting on some icon .pngs from Richard)
4070 #
4071 # Revision 1.176 2005/01/31 10:37:26 ncq
4072 # - gmPatient.py -> gmPerson.py
4073 #
4074 # Revision 1.175 2004/10/01 13:17:35 ncq
4075 # - eventually do what was intended on slave_mode != 1
4076 #
4077 # Revision 1.174 2004/10/01 11:49:59 ncq
4078 # - improve message on unset database language
4079 #
4080 # Revision 1.173 2004/09/13 09:36:43 ncq
4081 # - cleanup
4082 # - --slave -> 'main.slave_mode'
4083 #
4084 # Revision 1.172 2004/09/06 22:21:08 ncq
4085 # - properly use setDBParam()
4086 # - store sidebar.width if not found
4087 #
4088 # Revision 1.171 2004/09/05 14:47:24 ncq
4089 # - fix setDBParam() calls
4090 #
4091 # Revision 1.170 2004/08/20 13:34:48 ncq
4092 # - getFirstMatchingDBSet() -> getDBParam()
4093 #
4094 # Revision 1.169 2004/08/11 08:15:06 ncq
4095 # - log debugging info on why workplace appears to be list on Richard's machine
4096 #
4097 # Revision 1.168 2004/08/09 00:03:19 ncq
4098 # - Horst space layout manager factored out into its own file
4099 #
4100 # Revision 1.167 2004/08/04 17:16:02 ncq
4101 # - wxNotebookPlugin -> cNotebookPlugin
4102 # - derive cNotebookPluginOld from cNotebookPlugin
4103 # - make cNotebookPluginOld warn on use and implement old
4104 # explicit "main.notebook.raised_plugin"/ReceiveFocus behaviour
4105 # - ReceiveFocus() -> receive_focus()
4106 #
4107 # Revision 1.166 2004/07/28 15:40:05 ncq
4108 # - log wxWidgets version
4109 #
4110 # Revision 1.165 2004/07/24 17:21:49 ncq
4111 # - some cleanup, also re from wxPython import wx
4112 # - factored out Horst space layout manager into it's own
4113 # wx.Panel child class
4114 # - subsequently renamed
4115 # 'main.notebook.plugins' -> 'horstspace.notebook.pages'
4116 # 'modules.gui' -> 'horstspace.notebook.gui' (to be renamed horstspace.notebook.plugins later)
4117 # - adapt to said changes
4118 #
4119 # Revision 1.164 2004/07/24 10:26:35 ncq
4120 # - two missing event.Skip()s added
4121 #
4122 # Revision 1.163 2004/07/19 11:50:42 ncq
4123 # - cfg: what used to be called "machine" really is "workplace", so fix
4124 #
4125 # Revision 1.162 2004/07/18 19:54:44 ncq
4126 # - improved logging for page change/veto debugging
4127 #
4128 # Revision 1.161 2004/07/18 19:49:07 ncq
4129 # - cleanup, commenting, better logging
4130 # - preparation for inner-frame notebook layout manager arrival
4131 # - use Python True, not wxWidgets true, as Python tells us to do
4132 #
4133 # Revision 1.160 2004/07/15 18:41:22 ncq
4134 # - cautiously go back to previous notebook plugin handling
4135 # avoiding to remove too much of Ian's new work
4136 # - store window size across sessions
4137 # - try a trick for veto()ing failing notebook page changes on broken platforms
4138 #
4139 # Revision 1.159 2004/07/15 14:02:43 ncq
4140 # - refactored out __set_GUI_size() from TopLevelFrame.__init__()
4141 # so cleanup will be easier
4142 # - added comment on layout managers
4143 #
4144 # Revision 1.158 2004/07/15 07:57:20 ihaywood
4145 # This adds function-key bindings to select notebook tabs
4146 # (Okay, it's a bit more than that, I've changed the interaction
4147 # between gmGuiMain and gmPlugin to be event-based.)
4148 #
4149 # Oh, and SOAPTextCtrl allows Ctrl-Enter
4150 #
4151 # Revision 1.157 2004/06/26 23:09:22 ncq
4152 # - better comments
4153 #
4154 # Revision 1.156 2004/06/25 14:39:35 ncq
4155 # - make right-click runtime load/drop of plugins work again
4156 #
4157 # Revision 1.155 2004/06/25 12:51:23 ncq
4158 # - InstPlugin() -> instantiate_plugin()
4159 #
4160 # Revision 1.154 2004/06/25 12:37:20 ncq
4161 # - eventually fix the import gmI18N issue
4162 #
4163 # Revision 1.153 2004/06/23 20:53:30 ncq
4164 # - don't break the i18n epydoc fixup, if you don't understand it then ask
4165 #
4166 # Revision 1.152 2004/06/22 07:58:47 ihaywood
4167 # minor bugfixes
4168 # let gmCfg cope with config files that are not real files
4169 #
4170 # Revision 1.151 2004/06/21 16:06:54 ncq
4171 # - fix epydoc i18n fix
4172 #
4173 # Revision 1.150 2004/06/21 14:48:26 sjtan
4174 #
4175 # restored some methods that gmContacts depends on, after they were booted
4176 # out from gmDemographicRecord with no home to go , works again ;
4177 # removed cCatFinder('occupation') instantiating in main module scope
4178 # which was a source of complaint , as it still will lazy load anyway.
4179 #
4180 # Revision 1.149 2004/06/20 16:01:05 ncq
4181 # - please epydoc more carefully
4182 #
4183 # Revision 1.148 2004/06/20 06:49:21 ihaywood
4184 # changes required due to Epydoc's OCD
4185 #
4186 # Revision 1.147 2004/06/13 22:31:48 ncq
4187 # - gb['main.toolbar'] -> gb['main.top_panel']
4188 # - self.internal_name() -> self.__class__.__name__
4189 # - remove set_widget_reference()
4190 # - cleanup
4191 # - fix lazy load in _on_patient_selected()
4192 # - fix lazy load in ReceiveFocus()
4193 # - use self._widget in self.GetWidget()
4194 # - override populate_with_data()
4195 # - use gb['main.notebook.raised_plugin']
4196 #
4197 # Revision 1.146 2004/06/01 07:59:55 ncq
4198 # - comments improved
4199 #
4200 # Revision 1.145 2004/05/15 15:51:03 sjtan
4201 #
4202 # hoping to link this to organization widget.
4203 #
4204 # Revision 1.144 2004/03/25 11:03:23 ncq
4205 # - getActiveName -> get_names
4206 #
4207 # Revision 1.143 2004/03/12 13:22:02 ncq
4208 # - fix imports
4209 #
4210 # Revision 1.142 2004/03/04 19:46:54 ncq
4211 # - switch to package based import: from Gnumed.foo import bar
4212 #
4213 # Revision 1.141 2004/03/03 23:53:22 ihaywood
4214 # GUI now supports external IDs,
4215 # Demographics GUI now ALPHA (feature-complete w.r.t. version 1.0)
4216 # but happy to consider cosmetic changes
4217 #
4218 # Revision 1.140 2004/02/18 14:00:56 ncq
4219 # - moved encounter handling to gmClinicalRecord.__init__()
4220 #
4221 # Revision 1.139 2004/02/12 23:55:34 ncq
4222 # - different title bar on --slave
4223 #
4224 # Revision 1.138 2004/02/05 23:54:11 ncq
4225 # - wxCallAfter()
4226 # - start/stop scripting listener
4227 #
4228 # Revision 1.137 2004/01/29 16:12:18 ncq
4229 # - add check for DB account to staff member mapping
4230 #
4231 # Revision 1.136 2004/01/18 21:52:20 ncq
4232 # - stop backend listeners in clean_exit()
4233 #
4234 # Revision 1.135 2004/01/06 10:05:21 ncq
4235 # - question dialog on continuing previous encounter was incorrect
4236 #
4237 # Revision 1.134 2004/01/04 09:33:32 ihaywood
4238 # minor bugfixes, can now create new patients, but doesn't update properly
4239 #
4240 # Revision 1.133 2003/12/29 23:32:56 ncq
4241 # - reverted tolerance to missing db account <-> staff member mapping
4242 # - added comment as to why
4243 #
4244 # Revision 1.132 2003/12/29 20:44:16 uid67323
4245 # -fixed the bug that made gnumed crash if no staff entry was available for the current user
4246 #
4247 # Revision 1.131 2003/12/29 16:56:00 uid66147
4248 # - current user now handled by whoami
4249 # - updateTitle() has only one parameter left: anActivity, the others can be derived
4250 #
4251 # Revision 1.130 2003/11/30 01:09:10 ncq
4252 # - use gmGuiHelpers
4253 #
4254 # Revision 1.129 2003/11/29 01:33:23 ncq
4255 # - a bit of streamlining
4256 #
4257 # Revision 1.128 2003/11/21 19:55:32 hinnef
4258 # re-included patch from 1.116 that was lost before
4259 #
4260 # Revision 1.127 2003/11/19 14:45:32 ncq
4261 # - re-decrease excess logging on plugin load failure which
4262 # got dropped in Syans recent commit
4263 #
4264 # Revision 1.126 2003/11/19 01:22:24 ncq
4265 # - some cleanup, some local vars renamed
4266 #
4267 # Revision 1.125 2003/11/19 01:01:17 shilbert
4268 # - fix for new demographic API got lost
4269 #
4270 # Revision 1.124 2003/11/17 10:56:38 sjtan
4271 #
4272 # synced and commiting.
4273 #
4274 # Revision 1.123 2003/11/11 18:22:18 ncq
4275 # - fix longstanding bug in plugin loader error handler (duh !)
4276 #
4277 # Revision 1.122 2003/11/09 17:37:12 shilbert
4278 # - ['demographics'] -> ['demographic record']
4279 #
4280 # Revision 1.121 2003/10/31 23:23:17 ncq
4281 # - make "attach to encounter ?" dialog more informative
4282 #
4283 # Revision 1.120 2003/10/27 15:53:10 ncq
4284 # - getDOB has changed
4285 #
4286 # Revision 1.119 2003/10/26 17:39:00 ncq
4287 # - cleanup
4288 #
4289 # Revision 1.118 2003/10/26 11:27:10 ihaywood
4290 # gmPatient is now the "patient stub", all demographics stuff in gmDemographics.
4291 #
4292 # syncing with main tree.
4293 #
4294 # Revision 1.1 2003/10/23 06:02:39 sjtan
4295 #
4296 # manual edit areas modelled after r.terry's specs.
4297 #
4298 # Revision 1.116 2003/10/22 21:34:42 hinnef
4299 # -changed string array for main.window.size into two separate integer parameters
4300 #
4301 # Revision 1.115 2003/10/19 12:17:16 ncq
4302 # - just cleanup
4303 #
4304 # Revision 1.114 2003/10/13 21:00:29 hinnef
4305 # -added main.window.size config parameter (will be set on startup)
4306 #
4307 # Revision 1.113 2003/09/03 17:32:41 hinnef
4308 # make use of gmWhoAmI
4309 #
4310 # Revision 1.112 2003/07/21 21:05:56 ncq
4311 # - actually set database client encoding from config file, warn if missing
4312 #
4313 # Revision 1.111 2003/07/07 08:34:31 ihaywood
4314 # bugfixes on gmdrugs.sql for postgres 7.3
4315 #
4316 # Revision 1.110 2003/06/26 22:28:50 ncq
4317 # - need to define self.nb before using it
4318 # - reordered __init__ for clarity
4319 #
4320 # Revision 1.109 2003/06/26 21:38:28 ncq
4321 # - fatal->verbose
4322 # - ignore system-to-database locale mismatch if user so desires
4323 #
4324 # Revision 1.108 2003/06/25 22:50:30 ncq
4325 # - large cleanup
4326 # - lots of comments re method call order on application closing
4327 # - send application_closing() from _clean_exit()
4328 # - add OnExit() handler, catch/log session management events
4329 # - add helper __show_question()
4330 #
4331 # Revision 1.107 2003/06/24 12:55:40 ncq
4332 # - typo: it's qUestion, not qestion
4333 #
4334 # Revision 1.106 2003/06/23 22:29:59 ncq
4335 # - in on_patient_selected() add code to attach to a
4336 # previous encounter or create one if necessary
4337 # - show_error/quesion() helper
4338 #
4339 # Revision 1.105 2003/06/19 15:27:53 ncq
4340 # - also process wx.EVT_NOTEBOOK_PAGE_CHANGING
4341 # - veto() page change if can_receive_focus() is false
4342 #
4343 # Revision 1.104 2003/06/17 22:30:41 ncq
4344 # - some cleanup
4345 #
4346 # Revision 1.103 2003/06/10 09:55:34 ncq
4347 # - don't import handler_loader anymore
4348 #
4349 # Revision 1.102 2003/06/01 14:34:47 sjtan
4350 #
4351 # hopefully complies with temporary model; not using setData now ( but that did work).
4352 # Please leave a working and tested substitute (i.e. select a patient , allergy list
4353 # will change; check allergy panel allows update of allergy list), if still
4354 # not satisfied. I need a working model-view connection ; trying to get at least
4355 # a basically database updating version going .
4356 #
4357 # Revision 1.101 2003/06/01 12:36:40 ncq
4358 # - no way cluttering INFO level log files with arbitrary patient data
4359 #
4360 # Revision 1.100 2003/06/01 01:47:33 sjtan
4361 #
4362 # starting allergy connections.
4363 #
4364 # Revision 1.99 2003/05/12 09:13:31 ncq
4365 # - SQL ends with ";", cleanup
4366 #
4367 # Revision 1.98 2003/05/10 18:47:08 hinnef
4368 # - set 'currentUser' in GuiBroker-dict
4369 #
4370 # Revision 1.97 2003/05/03 14:16:33 ncq
4371 # - we don't use OnIdle(), so don't hook it
4372 #
4373 # Revision 1.96 2003/04/28 12:04:09 ncq
4374 # - use plugin.internal_name()
4375 #
4376 # Revision 1.95 2003/04/25 13:03:07 ncq
4377 # - just some silly whitespace fix
4378 #
4379 # Revision 1.94 2003/04/08 21:24:14 ncq
4380 # - renamed gmGP_Toolbar -> gmTopPanel
4381 #
4382 # Revision 1.93 2003/04/04 20:43:47 ncq
4383 # - take advantage of gmCurrentPatient()
4384 #
4385 # Revision 1.92 2003/04/03 13:50:21 ncq
4386 # - catch more early results of connection failures ...
4387 #
4388 # Revision 1.91 2003/04/01 15:55:24 ncq
4389 # - fix setting of db lang, better message if no lang set yet
4390 #
4391 # Revision 1.90 2003/04/01 12:26:04 ncq
4392 # - add menu "Reference"
4393 #
4394 # Revision 1.89 2003/03/30 00:24:00 ncq
4395 # - typos
4396 # - (hopefully) less confusing printk()s at startup
4397 #
4398 # Revision 1.88 2003/03/29 14:12:35 ncq
4399 # - set minimum size to 320x240
4400 #
4401 # Revision 1.87 2003/03/29 13:48:42 ncq
4402 # - cleanup, clarify, improve sizer use
4403 #
4404 # Revision 1.86 2003/03/24 17:15:05 ncq
4405 # - slightly speed up startup by using pre-calculated system_locale_level dict
4406 #
4407 # Revision 1.85 2003/03/23 11:46:14 ncq
4408 # - remove extra debugging statements
4409 #
4410 # Revision 1.84 2003/02/17 16:20:38 ncq
4411 # - streamline imports
4412 # - comment out app_init signal dispatch since it breaks
4413 #
4414 # Revision 1.83 2003/02/14 00:05:36 sjtan
4415 #
4416 # generated files more usable.
4417 #
4418 # Revision 1.82 2003/02/13 08:21:18 ihaywood
4419 # bugfix for MSW
4420 #
4421 # Revision 1.81 2003/02/12 23:45:49 sjtan
4422 #
4423 # removing dead code.
4424 #
4425 # Revision 1.80 2003/02/12 23:37:58 sjtan
4426 #
4427 # now using gmDispatcher and gmSignals for initialization and cleanup.
4428 # Comment out the import handler_loader in gmGuiMain will restore back
4429 # to prototype GUI stage.
4430 #
4431 # Revision 1.79 2003/02/11 12:21:19 sjtan
4432 #
4433 # one more dependency formed , at closing , to implement saving of persistence objects.
4434 # this should be temporary, if a periodic save mechanism is implemented
4435 #
4436 # Revision 1.78 2003/02/09 20:02:55 ncq
4437 # - rename main.notebook.numbers to main.notebook.plugins
4438 #
4439 # Revision 1.77 2003/02/09 12:44:43 ncq
4440 # - fixed my typo
4441 #
4442 # Revision 1.76 2003/02/09 09:47:38 sjtan
4443 #
4444 # handler loading placed here.
4445 #
4446 # Revision 1.75 2003/02/09 09:05:30 michaelb
4447 # renamed 'icon_gui_main' to 'icon_serpent', added icon to loading-plugins-progress-dialog box
4448 #
4449 # Revision 1.74 2003/02/07 22:57:59 ncq
4450 # - fixed extra (% cmd)
4451 #
4452 # Revision 1.73 2003/02/07 14:30:33 ncq
4453 # - setting the db language now works
4454 #
4455 # Revision 1.72 2003/02/07 08:57:39 ncq
4456 # - fixed type
4457 #
4458 # Revision 1.71 2003/02/07 08:37:13 ncq
4459 # - fixed some fallout from SJT's work
4460 # - don't die if select lang from i18n_curr_lang returns None
4461 #
4462 # Revision 1.70 2003/02/07 05:13:59 sjtan
4463 #
4464 # took out the myLog temporary so not broken when I'm running to see if hooks work.
4465 #
4466 # Revision 1.69 2003/02/06 14:02:47 ncq
4467 # - some more logging to catch the set_db_lang problem
4468 #
4469 # Revision 1.68 2003/02/06 12:44:06 ncq
4470 # - curr_locale -> system_locale
4471 #
4472 # Revision 1.67 2003/02/05 12:15:01 ncq
4473 # - not auto-sets the database level language if so desired and possible
4474 #
4475 # Revision 1.66 2003/02/02 09:11:19 ihaywood
4476 # gmDemographics will connect, search and emit patient_selected
4477 #
4478 # Revision 1.65 2003/02/01 21:59:42 michaelb
4479 # moved 'About GnuMed' into module; gmGuiMain version no longer displayed in about box
4480 #
4481 # Revision 1.64 2003/02/01 11:57:56 ncq
4482 # - display gmGuiMain version in About box
4483 #
4484 # Revision 1.63 2003/02/01 07:10:50 michaelb
4485 # fixed scrolling problem
4486 #
4487 # Revision 1.61 2003/01/29 04:26:37 michaelb
4488 # removed import images_gnuMedGP_TabbedLists.py
4489 #
4490 # Revision 1.60 2003/01/14 19:36:04 ncq
4491 # - frame.Maximize() works on Windows ONLY
4492 #
4493 # Revision 1.59 2003/01/14 09:10:19 ncq
4494 # - maybe icons work better now ?
4495 #
4496 # Revision 1.58 2003/01/13 06:30:16 michaelb
4497 # the serpent window-icon was added
4498 #
4499 # Revision 1.57 2003/01/12 17:31:10 ncq
4500 # - catch failing plugins better
4501 #
4502 # Revision 1.56 2003/01/12 01:46:57 ncq
4503 # - coding style cleanup
4504 #
4505 # Revision 1.55 2003/01/11 22:03:30 hinnef
4506 # removed gmConf
4507 #
4508 # Revision 1.54 2003/01/05 10:03:30 ncq
4509 # - code cleanup
4510 # - use new plugin config storage infrastructure
4511 #
4512 # Revision 1.53 2003/01/04 07:43:55 ihaywood
4513 # Popup menus on notebook tabs
4514 #
4515 # Revision 1.52 2002/12/26 15:50:39 ncq
4516 # - title bar fine-tuning
4517 #
4518 # Revision 1.51 2002/11/30 11:09:55 ncq
4519 # - refined title bar
4520 # - comments
4521 #
4522 # Revision 1.50 2002/11/13 10:07:25 ncq
4523 # - export updateTitle() via guibroker
4524 # - internally set title according to template
4525 #
4526 # Revision 1.49 2002/11/12 21:24:51 hherb
4527 # started to use dispatcher signals
4528 #
4529 # Revision 1.48 2002/11/09 18:14:38 hherb
4530 # Errors / delay caused by loading plugin progess bar fixed
4531 #
4532 # Revision 1.47 2002/09/30 10:57:56 ncq
4533 # - make GnuMed consistent spelling in user-visible strings
4534 #
4535 # Revision 1.46 2002/09/26 13:24:15 ncq
4536 # - log version
4537 #
4538 # Revision 1.45 2002/09/12 23:21:38 ncq
4539 # - fix progress bar
4540 #
4541 # Revision 1.44 2002/09/10 12:25:33 ncq
4542 # - gimmicks rule :-)
4543 # - display plugin_nr/nr_of_plugins on load in progress bar
4544 #
4545 # Revision 1.43 2002/09/10 10:26:03 ncq
4546 # - properly i18n() strings
4547 #
4548 # Revision 1.42 2002/09/10 09:08:49 ncq
4549 # - set a useful window title and add a comment regarding this item
4550 #
4551 # Revision 1.41 2002/09/09 10:07:48 ncq
4552 # - long initial string so module names fit into progress bar display
4553 #
4554 # Revision 1.40 2002/09/09 00:52:55 ncq
4555 # - show progress bar on plugin load :-)
4556 #
4557 # Revision 1.39 2002/09/08 23:17:37 ncq
4558 # - removed obsolete reference to gmLogFrame.py
4559 #
4560 # @change log:
4561 # 10.06.2001 hherb initial implementation, untested
4562 # 01.11.2001 hherb comments added, modified for distributed servers
4563 # make no mistake: this module is still completely useless!
4564
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Tue Feb 9 04:01:19 2010 | http://epydoc.sourceforge.net |