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