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