Package Gnumed :: Package wxpython :: Package gui :: Module gmConfigRegistry
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gui.gmConfigRegistry

  1  """GnuMed configuration editor. 
  2   
  3  Works quite similar to the Windows Registry editor (but is 
  4  a clean-room implementation). 
  5   
  6  @license: GPL""" 
  7  #================================================================ 
  8  # $Source: /cvsroot/gnumed/gnumed/gnumed/client/wxpython/gui/gmConfigRegistry.py,v $ 
  9  __version__ = "$Revision: 1.43 $" 
 10  __author__ = "H.Berger, S.Hilbert, K.Hilbert" 
 11   
 12  import sys, os, string, types 
 13   
 14  _log = gmLog.gmDefLog 
 15  if __name__ == '__main__': 
 16          _log.SetAllLogLevels(gmLog.lData) 
 17   
 18  from Gnumed.pycommon import gmCfg, gmConfigCommon, gmI18N 
 19  from Gnumed.wxpython import gmPlugin, gmGuiHelpers, gmRegetMixin 
 20  from Gnumed.business import gmPerson, gmSurgery 
 21   
 22  import wx 
 23   
 24  _cfg = gmCfg.gmDefCfgFile 
 25   
 26  _log.Log(gmLog.lInfo, __version__) 
 27   
 28  [       ConfigTreeCtrlID, 
 29          ConfigTreeBoxID, 
 30          ParamBoxID, 
 31          ConfigEntryParamCtrlID, 
 32          ButtonParamApplyID, 
 33          ButtonParamRevertID, 
 34          DescriptionBoxID, 
 35          ConfigDescriptionTextID 
 36  ] = map(lambda _init_ctrls: wx.NewId(), range(8)) 
 37   
 38  #================================================================ 
39 -class cConfTree(wx.TreeCtrl):
40 """This wx.TreeCtrl derivative displays a tree view of configuration 41 parameter names. 42 """
43 - def __init__(self, parent, id, size=wx.DefaultSize,pos=wx.DefaultPosition, 44 style=None,configSources = None,rootLabel = "",paramWidgets=None):
45 """Set up our specialised tree.""" 46 47 self.paramTextCtrl = paramWidgets[0] 48 self.paramDescription = paramWidgets[1] 49 self.mConfSources = configSources 50 for src in configSources: 51 _log.Log(gmLog.lData, 'config source: [%s]' % str(src)) 52 self.rootLabel = rootLabel 53 54 wx.TreeCtrl.__init__(self, parent, id, pos, size, style) 55 56 self.root = None 57 self.param_list = None 58 # currently selected parameter/subtree 59 self.currSelParam = None 60 self.currSelSubtree = None 61 62 # connect handler 63 wx.EVT_TREE_ITEM_ACTIVATED (self, self.GetId(), self.OnActivate) 64 wx.EVT_RIGHT_DOWN(self,self.OnRightDown)
65 66 #------------------------------------------------------------------------
67 - def update(self):
68 69 if self.param_list is not None: 70 del self.param_list 71 72 if self.__populate_tree() is None: 73 return None 74 75 return True
76 #------------------------------------------------------------------------
77 - def __populate_tree(self):
78 # FIXME: TODO ALL ! 79 80 # clean old tree 81 if not self.root is None: 82 self.DeleteAllItems() 83 84 # init new tree 85 self.root = self.AddRoot(self.rootLabel, -1, -1) 86 self.SetPyData(self.root, {'type': 'root', 'name': self.rootLabel}) 87 self.SetItemHasChildren(self.root, False) 88 89 # now get subtrees for four maingroups (see __init__) 90 91 for nodeDescription in (self.mConfSources.keys()): 92 93 _log.Log(gmLog.lData, 'adding first level node: [%s]' % nodeDescription) 94 node = self.AppendItem(self.root, nodeDescription) 95 self.SetPyData(node, {'type': 'defaultSubtree', 'name': nodeDescription}) 96 97 # add subtree if any 98 subTree = self.__getSubTree(nodeDescription) 99 if subTree is None: 100 self.SetItemHasChildren(node, False) 101 _log.Log(gmLog.lData, 'node has no children') 102 continue 103 self.__addSubTree(node, subTree) 104 105 self.SortChildren(node) 106 self.SetItemHasChildren(node, True) 107 108 self.SetItemHasChildren(self.root, True) 109 self.SortChildren(self.root) 110 # and uncollapse 111 self.Expand(self.root) 112 113 return True
114 #------------------------------------------------------------------------ 115 # this must be reentrant as we will iterate over the tree branches
116 - def __addSubTree(self,aNode=None, aSubTree=None):
117 """ 118 Adds a subtree of parameter names to an existing tree. 119 Returns resulting tree. 120 """ 121 _log.Log(gmLog.lData, 'adding sub tree: [%s]' % str(aSubTree)) 122 123 # check if subtree is empty 124 if aSubTree[1] == {}: 125 return None 126 127 # check if subtree has children 128 childrenList = aSubTree[1].keys() 129 if childrenList is None: 130 return None 131 self.SetItemHasChildren(aNode, True) 132 133 # add every child as new node, add child-subtrees as subtree 134 # reiterating this method 135 for subTreeNode in childrenList: 136 nodeEntry = aSubTree[1][subTreeNode] 137 nodeName = nodeEntry[2] 138 node = self.AppendItem(aNode, nodeName) 139 self.SetPyData(node, nodeEntry[0]) 140 self.SetItemHasChildren(node, False) 141 # now add subTrees 142 if not nodeEntry[1] == {}: 143 self.__addSubTree(node,nodeEntry) 144 self.SortChildren(node)
145 146 #------------------------------------------------------------------------
147 - def __getSubTree(self,nodeDescription):
148 """ 149 get a subtree from the backend via ConfigData layer. 150 the subtree must have a special structure (see addTreeItem). 151 """ 152 # if the subtree config data source is null, return empty subtree 153 if self.mConfSources[nodeDescription] is None: 154 return None 155 156 # get all parameter names 157 tmpParamList = self.mConfSources[nodeDescription].getAllParamNames() 158 if tmpParamList is None: 159 return None 160 161 # convert name list to a tree structure 162 currSubTree = [None,{},""] 163 # add each item 164 # attach parameter name (= reference for ConfigData) and subtree as object 165 for paramName in tmpParamList: 166 self.__addTreeItem ( 167 currSubTree, 168 paramName, 169 {'type': 'parameter', 'ref': paramName, 'subtree': nodeDescription} 170 ) 171 172 return currSubTree
173 #------------------------------------------------------------------------
174 - def __addTreeItem(self,aSubTree, aStructuredName,object=None):
175 """ 176 adds a name of the form "a.b.c.d" to a dict so that 177 dict['a']['b']['c']['d'] is a valid tree entry 178 each subTree entry consists of a 3 element list: 179 element [0] is an optional arbitrary object that should be connected 180 with the tree element(ID, etc.), element [1] a dictionary 181 holding the children of this element (again elements of type subTree) 182 list element [3] is the branch name 183 """ 184 nameParts = string.split(str(aStructuredName), '.') 185 186 tmpFunc = "aSubTree" 187 tmpDict = None 188 branchName = "" 189 # loop through all name parts 190 for part in (nameParts): 191 #recreate branch name 192 if branchName == "": 193 branchName = branchName + part 194 else: 195 branchName = branchName + "." + part 196 # get subtree dict 197 tmpDict = eval(tmpFunc)[1] 198 if not tmpDict.has_key(part): 199 # initialize new branch 200 tmpDict[part]=[] 201 tmpDict[part].append({ 'type': 'branch', 'name': branchName }) 202 tmpDict[part].append({}) 203 tmpDict[part].append(part) 204 # set new start for branching nodes 205 tmpFunc = tmpFunc + "[1]['%s']" % part 206 # set object 207 eval(tmpFunc)[0]=object 208 return aSubTree
209 #------------------------------------------------------------------------
210 - def SaveCurrParam(self):
211 """save parameter dialog""" 212 # self.currSelParam is the name of the parameter with optional 213 # cookie part appended, defParamName the name without cookie part ! 214 # you must use the latter to access config definitions ! 215 216 if not (self.currSelParam is None or self.currSelSubtree is None): 217 218 # get new value 219 val = self.paramTextCtrl.GetValue() 220 221 currConfSource = self.mConfSources[self.currSelSubtree] 222 newValue = currConfSource.castType(self.currSelParam,val) 223 224 if newValue is None: 225 gmGuiHelpers.gm_show_error ( 226 _('Type of entered value is not compatible with type expected.'), 227 _('saving configuration') 228 ) 229 230 # a particular config definition refers to a parameter name 231 # without the cookie part. we have to strip the 232 # cookie off get the correct parameter 233 defParamName = currConfSource.getRawName(self.currSelParam) 234 235 # config definition object 236 confDefinition = currConfSource.hasDefinition() 237 238 # if there is no config definition, ask the user if the 239 # new value should be stored unchecked 240 241 if not confDefinition or not currConfSource.hasParameterDefinition(defParamName): 242 if gmGuiHelpers.gm_show_question ( 243 _("There is no config definition for this parameter.\nThus it can't be checked for validity.\n\nSave anyway ?"), 244 _('saving configuration')): 245 currConfSource.setConfigData( self.currSelParam,newValue) 246 247 # reshow new data to mark it non modified 248 self.__show_parameter(self.currSelSubtree,self.currSelParam) 249 return 250 251 # else check parameter for validity 252 253 if currConfSource.isValid(defParamName,newValue): 254 currConfSource.setConfigData(self.currSelParam,newValue) 255 256 # reshow new data to mark it non modified 257 self.__show_parameter(self.currSelSubtree,self.currSelParam) 258 else: 259 # TODO: display some hint on what could be wrong 260 gmGuiHelpers.gm_show_error ( 261 _('Entered value is not valid.'), 262 _('saving configuration') 263 )
264 265 #------------------------------------------------------------------------
266 - def OnActivate (self, event):
267 item = event.GetItem() 268 data = self.GetPyData(item) 269 270 self.paramDescription.Clear() 271 self.paramTextCtrl.SetEditable(0) 272 type = data['type'] 273 if type == 'parameter': 274 # ref is the parameter name for use in ConfigData Object 275 self.currSelParam = data['ref'] 276 # Config Data subtree 277 self.currSelSubtree = data ['subtree'] 278 self.__show_parameter(self.currSelSubtree,self.currSelParam) 279 return 1 280 elif type == 'branch': 281 message=_("(Branch)") 282 elif type == 'defaultSubtree': 283 message=_("(Subtree root)") 284 elif type == 'root': 285 message=_("<Options for current/default user and workplace>") 286 # show message 287 self.paramTextCtrl.ShowMessage(message) 288 # expand/unexpand node if it has children 289 if self.ItemHasChildren(item): 290 if self.IsExpanded(item): 291 self.Collapse(item) 292 else: 293 self.Expand(item) 294 return True
295 296 #--------------------------------------------------------
297 - def OnRightDown(self,event):
298 position = event.GetPosition() 299 (item,flags) = self.HitTest(position) 300 # if flags & (wx.TREE_HITTEST_ONITEMLABEL) == True: 301 self.SelectItem(item)
302 #------------------------------------------------------------------------
303 - def __show_parameter(self,aSubtree=None, aParam=None):
304 # get the parameter value 305 value = self.mConfSources[aSubtree].getConfigData(aParam) 306 currType = self.mConfSources[aSubtree].getParamType(aParam) 307 # get description 308 description = self.mConfSources[aSubtree].getDescription(aParam) 309 # print "showing parameter:" 310 # print "param:", aParam 311 # print "val :", value 312 # print "type :", currType 313 # print "desc :", description 314 self.paramTextCtrl.ShowParam(aParam,currType,value) 315 self.paramTextCtrl.SetEditable(1) 316 self.paramDescription.SetValue(description)
317 ###############################################################################
318 -class cParamCtrl(wx.TextCtrl):
319 - def __init__(self, parent, id,value,pos,size,style,type ):
320 wx.TextCtrl.__init__(self, parent, -1, value="",style=style) 321 self.parent = parent
322
323 - def ShowParam(self,aParam=None,aType=None,aValue=None):
324 self.Clear() 325 if aParam is None: 326 return 327 # store current parameter for later use 328 self.currParam = aParam 329 self.value = aValue 330 self.type = aType 331 332 if self.type == 'string': 333 self.SetValue(self.value) 334 elif self.type == 'str_array': 335 # we can't use AppendText here because that would mark the value 336 # as modified 337 first = 1 338 all = '' 339 for line in (self.value): 340 if first: 341 first = 0 342 else: 343 all = all + '\n' 344 all = all + line 345 self.SetValue(all) 346 elif self.type == 'numeric': 347 self.SetValue(str(self.value))
348
349 - def ShowMessage(self,aMessage=""):
350 self.currParam = None 351 self.Clear() 352 self.SetValue(aMessage)
353 354
355 - def RevertToSaved(self):
356 if not self.currParam is None: 357 self.ShowParam(self.currParam, self.type, self.value)
358 359 ############################################################################### 360 # TODO: -a MenuBar allowing for import, export and options 361 # -open a connection to backend via gmCfg
362 -class gmConfigEditorPanel(wx.Panel):
363 - def __init__(self, parent, aUser,aWorkplace, plugin = 1):
364 """aUser and aWorkplace can be set such that an admin 365 could potentially edit another user ... 366 """ 367 wx.Panel.__init__(self, parent, -1) 368 369 self.currUser = aUser 370 self.currWorkplace = aWorkplace 371 # init data structures 372 # initialize the objects holding data on the subtrees 373 # add default subtrees root nodes if possible 374 # default entries in root: 375 # -default config file (usually ~/.gnumed/gnumed.conf) 376 # -current user, current workplace 377 # -current user, default workplace 378 # -default user, current workplace 379 # -default user, default workplace 380 self.mConfSources = {} 381 382 # if we pass no config file name, we get the default cfg file 383 cfgFileDefault = gmConfigCommon.ConfigSourceFile("gnumed.conf") 384 cfgFileName = cfgFileDefault.GetFullPath() 385 # if the file was not found, we display some error message 386 if cfgFileName is None: 387 cfgFileName = "gnumed.conf not found" 388 # now get the absolute path of the default cfg file 389 self.mConfSources['FILE:%s' % cfgFileName] = cfgFileDefault 390 try: 391 if not (self.currUser is None or self.currWorkplace is None): 392 self.mConfSources['DB:CURRENT_USER_CURRENT_WORKPLACE'] = gmConfigCommon.ConfigSourceDB('DB:CURRENT_USER_CURRENT_WORKPLACE',aWorkplace=self.currWorkplace) 393 except: pass 394 try: 395 if not (self.currUser is None) : 396 self.mConfSources['DB:CURRENT_USER_DEFAULT_WORKPLACE'] = gmConfigCommon.ConfigSourceDB('DB:CURRENT_USER_DEFAULT_WORKPLACE') 397 except: pass 398 try: 399 if not (self.currWorkplace is None): 400 self.mConfSources['DB:DEFAULT_USER_CURRENT_WORKPLACE'] = gmConfigCommon.ConfigSourceDB('DB:DEFAULT_USER_CURRENT_WORKPLACE',aUser='xxxDEFAULTxxx',aWorkplace=self.currWorkplace) 401 except: pass 402 try: 403 # this should always work 404 self.mConfSources['DB:DEFAULT_USER_DEFAULT_WORKPLACE'] = gmConfigCommon.ConfigSourceDB('DB:DEFAULT_USER_DEFAULT_WORKPLACE',aUser='xxxDEFAULTxxx') 405 except: 406 pass 407 # main sizers 408 self.mainSizer = wx.BoxSizer(wx.HORIZONTAL) 409 self.rightSizer = wx.BoxSizer(wx.VERTICAL) 410 411 # selected parameter 412 self.configEntryParamBox = wx.StaticBox( self, ParamBoxID, _("Parameters") ) 413 self.configEntryParamBoxSizer = wx.StaticBoxSizer( self.configEntryParamBox, wx.HORIZONTAL ) 414 415 self.configEntryParamCtrl = cParamCtrl( parent = self, 416 id = ConfigEntryParamCtrlID, 417 pos = wx.DefaultPosition, 418 size = wx.Size(250,200), 419 value = "" , 420 style = wx.LB_SINGLE, 421 type = None) 422 423 self.paramButtonSizer = wx.BoxSizer(wx.HORIZONTAL) 424 self.paramCtrlSizer = wx.BoxSizer(wx.VERTICAL) 425 self.buttonApply = wx.Button(parent=self, 426 id = ButtonParamApplyID, 427 label = "Apply changes" ) 428 self.buttonRevert = wx.Button(parent=self, 429 id = ButtonParamRevertID, 430 label = "Revert to saved" ) 431 432 wx.EVT_BUTTON(self,ButtonParamApplyID,self.ApplyChanges) 433 wx.EVT_BUTTON(self,ButtonParamRevertID,self.RevertChanges) 434 435 436 # parameter description 437 self.configEntryDescriptionBox = wx.StaticBox( self, DescriptionBoxID, _("Parameter Description") ) 438 self.configEntryDescriptionBoxSizer = wx.StaticBoxSizer( self.configEntryDescriptionBox, wx.HORIZONTAL ) 439 440 self.configEntryDescription = wx.TextCtrl(parent = self, 441 id = ConfigDescriptionTextID, 442 pos = wx.DefaultPosition, 443 size = wx.Size(250,100), 444 style = wx.TE_READONLY | wx.LB_SINGLE, 445 value ="" ) 446 self.configEntryDescriptionBoxSizer.Add( self.configEntryDescription, 1, wx.ALIGN_CENTRE|wx.ALL|wx.EXPAND, 2 ) 447 # static box for config tree 448 self.configTreeBox = wx.StaticBox( self, ConfigTreeBoxID, _("Config Options") ) 449 self.configTreeBoxSizer = wx.StaticBoxSizer( self.configTreeBox, wx.HORIZONTAL ) 450 451 # config tree 452 rootLabel = "%s@%s" % (self.currUser,self.currWorkplace) 453 self.configTree = cConfTree( parent = self, 454 id = ConfigTreeCtrlID , 455 pos = wx.Point(0, 0), 456 size = wx.Size(200, 300), 457 style = wx.TR_HAS_BUTTONS|wx.TAB_TRAVERSAL, 458 configSources = self.mConfSources, 459 rootLabel = rootLabel, 460 paramWidgets=(self.configEntryParamCtrl,self.configEntryDescription) 461 ) 462 self.configTree.SetFocus() 463 self.configTreeBoxSizer.Add( self.configTree, 1, wx.ALIGN_CENTRE|wx.ALL|wx.EXPAND, 5 ) 464 465 self.paramCtrlSizer.Add(self.configEntryParamCtrl,1,wx.ALIGN_CENTRE|wx.ALL|wx.EXPAND, 2 ) 466 self.paramButtonSizer.Add(self.buttonApply,1,wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 2 ) 467 self.paramButtonSizer.Add(self.buttonRevert,1,wx.ALIGN_RIGHT|wx.ALL|wx.EXPAND, 2 ) 468 self.paramCtrlSizer.Add(self.paramButtonSizer,0,wx.ALIGN_BOTTOM, 2 ) 469 self.configEntryParamBoxSizer.Add(self.paramCtrlSizer , 1, wx.ALIGN_CENTRE|wx.ALL|wx.EXPAND, 2 ) 470 471 # add right panels to right sizer 472 self.rightSizer.Add(self.configEntryParamBoxSizer, 1, wx.EXPAND, 0) 473 self.rightSizer.Add(self.configEntryDescriptionBoxSizer, 1, wx.EXPAND, 0) 474 475 # add widgets to main sizer 476 self.mainSizer.Add(self.configTreeBoxSizer, 1, wx.EXPAND, 0) 477 self.mainSizer.Add(self.rightSizer, 1, wx.EXPAND, 0) 478 self.SetAutoLayout(1) 479 self.SetSizer(self.mainSizer) 480 self.mainSizer.Fit(self) 481 self.mainSizer.SetSizeHints(self) 482 self.Layout()
483
484 - def ApplyChanges(self,event):
485 if self.configEntryParamCtrl.IsModified(): 486 self.configTree.SaveCurrParam()
487
488 - def RevertChanges(self,event):
489 self.configEntryParamCtrl.RevertToSaved()
490
491 - def repopulate_ui(self):
492 self.configTree.update()
493 494 #================================================================ 495 # MAIN 496 #---------------------------------------------------------------- 497 if __name__ == '__main__': 498 from Gnumed.wx.python import gmPlugin 499 _log.Log (gmLog.lInfo, "starting config browser") 500 501 workplace = raw_input("Please enter a workplace name: ") 502 # catch all remaining exceptions 503 try: 504 application = wx.PyWidgetTester(size=(640,480)) 505 application.SetWidget(gmConfigEditorPanel,"any-doc",workplace, 0) 506 application.MainLoop() 507 except: 508 _log.LogException("unhandled exception caught !", sys.exc_info(), verbose=0) 509 # but re-raise them 510 raise 511 512 _log.Log (gmLog.lInfo, "closing config browser") 513 514 else:
515 - class gmConfigRegistry(gmPlugin.cNotebookPlugin):
516 """Class to load this module from an environment that wants a notebook plugin 517 """
518 - def name (self):
519 return _("Setup")
520
521 - def GetWidget (self, parent):
522 # get current workplace name 523 workplace = gmSurgery.gmCurrentPractice().active_workplace 524 currUser = gmPerson.gmCurrentProvider()['db_user'] 525 _log.Log (gmLog.lInfo, "ConfigReg: %s@%s" % (currUser,workplace)) 526 self._widget = gmConfigEditorPanel(parent,currUser,workplace) 527 return self._widget
528
529 - def MenuInfo (self):
530 return ('tools', _('&ConfigRegistry'))
531
532 - def Setup(parent):
533 """Wrapper to load this module from an environment that wants a panel 534 """ 535 currUser = gmPerson.gmCurrentProvider()['db_user'] 536 workplace = gmSurgery.gmCurrentPractice().active_workplace 537 return gmConfigEditorPanel(parent,currUser,workplace)
538 539 #------------------------------------------------------------ 540 # $Log: gmConfigRegistry.py,v $ 541 # Revision 1.43 2008/03/06 18:32:30 ncq 542 # - standard lib logging only 543 # 544 # Revision 1.42 2007/10/07 12:33:27 ncq 545 # - workplace property now on gmSurgery.gmCurrentPractice() borg 546 # 547 # Revision 1.41 2007/02/17 14:13:11 ncq 548 # - gmPerson.gmCurrentProvider().workplace now property 549 # 550 # Revision 1.40 2006/12/13 14:58:03 ncq 551 # - a bit of cleanup 552 # 553 # Revision 1.39 2006/12/05 14:02:09 ncq 554 # - fix wx import 555 # - add some logging 556 # 557 # Revision 1.38 2006/06/28 10:19:28 ncq 558 # - remove reget mixin 559 # - fix for receive_focus reload 560 # 561 # Revision 1.37 2006/05/20 18:56:03 ncq 562 # - use receive_focus() interface 563 # 564 # Revision 1.36 2006/05/14 21:44:22 ncq 565 # - add get_workplace() to gmPerson.gmCurrentProvider and make use thereof 566 # - remove use of gmWhoAmI.py 567 # 568 # Revision 1.35 2006/05/12 14:00:15 ncq 569 # - need to import gmPerson 570 # 571 # Revision 1.34 2006/05/12 12:19:09 ncq 572 # - whoami -> whereami 573 # 574 # Revision 1.33 2005/10/12 15:42:17 ncq 575 # - cleanup 576 # 577 # Revision 1.32 2005/10/02 11:38:03 sjtan 578 # import wx fixup. import wx.html 579 # 580 # Revision 1.31 2005/09/28 21:27:30 ncq 581 # - a lot of wx.2.6-ification 582 # 583 # Revision 1.30 2005/09/26 18:01:52 ncq 584 # - use proper way to import wx.26 vs wx.2.4 585 # - note: THIS WILL BREAK RUNNING THE CLIENT IN SOME PLACES 586 # - time for fixup 587 # 588 # Revision 1.29 2005/03/29 07:33:06 ncq 589 # - add comment 590 # 591 # Revision 1.28 2005/03/17 20:29:47 hinnef 592 # added Setup method for Richard-Space 593 # 594 # Revision 1.27 2005/03/06 14:54:19 ncq 595 # - szr.AddWindow() -> Add() such that wx.2.5 works 596 # - 'demographic record' -> get_identity() 597 # 598 # Revision 1.26 2004/09/25 13:11:40 ncq 599 # - improve tree root node naming 600 # 601 # Revision 1.25 2004/08/04 17:16:02 ncq 602 # - wx.NotebookPlugin -> cNotebookPlugin 603 # - derive cNotebookPluginOld from cNotebookPlugin 604 # - make cNotebookPluginOld warn on use and implement old 605 # explicit "main.notebook.raised_plugin"/ReceiveFocus behaviour 606 # - ReceiveFocus() -> receive_focus() 607 # 608 # Revision 1.24 2004/08/02 17:48:53 hinnef 609 # converted to use gmRegetMixin 610 # 611 # Revision 1.23 2004/07/24 10:27:22 ncq 612 # - TRUE/FALSE -> True/False so Python doesn't barf 613 # 614 # Revision 1.22 2004/07/19 11:50:43 ncq 615 # - cfg: what used to be called "machine" really is "workplace", so fix 616 # 617 # Revision 1.21 2004/07/15 07:57:20 ihaywood 618 # This adds function-key bindings to select notebook tabs 619 # (Okay, it's a bit more than that, I've changed the interaction 620 # between gmGuiMain and gmPlugin to be event-based.) 621 # 622 # Oh, and SOAPTextCtrl allows Ctrl-Enter 623 # 624 # Revision 1.20 2004/07/06 20:55:38 hinnef 625 # fixed bug introduced during testing :( 626 # 627 # Revision 1.19 2004/06/28 22:34:09 hinnef 628 # fixed missing tree population in standalone use 629 # 630 # Revision 1.18 2004/06/13 22:31:48 ncq 631 # - gb['main.toolbar'] -> gb['main.top_panel'] 632 # - self.internal_name() -> self.__class__.__name__ 633 # - remove set_widget_reference() 634 # - cleanup 635 # - fix lazy load in _on_patient_selected() 636 # - fix lazy load in ReceiveFocus() 637 # - use self._widget in self.GetWidget() 638 # - override populate_with_data() 639 # - use gb['main.notebook.raised_plugin'] 640 # 641 # Revision 1.17 2004/03/12 22:30:12 ncq 642 # - Hilmar, thanks :-) 643 # - also some cleanup (hehe, you guessed it) 644 # 645 # Revision 1.16 2004/03/12 18:33:02 hinnef 646 # - fixed module import 647 # 648 # Revision 1.15 2004/03/09 08:59:35 ncq 649 # - cleanup imports 650 # 651 # Revision 1.14 2004/03/09 07:34:51 ihaywood 652 # reactivating plugins 653 # 654 # Revision 1.13 2004/02/25 09:46:22 ncq 655 # - import from pycommon now, not python-common 656 # 657 # Revision 1.12 2004/01/06 23:44:40 ncq 658 # - __default__ -> xxxDEFAULTxxx 659 # 660 # Revision 1.11 2003/12/29 16:59:42 uid66147 661 # - whoami adjustment 662 # 663 # Revision 1.10 2003/11/17 10:56:39 sjtan 664 # 665 # synced and commiting. 666 # 667 # Revision 1.1 2003/10/23 06:02:40 sjtan 668 # 669 # manual edit areas modelled after r.terry's specs. 670 # 671 # Revision 1.9 2003/10/13 21:04:00 hinnef 672 # - added GPL statement 673 # 674 # Revision 1.8 2003/10/13 21:01:46 hinnef 675 # -fixed a bug that would introduce newlines in str_array type values 676 # 677 # Revision 1.7 2003/09/03 17:33:22 hinnef 678 # make use of gmWhoAmI, try to get config info from backend 679 # 680 # Revision 1.6 2003/08/24 08:58:18 ncq 681 # - use gm_show_* 682 # 683 # Revision 1.5 2003/08/23 18:40:43 hinnef 684 # split up in gmConfigRegistry.py and gmConfigCommon.py, debugging, more comments 685 # 686 # Revision 1.4 2003/06/26 21:41:51 ncq 687 # - fatal->verbose 688 # 689 # Revision 1.3 2003/06/26 04:18:40 ihaywood 690 # Fixes to gmCfg for commas 691 # 692 # Revision 1.2 2003/06/10 09:56:31 ncq 693 # - coding style, comments, tab name 694 # 695 # Revision 1.1 2003/06/03 21:50:44 hinnef 696 # - now we can store changed values to file/backend 697 # 698 # Revision 1.7 2003/05/22 21:19:21 ncq 699 # - some comments and cleanup 700 # 701 # Revision 1.6 2003/05/22 16:28:37 hinnef 702 # - selecting an item now expands/collapses its subtrees 703 # 704 # Revision 1.5 2003/05/16 10:51:45 hinnef 705 # - now subtrees can hold config file data 706 # 707 # Revision 1.4 2003/05/11 17:00:26 hinnef 708 # - removed obsolete code lines 709 # 710 # Revision 1.3 2003/05/11 16:56:48 hinnef 711 # - now shows values of config parameters, too 712 # 713 # Revision 1.2 2003/05/10 18:44:02 hinnef 714 # added revision log keyword 715 # 716