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
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
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
59 self.currSelParam = None
60 self.currSelSubtree = None
61
62
63 wx.EVT_TREE_ITEM_ACTIVATED (self, self.GetId(), self.OnActivate)
64 wx.EVT_RIGHT_DOWN(self,self.OnRightDown)
65
66
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
78
79
80
81 if not self.root is None:
82 self.DeleteAllItems()
83
84
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
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
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
111 self.Expand(self.root)
112
113 return True
114
115
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
124 if aSubTree[1] == {}:
125 return None
126
127
128 childrenList = aSubTree[1].keys()
129 if childrenList is None:
130 return None
131 self.SetItemHasChildren(aNode, True)
132
133
134
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
142 if not nodeEntry[1] == {}:
143 self.__addSubTree(node,nodeEntry)
144 self.SortChildren(node)
145
146
148 """
149 get a subtree from the backend via ConfigData layer.
150 the subtree must have a special structure (see addTreeItem).
151 """
152
153 if self.mConfSources[nodeDescription] is None:
154 return None
155
156
157 tmpParamList = self.mConfSources[nodeDescription].getAllParamNames()
158 if tmpParamList is None:
159 return None
160
161
162 currSubTree = [None,{},""]
163
164
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
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
190 for part in (nameParts):
191
192 if branchName == "":
193 branchName = branchName + part
194 else:
195 branchName = branchName + "." + part
196
197 tmpDict = eval(tmpFunc)[1]
198 if not tmpDict.has_key(part):
199
200 tmpDict[part]=[]
201 tmpDict[part].append({ 'type': 'branch', 'name': branchName })
202 tmpDict[part].append({})
203 tmpDict[part].append(part)
204
205 tmpFunc = tmpFunc + "[1]['%s']" % part
206
207 eval(tmpFunc)[0]=object
208 return aSubTree
209
211 """save parameter dialog"""
212
213
214
215
216 if not (self.currSelParam is None or self.currSelSubtree is None):
217
218
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
231
232
233 defParamName = currConfSource.getRawName(self.currSelParam)
234
235
236 confDefinition = currConfSource.hasDefinition()
237
238
239
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
248 self.__show_parameter(self.currSelSubtree,self.currSelParam)
249 return
250
251
252
253 if currConfSource.isValid(defParamName,newValue):
254 currConfSource.setConfigData(self.currSelParam,newValue)
255
256
257 self.__show_parameter(self.currSelSubtree,self.currSelParam)
258 else:
259
260 gmGuiHelpers.gm_show_error (
261 _('Entered value is not valid.'),
262 _('saving configuration')
263 )
264
265
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
275 self.currSelParam = data['ref']
276
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
287 self.paramTextCtrl.ShowMessage(message)
288
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
298 position = event.GetPosition()
299 (item,flags) = self.HitTest(position)
300
301 self.SelectItem(item)
302
317
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
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
336
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
350 self.currParam = None
351 self.Clear()
352 self.SetValue(aMessage)
353
354
356 if not self.currParam is None:
357 self.ShowParam(self.currParam, self.type, self.value)
358
359
360
361
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
372
373
374
375
376
377
378
379
380 self.mConfSources = {}
381
382
383 cfgFileDefault = gmConfigCommon.ConfigSourceFile("gnumed.conf")
384 cfgFileName = cfgFileDefault.GetFullPath()
385
386 if cfgFileName is None:
387 cfgFileName = "gnumed.conf not found"
388
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
404 self.mConfSources['DB:DEFAULT_USER_DEFAULT_WORKPLACE'] = gmConfigCommon.ConfigSourceDB('DB:DEFAULT_USER_DEFAULT_WORKPLACE',aUser='xxxDEFAULTxxx')
405 except:
406 pass
407
408 self.mainSizer = wx.BoxSizer(wx.HORIZONTAL)
409 self.rightSizer = wx.BoxSizer(wx.VERTICAL)
410
411
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
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
448 self.configTreeBox = wx.StaticBox( self, ConfigTreeBoxID, _("Config Options") )
449 self.configTreeBoxSizer = wx.StaticBoxSizer( self.configTreeBox, wx.HORIZONTAL )
450
451
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
472 self.rightSizer.Add(self.configEntryParamBoxSizer, 1, wx.EXPAND, 0)
473 self.rightSizer.Add(self.configEntryDescriptionBoxSizer, 1, wx.EXPAND, 0)
474
475
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
485 if self.configEntryParamCtrl.IsModified():
486 self.configTree.SaveCurrParam()
487
490
493
494
495
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
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
510 raise
511
512 _log.Log (gmLog.lInfo, "closing config browser")
513
514 else:
516 """Class to load this module from an environment that wants a notebook plugin
517 """
520
528
530 return ('tools', _('&ConfigRegistry'))
531
538
539
540