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

Source Code for Module Gnumed.wxpython.gmGuiMain

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