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, 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
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
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716