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

Source Code for Module Gnumed.wxpython.gmAuthWidgets

   1  """GNUmed authentication widgets. 
   2   
   3  This module contains widgets and GUI 
   4  functions for authenticating users. 
   5  """ 
   6  #================================================================ 
   7  # $Source: /cvsroot/gnumed/gnumed/gnumed/client/wxpython/gmAuthWidgets.py,v $ 
   8  # $Id: gmAuthWidgets.py,v 1.45 2009/11/06 15:16:21 ncq Exp $ 
   9  __version__ = "$Revision: 1.45 $" 
  10  __author__ = "karsten.hilbert@gmx.net, H.Herb, H.Berger, R.Terry" 
  11  __license__ = "GPL (details at http://www.gnu.org)" 
  12   
  13   
  14  # stdlib 
  15  import sys, os.path, cPickle, zlib, logging 
  16   
  17   
  18  # 3rd party 
  19  import wx 
  20   
  21   
  22  # GNUmed 
  23  if __name__ == '__main__': 
  24          sys.path.insert(0, '../../') 
  25  from Gnumed.pycommon import gmLoginInfo, gmPG2, gmBackendListener, gmTools, gmCfg2, gmI18N 
  26  from Gnumed.business import gmSurgery 
  27  from Gnumed.wxpython import gmGuiHelpers, gmExceptionHandlingWidgets 
  28   
  29   
  30  _log = logging.getLogger('gm.ui') 
  31  _log.info(__version__) 
  32  _cfg = gmCfg2.gmCfgData() 
  33   
  34  try: 
  35          _('dummy-no-need-to-translate-but-make-epydoc-happy') 
  36  except NameError: 
  37          _ = lambda x:x 
  38   
  39   
  40  msg_generic = _(""" 
  41  GNUmed database version mismatch. 
  42   
  43  This database version cannot be used with this client: 
  44   
  45   client version: %s 
  46   database version detected: %s 
  47   database version needed: %s 
  48   
  49  Currently connected to database: 
  50   
  51   host: %s 
  52   database: %s 
  53   user: %s 
  54  """) 
  55   
  56  msg_time_skew_fail = _("""\ 
  57  The server and client clocks are off 
  58  by more than %s minutes ! 
  59   
  60  You must fix the time settings before 
  61  you can use this database with this 
  62  client. 
  63   
  64  You may have to contact your 
  65  administrator for help.""") 
  66   
  67  msg_time_skew_warn = _("""\ 
  68  The server and client clocks are off 
  69  by more than %s minutes ! 
  70   
  71  You should fix the time settings. 
  72  Otherwise clinical data may appear to 
  73  have been entered at the wrong time. 
  74   
  75  You may have to contact your 
  76  administrator for help.""") 
  77   
  78  msg_insanity = _(""" 
  79  There is a serious problem with the database settings: 
  80   
  81  %s 
  82   
  83  You may have to contact your administrator for help.""") 
  84   
  85  msg_fail = _(""" 
  86  You must connect to a different database in order 
  87  to use the GNUmed client. You may have to contact 
  88  your administrator for help.""") 
  89   
  90  msg_override = _(""" 
  91  The client will, however, continue to start up because 
  92  you are running a development/test version of GNUmed. 
  93   
  94  There may be schema related errors. Please report and/or 
  95  fix them. Do not rely on this database to work properly 
  96  in all cases !""") 
  97   
  98  #================================================================ 
  99  # convenience functions 
 100  #---------------------------------------------------------------- 
101 -def connect_to_database(max_attempts=3, expected_version=None, require_version=True):
102 """Display the login dialog and try to log into the backend. 103 104 - up to max_attempts times 105 - returns True/False 106 """ 107 # force programmer to set a valid expected_version 108 expected_hash = gmPG2.known_schema_hashes[expected_version] 109 client_version = _cfg.get(option = u'client_version') 110 global current_db_name 111 current_db_name = u'gnumed_%s' % expected_version 112 113 attempt = 0 114 115 dlg = cLoginDialog(None, -1, client_version = client_version) 116 dlg.Centre(wx.BOTH) 117 118 while attempt < max_attempts: 119 120 _log.debug('login attempt %s of %s', (attempt+1), max_attempts) 121 122 connected = False 123 124 dlg.ShowModal() 125 login = dlg.panel.GetLoginInfo() 126 if login is None: 127 _log.info("user cancelled login dialog") 128 break 129 130 # try getting a connection to verify the DSN works 131 dsn = gmPG2.make_psycopg2_dsn ( 132 database = login.database, 133 host = login.host, 134 port = login.port, 135 user = login.user, 136 password = login.password 137 ) 138 try: 139 conn = gmPG2.get_raw_connection(dsn = dsn, verbose = True, readonly = True) 140 connected = True 141 142 except gmPG2.cAuthenticationError, e: 143 attempt += 1 144 _log.error(u"login attempt failed: %s", e) 145 if attempt < max_attempts: 146 gmGuiHelpers.gm_show_error (_( 147 "Unable to connect to database:\n\n" 148 "%s\n\n" 149 "Please retry with proper credentials or cancel.\n" 150 "\n" 151 'You may also need to check the PostgreSQL client\n' 152 'authentication configuration in pg_hba.conf. For\n' 153 'details see:\n' 154 '\n' 155 'wiki.gnumed.de/bin/view/Gnumed/ConfigurePostgreSQL' 156 ) % e, 157 _('Connecting to backend') 158 ) 159 del e 160 continue 161 162 except gmPG2.dbapi.OperationalError, e: 163 _log.error(u"login attempt failed: %s", e) 164 gmGuiHelpers.gm_show_error (_( 165 "Unable to connect to database:\n\n" 166 "%s\n\n" 167 "Please retry another backend / user / password combination !\n" 168 ) % gmPG2.extract_msg_from_pg_exception(e), 169 _('Connecting to backend') 170 ) 171 del e 172 continue 173 174 # connect was successful 175 gmPG2.set_default_login(login = login) 176 gmPG2.set_default_client_encoding(encoding = dlg.panel.backend_profile.encoding) 177 178 compatible = gmPG2.database_schema_compatible(version = expected_version) 179 if compatible or not require_version: 180 dlg.panel.save_state() 181 182 if not compatible: 183 connected_db_version = gmPG2.get_schema_version() 184 msg = msg_generic % ( 185 client_version, 186 connected_db_version, 187 expected_version, 188 gmTools.coalesce(login.host, '<localhost>'), 189 login.database, 190 login.user 191 ) 192 if require_version: 193 gmGuiHelpers.gm_show_error(msg + msg_fail, _('Verifying database version')) 194 continue 195 gmGuiHelpers.gm_show_info(msg + msg_override, _('Verifying database version')) 196 197 # FIXME: make configurable 198 max_skew = 1 # minutes 199 if _cfg.get(option = 'debug'): 200 max_skew = 10 201 if not gmPG2.sanity_check_time_skew(tolerance = (max_skew * 60)): 202 if _cfg.get(option = 'debug'): 203 gmGuiHelpers.gm_show_warning(msg_time_skew_warn % max_skew, _('Verifying database settings')) 204 else: 205 gmGuiHelpers.gm_show_error(msg_time_skew_fail % max_skew, _('Verifying database settings')) 206 continue 207 208 sanity_level, message = gmPG2.sanity_check_database_settings() 209 if sanity_level != 0: 210 gmGuiHelpers.gm_show_error((msg_insanity % message), _('Verifying database settings')) 211 if sanity_level == 2: 212 continue 213 214 gmExceptionHandlingWidgets.set_is_public_database(login.public_db) 215 gmExceptionHandlingWidgets.set_helpdesk(login.helpdesk) 216 217 listener = gmBackendListener.gmBackendListener(conn = conn) 218 break 219 220 dlg.Destroy() 221 222 return connected
223 #================================================================
224 -def get_dbowner_connection(procedure=None, dbo_password=None):
225 if procedure is None: 226 procedure = _('<restricted procedure>') 227 228 # 1) get password for gm-dbo 229 if dbo_password is None: 230 pwd_gm_dbo = wx.GetPasswordFromUser ( 231 message = _(""" 232 [%s] 233 234 This is a restricted procedure. We need the 235 password for the GNUmed database owner. 236 237 Please enter the password for <gm-dbo>:""") % procedure, 238 caption = procedure 239 ) 240 if pwd_gm_dbo == '': 241 return None 242 else: 243 pwd_gm_dbo = dbo_password 244 245 # 2) connect as gm-dbo 246 login = gmPG2.get_default_login() 247 dsn = gmPG2.make_psycopg2_dsn(database=login.database, host=login.host, port=login.port, user='gm-dbo', password=pwd_gm_dbo) 248 try: 249 conn = gmPG2.get_connection(dsn=dsn, readonly=False, verbose=True, pooled=False) 250 except: 251 _log.exception('cannot connect') 252 gmGuiHelpers.gm_show_error ( 253 aMessage = _('Cannot connect as the GNUmed database owner <gm-dbo>.'), 254 aTitle = procedure 255 ) 256 return None 257 258 return conn
259 #================================================================
260 -class cBackendProfile:
261 pass
262 #================================================================
263 -class cLoginDialog(wx.Dialog):
264 """cLoginDialog - window holding cLoginPanel""" 265 266 icon_serpent='x\xdae\x8f\xb1\x0e\x83 \x10\x86w\x9f\xe2\x92\x1blb\xf2\x07\x96\xeaH:0\xd6\ 267 \xc1\x85\xd5\x98N5\xa5\xef?\xf5N\xd0\x8a\xdcA\xc2\xf7qw\x84\xdb\xfa\xb5\xcd\ 268 \xd4\xda;\xc9\x1a\xc8\xb6\xcd<\xb5\xa0\x85\x1e\xeb\xbc\xbc7b!\xf6\xdeHl\x1c\ 269 \x94\x073\xec<*\xf7\xbe\xf7\x99\x9d\xb21~\xe7.\xf5\x1f\x1c\xd3\xbdVlL\xc2\ 270 \xcf\xf8ye\xd0\x00\x90\x0etH \x84\x80B\xaa\x8a\x88\x85\xc4(U\x9d$\xfeR;\xc5J\ 271 \xa6\x01\xbbt9\xceR\xc8\x81e_$\x98\xb9\x9c\xa9\x8d,y\xa9t\xc8\xcf\x152\xe0x\ 272 \xe9$\xf5\x07\x95\x0cD\x95t:\xb1\x92\xae\x9cI\xa8~\x84\x1f\xe0\xa3ec' 273
274 - def __init__(self, parent, id, title=_("Welcome to the"), client_version=u'*** unknown ***'):
275 wx.Dialog.__init__(self, parent, id, title) 276 self.panel = cLoginPanel(self, -1, isDialog=1, client_version = client_version) 277 self.Fit() # needed for Windoze. 278 self.Centre() 279 280 # set window icon 281 icon_bmp_data = wx.BitmapFromXPMData(cPickle.loads(zlib.decompress(self.icon_serpent))) 282 icon = wx.EmptyIcon() 283 icon.CopyFromBitmap(icon_bmp_data) 284 self.SetIcon(icon)
285 #================================================================
286 -class cLoginPanel(wx.Panel):
287 """GUI panel class that interactively gets Postgres login parameters. 288 289 It features combo boxes which "remember" any number of 290 previously entered settings. 291 """
292 - def __init__(self, parent, id, 293 pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.TAB_TRAVERSAL, 294 isDialog = 0, client_version = u'*** unknown ***'):
295 """Create login panel. 296 297 isDialog: if this panel is the main panel of a dialog, the panel will 298 resize the dialog automatically to display everything neatly 299 if isDialog is set to True 300 """ 301 wx.Panel.__init__(self, parent, id, pos, size, style) 302 self.parent = parent 303 304 #True if dialog was cancelled by user 305 #if the dialog is closed manually, login should be cancelled 306 self.cancelled = True 307 308 # True if this panel is displayed within a dialog (will resize the dialog automatically then) 309 self.isDialog = isDialog 310 311 self.topsizer = wx.BoxSizer(wx.VERTICAL) 312 313 # find bitmap 314 paths = gmTools.gmPaths(app_name = u'gnumed', wx = wx) 315 bitmap = os.path.join(paths.system_app_data_dir, 'bitmaps', 'gnumedlogo.png') 316 try: 317 png = wx.Image(bitmap, wx.BITMAP_TYPE_PNG).ConvertToBitmap() 318 bmp = wx.StaticBitmap(self, -1, png, wx.Point(10, 10), wx.Size(png.GetWidth(), png.GetHeight())) 319 self.topsizer.Add ( 320 bmp, 321 proportion = 0, 322 flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 323 border = 10 324 ) 325 except: 326 self.topsizer.Add ( 327 wx.StaticText ( 328 self, 329 -1, 330 label = _("Cannot find image") + bitmap, 331 style = wx.ALIGN_CENTRE 332 ), 333 proportion = 0, 334 flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 335 border = 10 336 ) 337 338 paramsbox_caption = _('"%s" (version %s)') % (gmSurgery.gmCurrentPractice().active_workplace, client_version) 339 340 # FIXME: why doesn't this align in the centre ? 341 self.paramsbox = wx.StaticBox( self, -1, paramsbox_caption, style = wx.ALIGN_CENTRE_HORIZONTAL) 342 self.paramsboxsizer = wx.StaticBoxSizer( self.paramsbox, wx.VERTICAL ) 343 self.paramsbox.SetForegroundColour(wx.Colour(35, 35, 142)) 344 self.paramsbox.SetFont(wx.Font( 345 pointSize = 12, 346 family = wx.SWISS, 347 style = wx.NORMAL, 348 weight = wx.BOLD, 349 underline = False 350 )) 351 self.pboxgrid = wx.FlexGridSizer(5, 2, 5, 5) 352 self.pboxgrid.AddGrowableCol(1) 353 354 # PROFILE COMBO 355 label = wx.StaticText( self, -1, _('Log into'), wx.DefaultPosition, wx.DefaultSize, 0) 356 label.SetForegroundColour(wx.Colour(35, 35, 142)) 357 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) 358 self.__backend_profiles = self.__get_backend_profiles() 359 self._CBOX_profile = wx.ComboBox ( 360 self, 361 -1, 362 self.__backend_profiles.keys()[0], 363 wx.DefaultPosition, 364 size = wx.Size(150,-1), 365 choices = self.__backend_profiles.keys(), 366 style = wx.CB_READONLY 367 ) 368 self.pboxgrid.Add (self._CBOX_profile, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 369 370 # USER NAME COMBO 371 label = wx.StaticText( self, -1, _("Username"), wx.DefaultPosition, wx.DefaultSize, 0 ) 372 label.SetForegroundColour(wx.Colour(35, 35, 142)) 373 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 374 self.__previously_used_accounts = self.__get_previously_used_accounts() 375 self._CBOX_user = wx.ComboBox ( 376 self, 377 -1, 378 self.__previously_used_accounts[0], 379 wx.DefaultPosition, 380 wx.Size(150,-1), 381 self.__previously_used_accounts, 382 wx.CB_DROPDOWN 383 ) 384 self.pboxgrid.Add( self._CBOX_user, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 385 386 #PASSWORD TEXT ENTRY 387 label = wx.StaticText( self, -1, _("Password"), wx.DefaultPosition, wx.DefaultSize, 0 ) 388 label.SetForegroundColour(wx.Colour(35, 35, 142)) 389 self.pboxgrid.Add( label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 390 self.pwdentry = wx.TextCtrl( self, 1, '', wx.DefaultPosition, wx.Size(80,-1), wx.TE_PASSWORD ) 391 # set focus on password entry 392 self.pwdentry.SetFocus() 393 self.pboxgrid.Add( self.pwdentry, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 394 395 # --debug checkbox 396 label = wx.StaticText(self, -1, _('Options'), wx.DefaultPosition, wx.DefaultSize, 0) 397 label.SetForegroundColour(wx.Colour(35, 35, 142)) 398 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 399 self._CHBOX_debug = wx.CheckBox(self, -1, _('&Debug mode')) 400 self._CHBOX_debug.SetToolTipString(_('Check this to run GNUmed client in debugging mode.')) 401 self.pboxgrid.Add(self._CHBOX_debug, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) 402 403 # --slave checkbox 404 label = wx.StaticText(self, -1, '', wx.DefaultPosition, wx.DefaultSize, 0) 405 label.SetForegroundColour(wx.Colour(35, 35, 142)) 406 self.pboxgrid.Add(label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) 407 self._CHBOX_slave = wx.CheckBox(self, -1, _('Enable &remote control')) 408 self._CHBOX_slave.SetToolTipString(_('Check this to run GNUmed client in slave mode for remote control.')) 409 self.pboxgrid.Add(self._CHBOX_slave, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) 410 411 #---------------------------------------------------------------------- 412 #new button code inserted rterry 06Sept02 413 #button order re-arraged to make it consistant with usual dialog format 414 #in most operating systems ie btns ok and cancel are standard and 415 #in that order 416 #ie Order is now help, ok and cancel 417 #The order of creation is the tab order 418 #login-ok button automatically is the default when tabbing (or <enter>) 419 #from password 420 #this eliminates the heavy border when you use the default 421 #?is the default word needed for any other reason? 422 #---------------------------------------------------------------------- 423 self.button_gridsizer = wx.GridSizer(1,3,0,0) 424 #--------------------- 425 #3:create login ok button 426 #--------------------- 427 ID_BUTTON_LOGIN = wx.NewId() 428 button_login_ok = wx.Button(self, ID_BUTTON_LOGIN, _("&Ok"), wx.DefaultPosition, wx.DefaultSize, 0 ) 429 button_login_ok.SetToolTip(wx.ToolTip(_("Proceed with login.")) ) 430 button_login_ok.SetDefault() 431 432 #--------------------- 433 #3:create cancel button 434 #--------------------- 435 ID_BUTTON_CANCEL = wx.NewId() 436 button_cancel = wx.Button(self, ID_BUTTON_CANCEL, _("&Cancel"), wx.DefaultPosition, wx.DefaultSize, 0 ) 437 button_cancel.SetToolTip(wx.ToolTip(_("Cancel Login.")) ) 438 #--------------------- 439 #2:create Help button 440 #--------------------- 441 ID_BUTTON_HELP = wx.NewId() 442 button_help = wx.Button(self, ID_BUTTON_HELP, _("&Help"), wx.DefaultPosition, wx.DefaultSize, 0 ) 443 button_help.SetToolTip(wx.ToolTip(_("Help for login screen"))) 444 #---------------------------- 445 #Add buttons to the gridsizer 446 #---------------------------- 447 self.button_gridsizer.Add (button_help,0,wx.EXPAND|wx.ALL,5) 448 self.button_gridsizer.Add (button_login_ok,0,wx.EXPAND|wx.ALL,5) 449 self.button_gridsizer.Add (button_cancel,0,wx.EXPAND|wx.ALL,5) 450 451 self.paramsboxsizer.Add(self.pboxgrid, 1, wx.GROW|wx.ALL, 10) 452 self.topsizer.Add(self.paramsboxsizer, 1, wx.GROW|wx.ALL, 10) 453 self.topsizer.Add( self.button_gridsizer, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) 454 455 self.__load_state() 456 457 self.SetAutoLayout(True) 458 self.SetSizer( self.topsizer) 459 self.topsizer.Fit( self ) 460 if self.isDialog: 461 self.topsizer.SetSizeHints(parent) 462 463 wx.EVT_BUTTON(self, ID_BUTTON_HELP, self.OnHelp) 464 wx.EVT_BUTTON(self, ID_BUTTON_LOGIN, self.__on_login_button_pressed) 465 wx.EVT_BUTTON(self, ID_BUTTON_CANCEL, self.OnCancel)
466 467 #---------------------------------------------------------- 468 # internal helper methods 469 #----------------------------------------------------------
471 472 accounts = gmTools.coalesce ( 473 _cfg.get ( 474 group = u'backend', 475 option = u'logins', 476 source_order = [ 477 (u'explicit', u'extend'), 478 (u'user', u'extend'), 479 (u'workbase', u'extend') 480 ] 481 ), 482 ['any-doc'] 483 ) 484 # FIXME: make unique 485 486 return accounts
487 #----------------------------------------------------
488 - def __get_backend_profiles(self):
489 """Get server profiles from the configuration files. 490 491 1) from system-wide file 492 2) from user file 493 494 Profiles in the user file which have the same name 495 as a profile in the system file will override the 496 system file. 497 """ 498 # find active profiles 499 src_order = [ 500 (u'explicit', u'extend'), 501 (u'system', u'extend'), 502 (u'user', u'extend'), 503 (u'workbase', u'extend') 504 ] 505 506 profile_names = gmTools.coalesce ( 507 _cfg.get(group = u'backend', option = u'profiles', source_order = src_order), 508 [] 509 ) 510 511 # find data for active profiles 512 src_order = [ 513 (u'explicit', u'return'), 514 (u'workbase', u'return'), 515 (u'user', u'return'), 516 (u'system', u'return') 517 ] 518 519 profiles = {} 520 521 for profile_name in profile_names: 522 # FIXME: once the profile has been found always use the corresponding source ! 523 # FIXME: maybe not or else we cannot override parts of the profile 524 profile = cBackendProfile() 525 profile_section = 'profile %s' % profile_name 526 527 profile.name = profile_name 528 profile.host = gmTools.coalesce(_cfg.get(profile_section, u'host', src_order), u'').strip() 529 port = gmTools.coalesce(_cfg.get(profile_section, u'port', src_order), 5432) 530 try: 531 profile.port = int(port) 532 if profile.port < 1024: 533 raise ValueError('refusing to use priviledged port (< 1024)') 534 except ValueError: 535 _log.warning('invalid port definition: [%s], skipping profile [%s]', port, profile_name) 536 continue 537 profile.database = gmTools.coalesce(_cfg.get(profile_section, u'database', src_order), u'').strip() 538 if profile.database == u'': 539 _log.warning('database name not specified, skipping profile [%s]', profile_name) 540 continue 541 profile.encoding = gmTools.coalesce(_cfg.get(profile_section, u'encoding', src_order), u'UTF8') 542 profile.public_db = bool(_cfg.get(profile_section, u'public/open access', src_order)) 543 profile.helpdesk = _cfg.get(profile_section, u'help desk', src_order) 544 545 label = u'%s (%s@%s)' % (profile_name, profile.database, profile.host) 546 profiles[label] = profile 547 548 # sort out profiles with incompatible database versions if not --debug 549 # NOTE: this essentially hardcodes the database name in production ... 550 if not (_cfg.get(option = 'debug') or current_db_name.endswith('_devel')): 551 profiles2remove = [] 552 for label in profiles: 553 if profiles[label].database != current_db_name: 554 profiles2remove.append(label) 555 for label in profiles2remove: 556 del profiles[label] 557 558 if len(profiles) == 0: 559 host = u'salaam.homeunix.com' 560 label = u'public GNUmed database (%s@%s)' % (current_db_name, host) 561 profiles[label] = cBackendProfile() 562 profiles[label].name = label 563 profiles[label].host = host 564 profiles[label].port = 5432 565 profiles[label].database = current_db_name 566 profiles[label].encoding = u'UTF8' 567 profiles[label].public_db = True 568 profiles[label].helpdesk = u'http://wiki.gnumed.de' 569 570 return profiles
571 #----------------------------------------------------------
572 - def __load_state(self):
573 574 src_order = [ 575 (u'explicit', u'return'), 576 (u'user', u'return'), 577 ] 578 579 self._CBOX_user.SetValue ( 580 gmTools.coalesce ( 581 _cfg.get(u'preferences', u'login', src_order), 582 self.__previously_used_accounts[0] 583 ) 584 ) 585 586 last_used_profile_label = _cfg.get(u'preferences', u'profile', src_order) 587 if last_used_profile_label in self.__backend_profiles.keys(): 588 self._CBOX_profile.SetValue(last_used_profile_label) 589 else: 590 self._CBOX_profile.SetValue(self.__backend_profiles.keys()[0]) 591 592 self._CHBOX_debug.SetValue(_cfg.get(option = 'debug')) 593 self._CHBOX_slave.SetValue(_cfg.get(option = 'slave'))
594 #----------------------------------------------------
595 - def save_state(self):
596 """Save parameter settings to standard configuration file""" 597 prefs_name = _cfg.get(option = 'user_preferences_file') 598 _log.debug(u'saving login preferences in [%s]', prefs_name) 599 600 gmCfg2.set_option_in_INI_file ( 601 filename = prefs_name, 602 group = 'preferences', 603 option = 'login', 604 value = self._CBOX_user.GetValue() 605 ) 606 607 gmCfg2.set_option_in_INI_file ( 608 filename = prefs_name, 609 group = 'preferences', 610 option = 'profile', 611 value = self._CBOX_profile.GetValue() 612 )
613 ############################################################################# 614 # Retrieve current settings from user interface widgets 615 #############################################################################
616 - def GetLoginInfo(self):
617 """convenience function for compatibility with gmLoginInfo.LoginInfo""" 618 if not self.cancelled: 619 # FIXME: do not assume conf file is latin1 ! 620 #profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('latin1').strip()] 621 profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('utf8').strip()] 622 _log.debug(u'backend profile "%s" selected', profile.name) 623 _log.debug(u' details: <%s> on %s@%s:%s (%s, %s)', 624 self._CBOX_user.GetValue(), 625 profile.database, 626 profile.host, 627 profile.port, 628 profile.encoding, 629 gmTools.bool2subst(profile.public_db, u'public', u'private') 630 ) 631 _log.debug(u' helpdesk: "%s"', profile.helpdesk) 632 login = gmLoginInfo.LoginInfo ( 633 user = self._CBOX_user.GetValue(), 634 password = self.pwdentry.GetValue(), 635 host = profile.host, 636 database = profile.database, 637 port = profile.port 638 ) 639 login.public_db = profile.public_db 640 login.helpdesk = profile.helpdesk 641 return login 642 643 return None
644 #---------------------------- 645 # event handlers 646 #----------------------------
647 - def OnHelp(self, event):
648 praxis = gmSurgery.gmCurrentPractice() 649 wx.MessageBox(_( 650 """GNUmed main login screen 651 652 USER: 653 name of the GNUmed user 654 PASSWORD 655 password for this user 656 657 button OK: 658 proceed with login 659 button OPTIONS: 660 set advanced options 661 button CANCEL: 662 abort login and quit GNUmed client 663 button HELP: 664 this help screen 665 666 For assistance on using GNUmed please contact: 667 %s""") % praxis.helpdesk)
668 669 #----------------------------
670 - def __on_login_button_pressed(self, event):
671 672 root_logger = logging.getLogger() 673 if self._CHBOX_debug.GetValue(): 674 _log.info('debug mode enabled') 675 _cfg.set_option(option = 'debug', value = True) 676 root_logger.setLevel(logging.DEBUG) 677 else: 678 _log.info('debug mode disabled') 679 _cfg.set_option(option = 'debug', value = False) 680 if _cfg.get(option = '--quiet', source_order = [('cli', 'return')]): 681 root_logger.setLevel(logging.ERROR) 682 else: 683 root_logger.setLevel(logging.WARNING) 684 685 if self._CHBOX_slave.GetValue(): 686 _log.info('slave mode enabled') 687 _cfg.set_option(option = 'slave', value = True) 688 else: 689 _log.info('slave mode disabled') 690 _cfg.set_option(option = 'slave', value = False) 691 692 self.backend_profile = self.__backend_profiles[self._CBOX_profile.GetValue().encode('latin1').strip()] 693 # self.user = self._CBOX_user.GetValue().strip() 694 # self.password = self.GetPassword() 695 self.cancelled = False 696 self.parent.Close()
697 #----------------------------
698 - def OnCancel(self, event):
699 self.cancelled = True 700 self.parent.Close()
701 702 #================================================================ 703 # main 704 #---------------------------------------------------------------- 705 if __name__ == "__main__": 706 707 from Gnumed.pycommon import gmI18N 708 709 logging.basicConfig(level = logging.DEBUG) 710 711 gmI18N.activate_locale() 712 gmI18N.install_domain(domain='gnumed') 713 #----------------------------------------------- 714 #-----------------------------------------------
715 - def test():
716 app = wx.PyWidgetTester(size = (300,400)) 717 #show the login panel in a main window 718 # app.SetWidget(cLoginPanel, -1) 719 #and pop the login dialog up modally 720 dlg = cLoginDialog(None, -1) #, png_bitmap = 'bitmaps/gnumedlogo.png') 721 dlg.ShowModal() 722 #demonstration how to access the login dialog values 723 lp = dlg.panel.GetLoginInfo() 724 if lp is None: 725 wx.MessageBox(_("Dialog was cancelled by user")) 726 else: 727 wx.MessageBox(_("You tried to log in as [%s] with password [%s].\nHost:%s, DB: %s, Port: %s") % (lp.GetUser(),lp.GetPassword(),lp.GetHost(),lp.GetDatabase(),lp.GetPort())) 728 dlg.Destroy()
729 # app.MainLoop() 730 #----------------------------------------------- 731 if len(sys.argv) > 1 and sys.argv[1] == 'test': 732 print "no regression tests yet" 733 734 #================================================================ 735 # $Log: gmAuthWidgets.py,v $ 736 # Revision 1.45 2009/11/06 15:16:21 ncq 737 # - add missing dot 738 # 739 # Revision 1.44 2009/10/20 10:25:10 ncq 740 # - try not to log previous exception instances 741 # 742 # Revision 1.43 2009/09/23 14:33:14 ncq 743 # - improved failed-auth message 744 # 745 # Revision 1.42 2009/07/02 20:50:04 ncq 746 # - cleanup 747 # 748 # Revision 1.41 2009/07/01 17:06:33 ncq 749 # - improved wording 750 # 751 # Revision 1.40 2009/06/11 13:04:13 ncq 752 # - cleanup 753 # 754 # Revision 1.39 2009/06/11 11:07:57 ncq 755 # - properly display localhost 756 # 757 # Revision 1.38 2009/04/14 11:02:20 ncq 758 # - if not debugging and not in development sort out database 759 # profiles with incompatible names, this essentially hardcodes 760 # the database name for the first time 761 # 762 # Revision 1.37 2009/04/03 10:40:17 ncq 763 # - calculate current db name from expected version 764 # 765 # Revision 1.36 2009/04/03 09:38:20 ncq 766 # - bump db version 767 # 768 # Revision 1.35 2009/02/05 13:03:08 ncq 769 # - cleanup 770 # 771 # Revision 1.34 2009/01/15 11:35:41 ncq 772 # - cleanup 773 # 774 # Revision 1.33 2008/12/25 17:46:09 ncq 775 # - better logging 776 # - work around PG unknown initial encoding problem 777 # 778 # Revision 1.32 2008/11/20 18:48:15 ncq 779 # - add default help desk to builtin default backend profile 780 # 781 # Revision 1.31 2008/10/22 12:13:09 ncq 782 # - bump db version 783 # 784 # Revision 1.30 2008/10/12 16:06:07 ncq 785 # - make profile label show db@host 786 # - log profile used 787 # 788 # Revision 1.29 2008/09/09 20:18:51 ncq 789 # - default to any-doc if no previous logins found 790 # 791 # Revision 1.28 2008/08/31 16:47:48 ncq 792 # - proper policy when retrieving previous logins 793 # 794 # Revision 1.27 2008/08/31 16:34:12 ncq 795 # - properly set src_order and policy when retrieving profile *data* 796 # 797 # Revision 1.26 2008/08/31 16:15:02 ncq 798 # - use "extend" policy when retrieving backend profiles 799 # 800 # Revision 1.25 2008/07/30 12:50:34 ncq 801 # - cleanup 802 # 803 # Revision 1.24 2008/07/16 11:11:10 ncq 804 # - set_helpdesk (no more _database_) 805 # 806 # Revision 1.23 2008/07/10 20:52:21 ncq 807 # - better to call path detection with app_name and wx 808 # 809 # Revision 1.22 2008/07/07 11:35:19 ncq 810 # - keyboard shortcuts for check boxes 811 # 812 # Revision 1.21 2008/05/28 21:26:40 ncq 813 # - gracefully handle OperationalErrors such as "server not available" 814 # 815 # Revision 1.20 2008/05/13 14:10:35 ncq 816 # - be more permissive in time skew check 817 # - handle per-profile public-db/helpdesk options 818 # 819 # Revision 1.19 2008/04/16 20:39:39 ncq 820 # - working versions of the wxGlade code and use it, too 821 # - show client version in login dialog 822 # 823 # Revision 1.18 2008/03/20 15:30:21 ncq 824 # - use gmPG2.sanity_check_time_skew() 825 # 826 # Revision 1.17 2008/03/11 17:00:49 ncq 827 # - explicitely request readonly raw connection 828 # 829 # Revision 1.16 2008/03/06 18:29:29 ncq 830 # - standard lib logging only 831 # 832 # Revision 1.15 2008/03/05 22:26:52 ncq 833 # - spelling 834 # 835 # Revision 1.14 2008/02/25 17:33:16 ncq 836 # - use improved db sanity checks 837 # 838 # Revision 1.13 2008/01/30 14:07:02 ncq 839 # - protect against faulty backend profile in preferences 840 # 841 # Revision 1.12 2008/01/27 21:13:17 ncq 842 # - no more gmCfg 843 # 844 # Revision 1.11 2008/01/14 20:33:06 ncq 845 # - cleanup 846 # - properly detect connection errors 847 # 848 # Revision 1.10 2008/01/13 01:16:52 ncq 849 # - log DSN on any connect errors 850 # 851 # Revision 1.9 2008/01/07 19:51:54 ncq 852 # - bump db version 853 # - we still need gmCfg 854 # 855 # Revision 1.8 2007/12/26 23:22:27 ncq 856 # - fix invalid variable access 857 # 858 # Revision 1.7 2007/12/26 22:44:31 ncq 859 # - missing import of logging 860 # - use std lib logger 861 # - cleanup 862 # 863 # Revision 1.6 2007/12/26 22:01:25 shilbert 864 # - cleanup 865 # 866 # Revision 1.5 2007/12/23 22:02:56 ncq 867 # - no more gmCLI 868 # 869 # Revision 1.4 2007/12/23 20:26:31 ncq 870 # - cleanup 871 # 872 # Revision 1.3 2007/12/23 12:07:40 ncq 873 # - cleanup 874 # - use gmCfg2 875 # 876 # Revision 1.2 2007/12/04 16:14:52 ncq 877 # - get_dbowner_connection() 878 # 879 # Revision 1.1 2007/12/04 16:03:43 ncq 880 # - merger of gmLogin and gmLoginDialog 881 # 882 # 883 884 #---------------------------------------------------------------- 885 # old logs 886 #---------------------------------------------------------------- 887 # Log: gmLogin.py,v 888 # Revision 1.37 2007/12/04 15:23:14 ncq 889 # - reorder connect_to_database() 890 # - check server settings sanity 891 # 892 # Revision 1.36 2007/11/09 14:40:33 ncq 893 # - gmPG2 dumps schema by itself now on hash mismatch 894 # 895 # Revision 1.35 2007/10/23 21:24:39 ncq 896 # - start backend listener on login 897 # 898 # Revision 1.34 2007/06/11 20:25:18 ncq 899 # - better logging 900 # 901 # Revision 1.33 2007/04/27 13:29:31 ncq 902 # - log schema dump on version conflict 903 # 904 # Revision 1.32 2007/03/18 14:10:07 ncq 905 # - do show schema mismatch warning even if --override-schema-check 906 # 907 # Revision 1.31 2007/03/08 11:41:55 ncq 908 # - set default client encoding from here 909 # - save state when --override-schema-check == True, too 910 # 911 # Revision 1.30 2006/12/15 15:27:01 ncq 912 # - move database schema version check here 913 # 914 # Revision 1.29 2006/10/25 07:46:44 ncq 915 # - Format() -> strftime() since datetime.datetime does not have .Format() 916 # 917 # Revision 1.28 2006/10/25 07:21:57 ncq 918 # - no more gmPG 919 # 920 # Revision 1.27 2006/10/24 13:25:19 ncq 921 # - Login() -> connect_to_database() 922 # - make gmPG2 main connection provider, piggyback gmPG onto it for now 923 # 924 # Revision 1.26 2006/10/08 11:04:45 ncq 925 # - simplify wx import 926 # - piggyback gmPG2 until gmPG is pruned 927 # 928 # Revision 1.25 2006/01/03 12:12:03 ncq 929 # - make epydoc happy re _() 930 # 931 # Revision 1.24 2005/09/27 20:44:59 ncq 932 # - wx.wx* -> wx.* 933 # 934 # Revision 1.23 2005/09/26 18:01:51 ncq 935 # - use proper way to import wx26 vs wx2.4 936 # - note: THIS WILL BREAK RUNNING THE CLIENT IN SOME PLACES 937 # - time for fixup 938 # 939 # Revision 1.22 2004/09/13 08:54:49 ncq 940 # - cleanup 941 # - use gmGuiHelpers 942 # 943 # Revision 1.21 2004/07/18 20:30:54 ncq 944 # - wxPython.true/false -> Python.True/False as Python tells us to do 945 # 946 # Revision 1.20 2004/06/20 16:01:05 ncq 947 # - please epydoc more carefully 948 # 949 # Revision 1.19 2004/06/20 06:49:21 ihaywood 950 # changes required due to Epydoc's OCD 951 # 952 # Revision 1.18 2004/03/04 19:47:06 ncq 953 # - switch to package based import: from Gnumed.foo import bar 954 # 955 # Revision 1.17 2003/11/17 10:56:38 sjtan 956 # 957 # synced and commiting. 958 # 959 # Revision 1.1 2003/10/23 06:02:39 sjtan 960 # 961 # manual edit areas modelled after r.terry's specs. 962 # 963 # Revision 1.16 2003/06/26 21:40:29 ncq 964 # - fatal->verbose 965 # 966 # Revision 1.15 2003/02/07 14:28:05 ncq 967 # - cleanup, cvs keywords 968 # 969 # @change log: 970 # 29.10.2001 hherb first draft, untested 971 # 972 #---------------------------------------------------------------- 973 # Log: gmLoginDialog.py,v 974 # Revision 1.90 2007/10/22 12:38:32 ncq 975 # - default db change 976 # 977 # Revision 1.89 2007/10/07 12:32:41 ncq 978 # - workplace property now on gmSurgery.gmCurrentPractice() borg 979 # 980 # Revision 1.88 2007/09/20 19:07:38 ncq 981 # - port 5432 on salaam again 982 # 983 # Revision 1.87 2007/09/04 23:30:28 ncq 984 # - support --slave and slave mode checkbox 985 # 986 # Revision 1.86 2007/08/07 21:42:40 ncq 987 # - cPaths -> gmPaths 988 # 989 # Revision 1.85 2007/06/14 21:55:49 ncq 990 # - try to fix wx2.8 problem with size 991 # 992 # Revision 1.84 2007/06/11 20:25:55 ncq 993 # - bump database version 994 # 995 # Revision 1.83 2007/06/10 10:17:54 ncq 996 # - fix when no --debug 997 # 998 # Revision 1.82 2007/05/22 13:35:11 ncq 999 # - default port 5433 now on salaam 1000 # 1001 # Revision 1.81 2007/05/08 11:16:10 ncq 1002 # - set debugging flag based on user checkbox selection 1003 # 1004 # Revision 1.80 2007/05/07 12:33:31 ncq 1005 # - use gmTools.cPaths 1006 # - support debug mode checkbox 1007 # 1008 # Revision 1.79 2007/04/11 20:45:01 ncq 1009 # - no more 'resource dir' 1010 # 1011 # Revision 1.78 2007/04/02 15:15:19 ncq 1012 # - v5 -> v6 1013 # 1014 # Revision 1.77 2007/03/08 16:20:50 ncq 1015 # - need to reference proper cfg file 1016 # 1017 # Revision 1.76 2007/03/08 11:46:23 ncq 1018 # - restructured 1019 # - cleanup 1020 # - no more cLoginParamChoices 1021 # - no more loginparams keyword 1022 # - properly set user preferences file 1023 # - backend profile now can contain per-profile default encoding 1024 # - support system-wide profile pre-defs in /etc/gnumed/gnumed-client.conf 1025 # 1026 # Revision 1.75 2007/02/17 14:13:11 ncq 1027 # - gmPerson.gmCurrentProvider().workplace now property 1028 # 1029 # Revision 1.74 2007/01/30 17:40:22 ncq 1030 # - cleanup, get rid of wxMAC IFDEF 1031 # - use user preferences file for storing login preferences 1032 # 1033 # Revision 1.73 2006/12/21 16:54:32 ncq 1034 # - inage handlers already inited 1035 # 1036 # Revision 1.72 2006/12/15 15:27:28 ncq 1037 # - cleanup 1038 # 1039 # Revision 1.71 2006/10/25 07:21:57 ncq 1040 # - no more gmPG 1041 # 1042 # Revision 1.70 2006/09/01 14:45:03 ncq 1043 # - assume conf file is latin1 ... FIX later ! 1044 # 1045 # Revision 1.69 2006/07/30 17:50:03 ncq 1046 # - properly load bitmaps 1047 # 1048 # Revision 1.68 2006/05/15 07:05:07 ncq 1049 # - must import gmPerson now 1050 # 1051 # Revision 1.67 2006/05/14 21:44:22 ncq 1052 # - add get_workplace() to gmPerson.gmCurrentProvider and make use thereof 1053 # - remove use of gmWhoAmI.py 1054 # 1055 # Revision 1.66 2006/05/12 12:18:11 ncq 1056 # - whoami -> whereami cleanup 1057 # - use gmCurrentProvider() 1058 # 1059 # Revision 1.65 2005/09/28 21:27:30 ncq 1060 # - a lot of wx2.6-ification 1061 # 1062 # Revision 1.64 2005/09/27 20:44:59 ncq 1063 # - wx.wx* -> wx.* 1064 # 1065 # Revision 1.63 2005/09/26 18:01:51 ncq 1066 # - use proper way to import wx26 vs wx2.4 1067 # - note: THIS WILL BREAK RUNNING THE CLIENT IN SOME PLACES 1068 # - time for fixup 1069 # 1070 # Revision 1.62 2005/09/24 09:17:29 ncq 1071 # - some wx2.6 compatibility fixes 1072 # 1073 # Revision 1.61 2005/08/15 15:15:25 ncq 1074 # - improved error message 1075 # 1076 # Revision 1.60 2005/08/14 15:22:04 ncq 1077 # - need to import gmNull 1078 # 1079 # Revision 1.59 2005/08/14 14:31:53 ncq 1080 # - better handling of missing/malformed config file 1081 # 1082 # Revision 1.58 2005/06/10 16:09:36 shilbert 1083 # foo.AddSizer()-> foo.Add() such that wx2.5 works 1084 # 1085 # Revision 1.57 2005/03/06 14:54:19 ncq 1086 # - szr.AddWindow() -> Add() such that wx2.5 works 1087 # - 'demographic record' -> get_identity() 1088 # 1089 # Revision 1.56 2005/01/22 22:26:06 ncq 1090 # - a bunch of cleanups 1091 # - i18n 1092 # 1093 # Revision 1.55 2005/01/20 21:37:40 hinnef 1094 # - added error dialog when no profiles specified 1095 # 1096 # Revision 1.54 2004/11/24 21:16:33 hinnef 1097 # - fixed issue with missing profiles when writing to empty gnumed.conf. 1098 # This lead to a crash when trying to load the invalid gnumed.conf. 1099 # Now we just ignore this and fall back to defaults. 1100 # 1101 # Revision 1.53 2004/11/22 19:32:36 hinnef 1102 # new login dialog with profiles 1103 # 1104 # Revision 1.52 2004/09/13 08:57:33 ncq 1105 # - losts of cleanup 1106 # - opt/tty not used in DSN anymore 1107 # - --slave -> gb['main.slave_mode'] 1108 # 1109 # Revision 1.51 2004/07/18 20:30:54 ncq 1110 # - wxPython.true/false -> Python.True/False as Python tells us to do 1111 # 1112 # Revision 1.50 2004/07/18 18:44:27 ncq 1113 # - use Python True, not wxPython true 1114 # 1115 # Revision 1.49 2004/06/20 16:01:05 ncq 1116 # - please epydoc more carefully 1117 # 1118 # Revision 1.48 2004/06/20 06:49:21 ihaywood 1119 # changes required due to Epydoc's OCD 1120 # 1121 # Revision 1.47 2004/05/28 13:06:41 ncq 1122 # - improve faceName/Mac OSX fix 1123 # 1124 # Revision 1.46 2004/05/28 09:09:34 shilbert 1125 # - remove faceName option from wx.Font on wxMac or else no go 1126 # 1127 # Revision 1.45 2004/05/26 20:35:23 ncq 1128 # - don't inherit from LoginDialog in OptionWindow, it barks on MacOSX 1129 # 1130 # Revision 1.44 2004/04/24 12:46:35 ncq 1131 # - logininfo() needs host= 1132 # 1133 # Revision 1.43 2004/03/04 19:47:06 ncq 1134 # - switch to package based import: from Gnumed.foo import bar 1135 # 1136 # Revision 1.42 2003/12/29 16:58:52 uid66147 1137 # - use whoami 1138 # 1139 # Revision 1.41 2003/11/17 10:56:38 sjtan 1140 # 1141 # synced and commiting. 1142 # 1143 # Revision 1.1 2003/10/23 06:02:39 sjtan 1144 # 1145 # manual edit areas modelled after r.terry's specs. 1146 # 1147 # Revision 1.40 2003/06/17 19:27:44 ncq 1148 # - cleanup 1149 # - only use cfg file login params if not empty list 1150 # 1151 # Revision 1.39 2003/05/17 17:30:36 ncq 1152 # - just some cleanup 1153 # 1154 # Revision 1.38 2003/05/12 09:01:45 ncq 1155 # - 1) type(tmp) is types.ListType implies tmp != None 1156 # - 2) check for ListType, not StringType 1157 # 1158 # Revision 1.37 2003/05/10 18:48:09 hinnef 1159 # - added stricter type checks when reading from cfg-file 1160 # 1161 # Revision 1.36 2003/04/05 00:37:46 ncq 1162 # - renamed a few variables to reflect reality 1163 # 1164 # Revision 1.35 2003/03/31 00:18:34 ncq 1165 # - or so I thought 1166 # 1167 # Revision 1.34 2003/03/31 00:17:43 ncq 1168 # - started cleanup/clarification 1169 # - made saving of values work again 1170 # 1171 # Revision 1.33 2003/02/09 18:55:47 ncq 1172 # - make comment less angry 1173 # 1174 # Revision 1.32 2003/02/08 00:32:30 ncq 1175 # - fixed failure to detect config file 1176 # 1177 # Revision 1.31 2003/02/08 00:15:17 ncq 1178 # - cvs metadata keywords 1179 # 1180 # Revision 1.30 2003/02/07 21:06:02 sjtan 1181 # 1182 # refactored edit_area_gen_handler to handler_generator and handler_gen_editarea. New handler for gmSelectPerson 1183 # 1184 # Revision 1.29 2003/02/02 07:38:29 michaelb 1185 # set serpent as window icon - login dialog & option dialog 1186 # 1187 # Revision 1.28 2003/01/16 09:22:28 ncq 1188 # - changed default workplace name to "__default__" to play better with the database 1189 # 1190 # Revision 1.27 2003/01/07 10:22:52 ncq 1191 # - fixed font definition 1192 # 1193 # Revision 1.26 2002/09/21 14:49:22 ncq 1194 # - cleanup related to gmi18n 1195 # 1196 # Revision 1.25 2002/09/12 23:19:27 ncq 1197 # - cleanup in preparation of cleansing 1198 # 1199 # Revision 1.24 2002/09/10 08:54:35 ncq 1200 # - remember workplace name once loaded 1201 # 1202 # Revision 1.23 2002/09/09 01:05:16 ncq 1203 # - fixed i18n glitch 1204 # - added note that _("") is invalid !! 1205 # 1206 # @change log: 1207 # 10.10.2001 hherb initial implementation, untested 1208 # 24.10.2001 hherb comments added 1209 # 24.10.2001 hherb LoginDialog class added, 1210 # 24.10.2001 hherb persistent changes across multiple processes enabled 1211 # 25.10.2001 hherb more flexible configuration options, more commenting 1212 # 07.02.2002 hherb saved parameters now showing corectly in combo boxes 1213 # 05.09.2002 hberger moved options to own dialog 1214 # 06.09.2002 rterry simplified gui 1215 # -duplication and visual clutter removed 1216 # removed duplication of information in display 1217 # login gone from title bar , occurs once only now 1218 # visually highlighted in dark blue 1219 # login button title now 'ok' to conform to usual defaults of 1220 # ok, cancel in most operating systems 1221 # reference to help removed (have help button for that) 1222 # date removed - can't see use of this in login - clutters 1223 # 06.09.2002 hberger removed old code, fixed "login on close window" bug 1224 # 07.09.2002 rterry removed duplicated heading in advanced login options 1225