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

Source Code for Module Gnumed.wxpython.gui.gmConfigRegistry

  1  # -*- coding: utf-8 -*- 
  2  """GNUmed configuration editor. 
  3   
  4  Works quite similar to the Windows Registry editor (but is 
  5  a clean-room implementation). 
  6   
  7  @license: GPL""" 
  8  #================================================================ 
  9  # $Source: /home/ncq/Projekte/cvs2git/vcs-mirror/gnumed/gnumed/client/wxpython/gui/gmConfigRegistry.py,v $ 
 10  __version__ = "$Revision: 1.43 $" 
 11  __author__ = "H.Berger, S.Hilbert, K.Hilbert" 
 12   
 13  import sys, os, string, types 
 14   
 15  _log = gmLog.gmDefLog 
 16  if __name__ == '__main__': 
 17          _log.SetAllLogLevels(gmLog.lData) 
 18   
 19  from Gnumed.pycommon import gmCfg, gmConfigCommon, gmI18N 
 20  from Gnumed.wxpython import gmPlugin, gmGuiHelpers, gmRegetMixin 
 21  from Gnumed.business import gmPerson, gmPraxis 
 22   
 23  import wx 
 24   
 25  _cfg = gmCfg.gmDefCfgFile 
 26   
 27  _log.Log(gmLog.lInfo, __version__) 
 28   
 29  [       ConfigTreeCtrlID, 
 30          ConfigTreeBoxID, 
 31          ParamBoxID, 
 32          ConfigEntryParamCtrlID, 
 33          ButtonParamApplyID, 
 34          ButtonParamRevertID, 
 35          DescriptionBoxID, 
 36          ConfigDescriptionTextID 
 37  ] = map(lambda _init_ctrls: wx.NewId(), range(8)) 
 38   
 39  #================================================================ 
40 -class cConfTree(wx.TreeCtrl):
41 """This wx.TreeCtrl derivative displays a tree view of configuration 42 parameter names. 43 """
44 - def __init__(self, parent, id, size=wx.DefaultSize,pos=wx.DefaultPosition, 45 style=None,configSources = None,rootLabel = "",paramWidgets=None):
46 """Set up our specialised tree.""" 47 48 self.paramTextCtrl = paramWidgets[0] 49 self.paramDescription = paramWidgets[1] 50 self.mConfSources = configSources 51 for src in configSources: 52 _log.Log(gmLog.lData, 'config source: [%s]' % str(src)) 53 self.rootLabel = rootLabel 54 55 wx.TreeCtrl.__init__(self, parent, id, pos, size, style) 56 57 self.root = None 58 self.param_list = None 59 # currently selected parameter/subtree 60 self.currSelParam = None 61 self.currSelSubtree = None 62 63 # connect handler 64 wx.EVT_TREE_ITEM_ACTIVATED (self, self.GetId(), self.OnActivate) 65 wx.EVT_RIGHT_DOWN(self,self.OnRightDown)
66 67 #------------------------------------------------------------------------
68 - def update(self):
69 70 if self.param_list is not None: 71 del self.param_list 72 73 if self.__populate_tree() is None: 74 return None 75 76 return True
77 #------------------------------------------------------------------------
78 - def __populate_tree(self):
79 # FIXME: TODO ALL ! 80 81 # clean old tree 82 if not self.root is None: 83 self.DeleteAllItems() 84 85 # init new tree 86 self.root = self.AddRoot(self.rootLabel, -1, -1) 87 self.SetPyData(self.root, {'type': 'root', 'name': self.rootLabel}) 88 self.SetItemHasChildren(self.root, False) 89 90 # now get subtrees for four maingroups (see __init__) 91 92 for nodeDescription in (self.mConfSources.keys()): 93 94 _log.Log(gmLog.lData, 'adding first level node: [%s]' % nodeDescription) 95 node = self.AppendItem(self.root, nodeDescription) 96 self.SetPyData(node, {'type': 'defaultSubtree', 'name': nodeDescription}) 97 98 # add subtree if any 99 subTree = self.__getSubTree(nodeDescription) 100 if subTree is None: 101 self.SetItemHasChildren(node, False) 102 _log.Log(gmLog.lData, 'node has no children') 103 continue 104 self.__addSubTree(node, subTree) 105 106 self.SortChildren(node) 107 self.SetItemHasChildren(node, True) 108 109 self.SetItemHasChildren(self.root, True) 110 self.SortChildren(self.root) 111 # and uncollapse 112 self.Expand(self.root) 113 114 return True
115 #------------------------------------------------------------------------ 116 # this must be reentrant as we will iterate over the tree branches
117 - def __addSubTree(self,aNode=None, aSubTree=None):
118 """ 119 Adds a subtree of parameter names to an existing tree. 120 Returns resulting tree. 121 """ 122 _log.Log(gmLog.lData, 'adding sub tree: [%s]' % str(aSubTree)) 123 124 # check if subtree is empty 125 if aSubTree[1] == {}: 126 return None 127 128 # check if subtree has children 129 childrenList = aSubTree[1].keys() 130 if childrenList is None: 131 return None 132 self.SetItemHasChildren(aNode, True) 133 134 # add every child as new node, add child-subtrees as subtree 135 # reiterating this method 136 for subTreeNode in childrenList: 137 nodeEntry = aSubTree[1][subTreeNode] 138 nodeName = nodeEntry[2] 139 node = self.AppendItem(aNode, nodeName) 140 self.SetPyData(node, nodeEntry[0]) 141 self.SetItemHasChildren(node, False) 142 # now add subTrees 143 if not nodeEntry[1] == {}: 144 self.__addSubTree(node,nodeEntry) 145 self.SortChildren(node)
146 147 #------------------------------------------------------------------------
148 - def __getSubTree(self,nodeDescription):
149 """ 150 get a subtree from the backend via ConfigData layer. 151 the subtree must have a special structure (see addTreeItem). 152 """ 153 # if the subtree config data source is null, return empty subtree 154 if self.mConfSources[nodeDescription] is None: 155 return None 156 157 # get all parameter names 158 tmpParamList = self.mConfSources[nodeDescription].getAllParamNames() 159 if tmpParamList is None: 160 return None 161 162 # convert name list to a tree structure 163 currSubTree = [None,{},""] 164 # add each item 165 # attach parameter name (= reference for ConfigData) and subtree as object 166 for paramName in tmpParamList: 167 self.__addTreeItem ( 168 currSubTree, 169 paramName, 170 {'type': 'parameter', 'ref': paramName, 'subtree': nodeDescription} 171 ) 172 173 return currSubTree
174 #------------------------------------------------------------------------
175 - def __addTreeItem(self,aSubTree, aStructuredName,object=None):
176 """ 177 adds a name of the form "a.b.c.d" to a dict so that 178 dict['a']['b']['c']['d'] is a valid tree entry 179 each subTree entry consists of a 3 element list: 180 element [0] is an optional arbitrary object that should be connected 181 with the tree element(ID, etc.), element [1] a dictionary 182 holding the children of this element (again elements of type subTree) 183 list element [3] is the branch name 184 """ 185 nameParts = string.split(str(aStructuredName), '.') 186 187 tmpFunc = "aSubTree" 188 tmpDict = None 189 branchName = "" 190 # loop through all name parts 191 for part in (nameParts): 192 #recreate branch name 193 if branchName == "": 194 branchName = branchName + part 195 else: 196 branchName = branchName + "." + part 197 # get subtree dict 198 tmpDict = eval(tmpFunc)[1] 199 if part not in tmpDict: 200 # initialize new branch 201 tmpDict[part]=[] 202 tmpDict[part].append({ 'type': 'branch', 'name': branchName }) 203 tmpDict[part].append({}) 204 tmpDict[part].append(part) 205 # set new start for branching nodes 206 tmpFunc = tmpFunc + "[1]['%s']" % part 207 # set object 208 eval(tmpFunc)[0]=object 209 return aSubTree
210 #------------------------------------------------------------------------
211 - def SaveCurrParam(self):
212 """save parameter dialog""" 213 # self.currSelParam is the name of the parameter with optional 214 # cookie part appended, defParamName the name without cookie part ! 215 # you must use the latter to access config definitions ! 216 217 if not (self.currSelParam is None or self.currSelSubtree is None): 218 219 # get new value 220 val = self.paramTextCtrl.GetValue() 221 222 currConfSource = self.mConfSources[self.currSelSubtree] 223 newValue = currConfSource.castType(self.currSelParam,val) 224 225 if newValue is None: 226 gmGuiHelpers.gm_show_error ( 227 _('Type of entered value is not compatible with type expected.'), 228 _('saving configuration') 229 ) 230 231 # a particular config definition refers to a parameter name 232 # without the cookie part. we have to strip the 233 # cookie off get the correct parameter 234 defParamName = currConfSource.getRawName(self.currSelParam) 235 236 # config definition object 237 confDefinition = currConfSource.hasDefinition() 238 239 # if there is no config definition, ask the user if the 240 # new value should be stored unchecked 241 242 if not confDefinition or not currConfSource.hasParameterDefinition(defParamName): 243 if gmGuiHelpers.gm_show_question ( 244 _("There is no config definition for this parameter.\nThus it can't be checked for validity.\n\nSave anyway ?"), 245 _('saving configuration')): 246 currConfSource.setConfigData( self.currSelParam,newValue) 247 248 # reshow new data to mark it non modified 249 self.__show_parameter(self.currSelSubtree,self.currSelParam) 250 return 251 252 # else check parameter for validity 253 254 if currConfSource.isValid(defParamName,newValue): 255 currConfSource.setConfigData(self.currSelParam,newValue) 256 257 # reshow new data to mark it non modified 258 self.__show_parameter(self.currSelSubtree,self.currSelParam) 259 else: 260 # TODO: display some hint on what could be wrong 261 gmGuiHelpers.gm_show_error ( 262 _('Entered value is not valid.'), 263 _('saving configuration') 264 )
265 266 #------------------------------------------------------------------------
267 - def OnActivate (self, event):
268 item = event.GetItem() 269 data = self.GetItemData(item) 270 271 self.paramDescription.Clear() 272 self.paramTextCtrl.SetEditable(0) 273 type = data['type'] 274 if type == 'parameter': 275 # ref is the parameter name for use in ConfigData Object 276 self.currSelParam = data['ref'] 277 # Config Data subtree 278 self.currSelSubtree = data ['subtree'] 279 self.__show_parameter(self.currSelSubtree,self.currSelParam) 280 return 1 281 elif type == 'branch': 282 message=_("(Branch)") 283 elif type == 'defaultSubtree': 284 message=_("(Subtree root)") 285 elif type == 'root': 286 message=_("<Options for current/default user and workplace>") 287 # show message 288 self.paramTextCtrl.ShowMessage(message) 289 # expand/unexpand node if it has children 290 if self.ItemHasChildren(item): 291 if self.IsExpanded(item): 292 self.Collapse(item) 293 else: 294 self.Expand(item) 295 return True
296 297 #--------------------------------------------------------
298 - def OnRightDown(self,event):
299 position = event.GetPosition() 300 (item,flags) = self.HitTest(position) 301 # if flags & (wx.TREE_HITTEST_ONITEMLABEL) == True: 302 self.SelectItem(item)
303 #------------------------------------------------------------------------
304 - def __show_parameter(self,aSubtree=None, aParam=None):
305 # get the parameter value 306 value = self.mConfSources[aSubtree].getConfigData(aParam) 307 currType = self.mConfSources[aSubtree].getParamType(aParam) 308 # get description 309 description = self.mConfSources[aSubtree].getDescription(aParam) 310 # print "showing parameter:" 311 # print "param:", aParam 312 # print "val :", value 313 # print "type :", currType 314 # print "desc :", description 315 self.paramTextCtrl.ShowParam(aParam,currType,value) 316 self.paramTextCtrl.SetEditable(1) 317 self.paramDescription.SetValue(description)
318 ###############################################################################
319 -class cParamCtrl(wx.TextCtrl):
320 - def __init__(self, parent, id,value,pos,size,style,type ):
321 wx.TextCtrl.__init__(self, parent, -1, value="",style=style) 322 self.parent = parent
323
324 - def ShowParam(self,aParam=None,aType=None,aValue=None):
325 self.Clear() 326 if aParam is None: 327 return 328 # store current parameter for later use 329 self.currParam = aParam 330 self.value = aValue 331 self.type = aType 332 333 if self.type == 'string': 334 self.SetValue(self.value) 335 elif self.type == 'str_array': 336 # we can't use AppendText here because that would mark the value 337 # as modified 338 first = 1 339 all = '' 340 for line in (self.value): 341 if first: 342 first = 0 343 else: 344 all = all + '\n' 345 all = all + line 346 self.SetValue(all) 347 elif self.type == 'numeric': 348 self.SetValue(str(self.value))
349
350 - def ShowMessage(self,aMessage=""):
351 self.currParam = None 352 self.Clear() 353 self.SetValue(aMessage)
354 355
356 - def RevertToSaved(self):
357 if not self.currParam is None: 358 self.ShowParam(self.currParam, self.type, self.value)
359 360 ############################################################################### 361 # TODO: -a MenuBar allowing for import, export and options 362 # -open a connection to backend via gmCfg
363 -class gmConfigEditorPanel(wx.Panel):
364 - def __init__(self, parent, aUser,aWorkplace, plugin = 1):
365 """aUser and aWorkplace can be set such that an admin 366 could potentially edit another user ... 367 """ 368 wx.Panel.__init__(self, parent, -1) 369 370 self.currUser = aUser 371 self.currWorkplace = aWorkplace 372 # init data structures 373 # initialize the objects holding data on the subtrees 374 # add default subtrees root nodes if possible 375 # default entries in root: 376 # -default config file (usually ~/.gnumed/gnumed.conf) 377 # -current user, current workplace 378 # -current user, default workplace 379 # -default user, current workplace 380 # -default user, default workplace 381 self.mConfSources = {} 382 383 # if we pass no config file name, we get the default cfg file 384 cfgFileDefault = gmConfigCommon.ConfigSourceFile("gnumed.conf") 385 cfgFileName = cfgFileDefault.GetFullPath() 386 # if the file was not found, we display some error message 387 if cfgFileName is None: 388 cfgFileName = "gnumed.conf not found" 389 # now get the absolute path of the default cfg file 390 self.mConfSources['FILE:%s' % cfgFileName] = cfgFileDefault 391 try: 392 if not (self.currUser is None or self.currWorkplace is None): 393 self.mConfSources['DB:CURRENT_USER_CURRENT_WORKPLACE'] = gmConfigCommon.ConfigSourceDB('DB:CURRENT_USER_CURRENT_WORKPLACE',aWorkplace=self.currWorkplace) 394 except: pass 395 try: 396 if not (self.currUser is None) : 397 self.mConfSources['DB:CURRENT_USER_DEFAULT_WORKPLACE'] = gmConfigCommon.ConfigSourceDB('DB:CURRENT_USER_DEFAULT_WORKPLACE') 398 except: pass 399 try: 400 if not (self.currWorkplace is None): 401 self.mConfSources['DB:DEFAULT_USER_CURRENT_WORKPLACE'] = gmConfigCommon.ConfigSourceDB('DB:DEFAULT_USER_CURRENT_WORKPLACE',aUser='xxxDEFAULTxxx',aWorkplace=self.currWorkplace) 402 except: pass 403 try: 404 # this should always work 405 self.mConfSources['DB:DEFAULT_USER_DEFAULT_WORKPLACE'] = gmConfigCommon.ConfigSourceDB('DB:DEFAULT_USER_DEFAULT_WORKPLACE',aUser='xxxDEFAULTxxx') 406 except: 407 pass 408 # main sizers 409 self.mainSizer = wx.BoxSizer(wx.HORIZONTAL) 410 self.rightSizer = wx.BoxSizer(wx.VERTICAL) 411 412 # selected parameter 413 self.configEntryParamBox = wx.StaticBox( self, ParamBoxID, _("Parameters") ) 414 self.configEntryParamBoxSizer = wx.StaticBoxSizer( self.configEntryParamBox, wx.HORIZONTAL ) 415 416 self.configEntryParamCtrl = cParamCtrl( parent = self, 417 id = ConfigEntryParamCtrlID, 418 pos = wx.DefaultPosition, 419 size = wx.Size(250,200), 420 value = "" , 421 style = wx.LB_SINGLE, 422 type = None) 423 424 self.paramButtonSizer = wx.BoxSizer(wx.HORIZONTAL) 425 self.paramCtrlSizer = wx.BoxSizer(wx.VERTICAL) 426 self.buttonApply = wx.Button(parent=self, 427 id = ButtonParamApplyID, 428 label = "Apply changes" ) 429 self.buttonRevert = wx.Button(parent=self, 430 id = ButtonParamRevertID, 431 label = "Revert to saved" ) 432 433 wx.EVT_BUTTON(self,ButtonParamApplyID,self.ApplyChanges) 434 wx.EVT_BUTTON(self,ButtonParamRevertID,self.RevertChanges) 435 436 437 # parameter description 438 self.configEntryDescriptionBox = wx.StaticBox( self, DescriptionBoxID, _("Parameter Description") ) 439 self.configEntryDescriptionBoxSizer = wx.StaticBoxSizer( self.configEntryDescriptionBox, wx.HORIZONTAL ) 440 441 self.configEntryDescription = wx.TextCtrl(parent = self, 442 id = ConfigDescriptionTextID, 443 pos = wx.DefaultPosition, 444 size = wx.Size(250,100), 445 style = wx.TE_READONLY | wx.LB_SINGLE, 446 value ="" ) 447 self.configEntryDescriptionBoxSizer.Add( self.configEntryDescription, 1, wx.ALIGN_CENTRE|wx.ALL|wx.EXPAND, 2 ) 448 # static box for config tree 449 self.configTreeBox = wx.StaticBox( self, ConfigTreeBoxID, _("Config Options") ) 450 self.configTreeBoxSizer = wx.StaticBoxSizer( self.configTreeBox, wx.HORIZONTAL ) 451 452 # config tree 453 rootLabel = "%s@%s" % (self.currUser,self.currWorkplace) 454 self.configTree = cConfTree( parent = self, 455 id = ConfigTreeCtrlID , 456 pos = wx.Point(0, 0), 457 size = wx.Size(200, 300), 458 style = wx.TR_HAS_BUTTONS|wx.TAB_TRAVERSAL, 459 configSources = self.mConfSources, 460 rootLabel = rootLabel, 461 paramWidgets=(self.configEntryParamCtrl,self.configEntryDescription) 462 ) 463 self.configTree.SetFocus() 464 self.configTreeBoxSizer.Add( self.configTree, 1, wx.ALIGN_CENTRE|wx.ALL|wx.EXPAND, 5 ) 465 466 self.paramCtrlSizer.Add(self.configEntryParamCtrl,1,wx.ALIGN_CENTRE|wx.ALL|wx.EXPAND, 2 ) 467 self.paramButtonSizer.Add(self.buttonApply,1,wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 2 ) 468 self.paramButtonSizer.Add(self.buttonRevert,1,wx.ALIGN_RIGHT|wx.ALL|wx.EXPAND, 2 ) 469 self.paramCtrlSizer.Add(self.paramButtonSizer,0,wx.ALIGN_BOTTOM, 2 ) 470 self.configEntryParamBoxSizer.Add(self.paramCtrlSizer , 1, wx.ALIGN_CENTRE|wx.ALL|wx.EXPAND, 2 ) 471 472 # add right panels to right sizer 473 self.rightSizer.Add(self.configEntryParamBoxSizer, 1, wx.EXPAND, 0) 474 self.rightSizer.Add(self.configEntryDescriptionBoxSizer, 1, wx.EXPAND, 0) 475 476 # add widgets to main sizer 477 self.mainSizer.Add(self.configTreeBoxSizer, 1, wx.EXPAND, 0) 478 self.mainSizer.Add(self.rightSizer, 1, wx.EXPAND, 0) 479 self.SetAutoLayout(1) 480 self.SetSizer(self.mainSizer) 481 self.mainSizer.Fit(self) 482 self.mainSizer.SetSizeHints(self) 483 self.Layout()
484
485 - def ApplyChanges(self,event):
486 if self.configEntryParamCtrl.IsModified(): 487 self.configTree.SaveCurrParam()
488
489 - def RevertChanges(self,event):
490 self.configEntryParamCtrl.RevertToSaved()
491
492 - def repopulate_ui(self):
493 self.configTree.update()
494 495 #================================================================ 496 # MAIN 497 #---------------------------------------------------------------- 498 if __name__ == '__main__': 499 from Gnumed.wx.python import gmPlugin 500 _log.Log (gmLog.lInfo, "starting config browser") 501 502 workplace = input("Please enter a workplace name: ") 503 # catch all remaining exceptions 504 try: 505 application = wx.PyWidgetTester(size=(640,480)) 506 application.SetWidget(gmConfigEditorPanel,"any-doc",workplace, 0) 507 application.MainLoop() 508 except: 509 _log.LogException("unhandled exception caught !", sys.exc_info(), verbose=0) 510 # but re-raise them 511 raise 512 513 _log.Log (gmLog.lInfo, "closing config browser") 514 515 else:
516 - class gmConfigRegistry(gmPlugin.cNotebookPlugin):
517 """Class to load this module from an environment that wants a notebook plugin 518 """
519 - def name (self):
520 return _("Setup")
521
522 - def GetWidget (self, parent):
523 # get current workplace name 524 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace 525 currUser = gmStaff.gmCurrentProvider()['db_user'] 526 _log.Log (gmLog.lInfo, "ConfigReg: %s@%s" % (currUser,workplace)) 527 self._widget = gmConfigEditorPanel(parent,currUser,workplace) 528 return self._widget
529
530 - def MenuInfo (self):
531 return ('tools', _('&ConfigRegistry'))
532
533 - def Setup(parent):
534 """Wrapper to load this module from an environment that wants a panel 535 """ 536 currUser = gmStaff.gmCurrentProvider()['db_user'] 537 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace 538 return gmConfigEditorPanel(parent,currUser,workplace)
539 540 #------------------------------------------------------------ 541