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: /home/ncq/Projekte/cvs2git/vcs-mirror/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, gmPraxis 
 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 = gmPraxis.gmCurrentPraxisBranch().active_workplace 524 currUser = gmStaff.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 = gmStaff.gmCurrentProvider()['db_user'] 536 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace 537 return gmConfigEditorPanel(parent,currUser,workplace)
538 539 #------------------------------------------------------------ 540