1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """This module contains the FitTree object designed for use in PDFgui.
16
17 Classes:
18 FitTree -- A tree specific to orgainizing data for pdffit
19
20 Exceptions:
21 FitTreeError -- Exception for errors with FitTree operations.
22 """
23
24 import wx
25 import sys, os, re, cPickle
26
27 from diffpy.pdfgui.gui.pdfguiglobals import iconpath
28 from diffpy.pdfgui.control.pdfguicontrol import pdfguicontrol
29 from diffpy.pdfgui.control.calculation import Calculation
30 from diffpy.pdfgui.control.fitting import Fitting
31 from diffpy.pdfgui.control.controlerrors import ControlError
32
34 """TreeCtrl designed to organize pdffit fits.
35
36 The root of the tree is hidden. Below that there are several levels
37 which are diagrammed below.
38
39 _ fit (*)
40 |
41 |____ phase (5)
42 |____ datset (*)
43 |____ calculation (*)
44
45 Fits are at the top level. Under fits there are phases, datasets, and
46 calculations (in that order).
47
48 It is required that the data for each node is a dictionary. In the 'type'
49 entry of this dictionary is the node type (fit, phase, dataset,
50 calculation). Fit items also have a 'cdata' entry in their tree item
51 dictionary. This is the control center data associated with this node's
52 branch.
53
54 Data members:
55 control -- The pdfguicontrol object that interfaces between the tree
56 and the pdffit2 engine. The tree is a mirror of the internal
57 structure of the control.
58
59 """
60
61 - def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
62 size=wx.DefaultSize,
63 style=wx.TR_HAS_BUTTONS|wx.TR_HIDE_ROOT|wx.TR_MULTIPLE,
64 validator=wx.DefaultValidator, name="FitTree"):
65 wx.TreeCtrl.__init__(self, parent, id, pos, size, style)
66
67
68
69
70
71
72 datasetbmp = wx.Bitmap(iconpath("datasetitem.png"))
73 phasebmp = wx.Bitmap(iconpath("phaseitem.png"))
74 fitbmp = wx.Bitmap(iconpath("fititem.png"))
75 calcbmp = wx.Bitmap(iconpath("calculationitem.png"))
76 isz = (16,16)
77 il = wx.ImageList(isz[0], isz[1])
78 self.fitbmid = il.Add(fitbmp)
79 self.dtsbmid = il.Add(datasetbmp)
80 self.phabmid = il.Add(phasebmp)
81 self.clcbmid = il.Add(calcbmp)
82 self.SetImageList(il)
83 self.treeImageList = il
84
85
86 return
87
89 """This initializes the tree by adding a root node."""
90 self.root = self.AddRoot("The Root Item")
91 self.SetNodeType(self.root, "root")
92
93
94
95
96
97
98
99 return
100
102 """Get the data dictionary of the node."""
103 return self.GetPyData(node)
104
106 """Return the id of the fit in which the passed node resides."""
107 if not node: return
108 fitId = node
109 nextId = self.GetItemParent(node)
110 while nextId != self.root:
111 fitId = nextId
112 nextId = self.GetItemParent(nextId)
113 return fitId
114
116 """Get the ids of the children of a given node."""
117 cookie = 0
118 ids = []
119 (child, cookie) = self.GetFirstChild(node)
120 while child.IsOk():
121 ids.append(child)
122 (child, cookie) = self.GetNextChild(node, cookie)
123
124 return ids
125
127 """Get the ids of the siblings of a given node."""
128 parent = self.GetItemParent(node)
129 ids = self.GetChildren(parent)
130 ids.remove(node)
131 return ids
132
134 """Get the id of each item in the tree of the same type as node."""
135 nodetype = self.GetNodeType(node)
136 fits = self.GetChildren(self.root)
137 if nodetype == 'fit':
138 return fits
139 else:
140 sametype = []
141 for fit in fits:
142 children = self.GetChildren(fit)
143 sametype.extend( [child for child in children if
144 self.GetNodeType(child) == nodetype] )
145 return sametype
146
148 """Get a list of phase in branch.
149
150 node is either the fit-root or a node in the fit-branch of interest.
151 """
152 nodes = self.GetChildren(self.GetFitRoot(node))
153 ids = [id for id in nodes if self.GetNodeType(id) == 'phase']
154 return ids
155
157 """Get a list of datasets in branch.
158
159 node is either the fit-root or a node in the fit-branch of interest.
160 """
161 nodes = self.GetChildren(self.GetFitRoot(node))
162 ids = [id for id in nodes if self.GetNodeType(id) == 'dataset']
163 return ids
164
166 """Get a list of calculations in branch.
167
168 node is either the fit-root or a node in the fit-branch of interest.
169 """
170 nodes = self.GetChildren(self.GetFitRoot(node))
171 ids = [id for id in nodes if self.GetNodeType(id) == 'calculation']
172 return ids
173
175 """Get the node type.
176
177 This is the "type" entry in the data dictionary of the node.
178 """
179 if not node: return
180 return self.GetTreeItemDict(node)['type']
181
183 """Set the node type of a node."""
184 if not node: return
185 datadict = self.GetTreeItemDict(node)
186 if not datadict:
187 self.SetPyData(node, {'type': type})
188 else:
189 self.GetTreeItemDict(node)['type'] = type
190 return
191
193 """Get the name of the branch in which node resides."""
194 fp = self.GetFitRoot(node)
195 return self.GetItemText(fp)
196
198 """Get the last phase child of the parent node.
199
200 This method is helpful in placing datasets and phases into the fit tree.
201 This method depends on the fact that phases are placed before datasets
202 in the fit tree.
203 """
204 siblings = self.GetChildren(node)
205 lastphase = None
206 for sib in siblings:
207 if self.GetNodeType(sib) == "dataset": break
208 elif self.GetNodeType(sib) == "calculation": break
209 else: lastphase = sib
210 return lastphase
211
213 """Get the last dataset child of the fit node.
214
215 If there is no last dataset node, this may return the last phase node.
216 The purpose of getting this node is to know where to place another node,
217 so the actual node type is not important.
218 """
219 siblings = self.GetChildren(node)
220 lastdata = None
221 for sib in siblings:
222 if self.GetNodeType(sib) == "calculation": break
223 else: lastdata = sib
224 return lastdata
225
227 """Get the number of phases in a branch.
228
229 node -- A node in the branch, or the root of the branch.
230 """
231 parent = self.GetFitRoot(node)
232 family = self.GetChildren(parent)
233 phases = [item for item in family if self.GetNodeType(item) == 'phase']
234 return len(phases)
235
237 """Get the number of datasets in a branch.
238
239 node -- A node in the branch, or the root of the branch.
240 """
241 parent = self.GetFitRoot(node)
242 family = self.GetChildren(parent)
243 phases = [item for item in family if self.GetNodeType(item) == 'dataset']
244 return len(phases)
245
247 """Get the index if the node in its subtree.
248
249 For fits the position is absolute within the tree. For phases, datasets,
250 and calculations, the location is taken to be in reference to the other
251 nodes of its type. This is designed to be compatible with the control
252 center.
253 """
254 parent = self.GetItemParent(node)
255 brood = self.GetChildren(parent)
256 pos = 0
257 for sib in brood:
258 if sib == node:
259 break
260 else: pos += 1
261 nodetype = self.GetNodeType(node)
262 if nodetype == 'dataset':
263 pos -= self.GetNumPhases(node)
264 if nodetype == 'calculation':
265 pos -= self.GetNumPhases(node) + self.GetNumDataSets(node)
266 return pos
267
269 """Set the control center data associated with the node.
270
271 This need only be called for 'fit' nodes.
272 This is the "cdata" entry in the data dictionary of the
273 node. It holds the object with which the right panel interfaces. For
274 example, for a 'phase' node, it contains a Structure object.
275 """
276 nodetype = self.GetNodeType(node)
277 if nodetype != 'fit':
278 message = 'Node type %s does not hold its own data' % nodetype
279 raise FitTreeError, message
280
281 self.GetTreeItemDict(node)['cdata'] = data
282 return
283
285 """Get the control center data associated with a node.
286
287 NOTE: The fit-root of a node holds this data. This method makes it
288 convenient to retrieve it.
289 """
290 nodetype = self.GetNodeType(node)
291 parent = self.GetFitRoot(node)
292 pdata = self.GetTreeItemDict(parent)['cdata']
293 if nodetype == 'fit':
294 return pdata
295 elif nodetype == 'phase':
296 pos = self.GetPositionInSubtree(node)
297 return pdata.getStructure(pos)
298 elif nodetype == 'dataset':
299 pos = self.GetPositionInSubtree(node)
300 return pdata.getDataSet(pos)
301 elif nodetype == 'calculation':
302 pos = self.GetPositionInSubtree(node)
303 return pdata.getCalculation(pos)
304 else:
305 message = "Node of type %s does not exist" % nodetype
306 raise FitTreeError, message
307 return
308
309 - def AddFit(self, fitname = "Fit 1", cdata = None, paste = False):
310 """Append a new fit tree to the end of the current fits.
311
312 fitname -- The name of the fit. This is incremented if it already
313 exists.
314 cdata -- Control data for the node. If cdata is None (default),
315 then the control is asked to create new data.
316 paste -- Whether or not the cdata is being pasted from another
317 node (default False).
318
319 Returns the id of the new node.
320 """
321
322 fits = self.GetChildren(self.root)
323 names = map(self.GetItemText, fits)
324 fitname = incrementName(fitname, names)
325
326 newfit = self.AppendItem(self.root, fitname)
327 self.SetNodeType(newfit, 'fit')
328 self.SetItemImage(newfit, self.fitbmid, wx.TreeItemIcon_Normal)
329 pos = self.GetPositionInSubtree(newfit)
330
331 try:
332
333 if cdata is None:
334 cdata = self.control.newFitting(fitname, pos)
335 elif paste:
336 cdata = self.control.paste(cdata, None, fitname, pos)
337 self.SetControlData(newfit, cdata)
338 return newfit
339 except:
340 self.Delete(newfit)
341 raise
342 return
343
344 - def AddPhase(self, node, label, insertafter=None, filename=None,
345 makedata = True, cdata=None):
346 """Add a new blank Phase to the tree as a child of node.
347
348 node -- The parent 'fit' node.
349 label -- The name of the new node.
350 insertafter -- The node after which to insert the new phase. If
351 insertafter is None (default) the new phase is
352 appended to the end of the phases in the subtree of
353 the parent node.
354 filename -- The file from which to load the structure. If this is
355 None (default), a new structure is created.
356 makedata -- Tells whether the control needs to make data for the
357 node (default True).
358 cdata -- Control data for the node. If cdata is None (default),
359 then it is assumed that the node already has data in the
360 control. See ExtendProjectTree and __InsertBranch for
361 examples of how this is used.
362
363 Phases are always placed before DataSets.
364
365 Raises:
366 FitTreeError if node is not a "fit" node.
367 FitTreeError if insertafter is not a "phase" node.
368
369 Returns the id of the new node.
370 """
371
372 nodetype = self.GetNodeType(node)
373 if nodetype != "fit":
374 message = "Can only add a phase as a child of a fit."
375 raise FitTreeError, message
376
377 if insertafter is not None:
378 afttype = self.GetNodeType(insertafter)
379 if afttype != "phase":
380 insertafter = None
381
382 if insertafter:
383 newphase = self.InsertItem(node, insertafter, label)
384 else:
385 lastphase = self.GetLastPhase(node)
386 if lastphase:
387
388 newphase = self.InsertItem(node, lastphase, label)
389 else:
390 newphase = self.PrependItem(node, label)
391
392 self.SetNodeType(newphase, "phase")
393 self.SetItemImage(newphase, self.phabmid, wx.TreeItemIcon_Normal)
394
395
396 pdata = self.GetControlData(node)
397 pos = self.GetPositionInSubtree(newphase)
398
399
400
401 try:
402 if makedata:
403 if filename is None:
404 self.control.newStructure(pdata, label, pos)
405 else:
406 self.control.loadStructure(pdata, filename, label, pos)
407
408 elif cdata is not None:
409 self.control.paste(cdata, pdata, label, pos)
410 return newphase
411 except:
412 self.Delete(newphase)
413 raise
414 return
415
416 - def AddDataSet(self, node, label, insertafter=None, filename=None,
417 makedata=True, cdata=None):
418 """Add a new DataSet to the tree as a child of fit.
419
420 node -- The parent node of the dataset. Must be 'fit' type.
421 label -- The label of the new node.
422 insertafter -- The node after which to insert the new dataset. If
423 insertafter is None (default) the new dataset is
424 appended to the end of the datasets in the subtree of
425 the parent node.
426 filename -- The name of the file from which to load the data.
427 makedata -- Tells whether the control needs to make data for the
428 node (default True). If True, cdata is ignored.
429 cdata -- Control data for the node. If False cdata is None
430 (default), then it is assumed that the node already has
431 data in the control. See ExtendProjectTree and
432 __InsertBranch for examples of how this is used.
433
434 DataSets are always placed after Phases.
435
436 Raises:
437 FitTreeError if node is not a "fit" node.
438 FitTreeError if insertafter is not a "dataset" node.
439
440 Returns the id of the new node.
441 """
442
443 nodetype = self.GetNodeType(node)
444 if nodetype != "fit":
445 message = "Can only add a data set as a child of a fit."
446 raise FitTreeError, message
447
448 if insertafter is not None:
449 afttype = self.GetNodeType(node)
450 if afttype != "dataset":
451 insertafter = None
452
453 if insertafter:
454 newset = self.InsertItem(node, insertafter, label)
455 else:
456 lastset = self.GetLastDataSet(node)
457 if lastset:
458 newset = self.InsertItem(node, lastset, label)
459 else:
460 newset = self.PrependItem(node, label)
461
462 self.SetNodeType(newset, "dataset")
463 self.SetItemImage(newset, self.dtsbmid, wx.TreeItemIcon_Normal)
464
465 pos = self.GetPositionInSubtree(newset)
466 pdata = self.GetControlData(node)
467
468 try:
469 if makedata:
470 if filename is not None:
471 self.control.loadDataset(pdata, filename, label, pos)
472 else:
473 raise FitTreeError, "Cannot load a dataset without a name!"
474 elif cdata is not None:
475 self.control.paste(cdata, pdata, label, pos)
476 return newset
477 except:
478 self.Delete(newset)
479 raise
480 return
481
482 - def AddCalc(self, node, label, insertafter=None, makedata=True, cdata=None):
483 """Add a new DataSet to the tree as a child of fit.
484
485 node -- The parent node of the calculation. Must be 'fit' type.
486 label -- The label of the new node.
487 insertafter -- The node after which to insert the new calculation. If
488 insertafter is None (default) the new calculation is
489 appended to the end of the calculation in the subtree of
490 the parent node.
491 makedata -- Tells whether the control needs to make data for the
492 node (default True). If True, cdata is ignored.
493 cdata -- Control data for the node. If False cdata is None
494 (default), then it is assumed that the node already has
495 data in the control. See ExtendProjectTree and
496 __InsertBranch for examples of how this is used.
497
498 Calculations are always placed after datasets.
499
500 Raises:
501 FitTreeError if node is not a "fit" node.
502 FitTreeError if insertafter is not a "calculation" node.
503
504 Returns the id of the new node.
505 """
506
507 nodetype = self.GetNodeType(node)
508 if nodetype != "fit":
509 message = "Can only add a calculation as a child of a fit."
510 raise FitTreeError, message
511
512 if insertafter is not None:
513 afttype = self.GetNodeType(node)
514 if afttype != "calculation":
515 insertafter = None
516
517 sibs = self.GetCalculations(node)
518 names = map(self.GetItemText, sibs)
519 label = incrementName(label, names)
520
521 if insertafter:
522 newcalc = self.InsertItem(node, insertafter, label)
523 else:
524 newcalc = self.AppendItem(node, label)
525
526 self.SetNodeType(newcalc, "calculation")
527 self.SetItemImage(newcalc, self.clcbmid, wx.TreeItemIcon_Normal)
528
529 pos = self.GetPositionInSubtree(newcalc)
530 pdata = self.GetControlData(node)
531
532 try:
533 if makedata:
534 self.control.newCalculation(pdata, label, pos)
535 elif cdata is not None:
536 self.control.paste(cdata, pdata, label, pos)
537 return newcalc
538 except:
539 self.Delete(newcalc)
540 raise
541 return
542
544 """Make a copy of a tree branch.
545
546 The branch is held in the system clipboard so it can be used in another
547 instance of the fittree.
548 """
549 nodetype = self.GetNodeType(startnode)
550 cdata = self.control.copy(self.GetControlData(startnode))
551 if isinstance(cdata, Fitting):
552 cdata = cdata.stripped()
553 cdata.type = nodetype
554 cdatastring = cPickle.dumps(cdata)
555 cdatastring = "pdfgui_cliboard=" + cdatastring
556 textdata = wx.PyTextDataObject(cdatastring)
557 if not wx.TheClipboard.IsOpened():
558 opened = wx.TheClipboard.Open()
559 if not opened: raise FitTreeError, "Cannot open the clipboard."
560 wx.TheClipboard.SetData(textdata)
561 wx.TheClipboard.Close()
562 return
563
565 """Get the clipboard data.
566
567 Returns the controldata in the clipboard, or None if the clipboard is
568 empty or contains the wrong type of data.
569 """
570
571 if not wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
572 return None
573
574 textdata = wx.PyTextDataObject()
575 if not wx.TheClipboard.IsOpened():
576 opened = wx.TheClipboard.Open()
577 if not opened: return None
578 success = wx.TheClipboard.GetData(textdata)
579 wx.TheClipboard.Close()
580 if not success: return None
581 cdatastring = textdata.GetText()
582
583 cdata = None
584 if cdatastring[:16] == "pdfgui_cliboard=":
585 cdatastring = cdatastring[16:]
586 try:
587 cdata = cPickle.loads(str(cdatastring))
588 except:
589 pass
590
591
592
593
594
595 return cdata
596
598 """Paste the branch from the clipboard into tree at the given node.
599
600 A certain type of branch can only be copied to specific places.
601
602 fit - A fit can be pasted to anywhere. This does not overwrite
603 an existing node, but simply inserts the fit into the
604 last available slot.
605 phase - A phase can be pasted from anywhere. If pasted from a
606 fit, it is placed at the end of the phase section of
607 that node. If inserted from a dataset or a calculation,
608 it is placed at the end of the phase section.
609 dataset - A dataset can be pasted from anywhere. If pasted from a
610 fit, the dataset is appended at the end of the other
611 datasets. If pasted from a dataset, the pasted set is
612 inserted right after that one. If pasted from a phase,
613 it is placed at the beginning of the dataset section. If
614 pasted from a calculation, it is placed at the end of
615 the dataset section.
616 calculation - A calculation can be pasted to anywhere, but it appears
617 at the end of the calculation section of the tree. If
618 pasted from a calculation node, it is inserted after
619 that node.
620
621 Raises:
622 FitTreeError if the entrypoint and branch type are incompatible.
623 """
624 cdata = self.GetClipboard()
625 if cdata is None:
626 message = "There is no branch to paste!"
627 raise FitTreeError, message
628
629
630 branchtype = cdata.type
631 insertafter = None
632 prepend = False
633 entrytype = None
634 if entrypoint:
635 entrytype = self.GetNodeType(entrypoint)
636
637
638 if branchtype == "fit":
639
640
641
642
643 entrytype = None
644 if entrypoint:
645 entrypoint = self.GetFitRoot(entrypoint)
646 entrytype = self.GetNodeType(entrypoint)
647
648 if entrytype is None:
649 entrypoint = self.root
650 insertafter = None
651 elif entrytype == "fit":
652 insertafter = entrypoint
653 entrypoint = self.root
654 else:
655 raise FitTreeError, "Cannot paste a fit branch here."
656
657 if branchtype == "phase":
658
659
660
661 if entrytype == "phase":
662
663 insertafter = entrypoint
664 entrypoint = self.GetItemParent(entrypoint)
665 elif entrytype in ("dataset", "calculation"):
666
667 entrypoint = self.GetItemParent(entrypoint)
668 insertafter = self.GetLastPhase(entrypoint)
669 if not insertafter:
670
671 prepend = True
672 elif entrytype == "fit":
673
674
675 insertafter = self.GetLastPhase(entrypoint)
676 if not insertafter:
677
678 prepend = True
679 else:
680 raise FitTreeError, "Cannot paste a phase branch here."
681
682 if branchtype == "dataset":
683
684
685 if entrytype == "dataset":
686
687 insertafter = entrypoint
688 entrypoint = self.GetItemParent(entrypoint)
689 elif entrytype == "phase":
690
691 entrypoint = self.GetItemParent(entrypoint)
692 insertafter = self.GetLastPhase(entrypoint)
693 elif entrytype == "calculation":
694
695 entrypoint = self.GetItemParent(entrypoint)
696 insertafter = self.GetLastDataSet(entrypoint)
697 elif entrytype == "fit":
698 insertafter = self.GetLastDataSet(entrypoint)
699
700
701 pass
702 else:
703 raise FitTreeError, "Cannot paste a data set branch here."
704
705 if branchtype == "calculation":
706
707
708 if entrytype == "calculation":
709
710 insertafter = entrypoint
711 entrypoint = self.GetItemParent(entrypoint)
712 elif entrytype in ("phase", "dataset"):
713 entrypoint = self.GetItemParent(entrypoint)
714 insertafter = self.GetLastDataSet(entrypoint)
715 elif entrytype == "fit":
716 insertafter = self.GetLastDataSet(entrypoint)
717 else:
718 raise FitTreeError, "Cannot paste a calculation branch here."
719
720
721
722 label = self.__copyLabel(cdata.name, entrypoint)
723
724
725 newnode = self.__InsertBranch(cdata, entrypoint, label, insertafter,
726 prepend)
727
728 return newnode
729
731 """Make a new label that is appropriate for a new node."""
732
733
734 siblings = self.GetChildren(entrypoint)
735 labels = map(self.GetItemText, siblings)
736 match = "_copy\d*$"
737 label = re.sub(match, '', oldlabel)
738 label += "_copy"
739 label = incrementName(label, labels)
740 return label
741
742 - def __InsertBranch(self, cdata, entrypoint, label, insertafter = None,
743 prepend = False):
744 """Instert control data into the tree.
745
746 cdata -- The control data that goes with the branch
747 entrypoint -- The subbranch (fit root) to paste into
748 label -- The label of the new node
749 insertafter -- A node after which to insert. If insertafter is None
750 (default), then the new node will be pasted after the
751 last node of the same type.
752 prepend -- Prepend to the beginning of the node group (default
753 False). insertafter takes prescedent over prepend.
754
755 Returns the newly inserted node.
756 """
757 if cdata is None:
758 message = "There is no branch to paste!"
759 raise FitTreeError, message
760
761 branchtype = cdata.type
762
763 if branchtype == 'fit':
764 cdata.name = label
765 newnode = self.ExtendProjectTree([cdata.organization()],
766 clear=False, paste=True)
767 elif branchtype == 'phase':
768 newnode = self.AddPhase(entrypoint, label, insertafter=insertafter,
769 makedata=False, cdata=cdata)
770 elif branchtype == 'dataset':
771 newnode = self.AddDataSet(entrypoint, label, insertafter=insertafter,
772 makedata=False, cdata=cdata)
773 elif branchtype == 'calculation':
774 newnode = self.AddCalc(entrypoint, label, insertafter=insertafter,
775 makedata=False, cdata=cdata)
776 else:
777 raise FitTreeError, "Unrecognized node type: %s" % branchtype
778
779 return newnode
780
782 """Remove the subtree starting from the selected node(s)."""
783
784 branchset = [node for node in selections if self.GetNodeType(node) ==\
785 "fit"]
786
787
788 childset = []
789 for node in branchset:
790 childset.extend(self.GetChildren(node))
791
792
793 nodeset = [node for node in selections if node not in childset]
794
795 for node in nodeset:
796 cdata = self.GetControlData(node)
797 self.control.remove(cdata)
798 self.Delete(node)
799 return nodeset
800
802 """Select all nodes."""
803 self.UnselectAll()
804 fits = self.GetChildren(self.root)
805 for fit in fits:
806 children = self.GetChildren(fit)
807 self.SelectItem(fit)
808 for child in children:
809 self.SelectItem(child)
810 return
811
813 """Select all nodes of same type as passed node.
814
815 node -- Node whose type to select. If node is None (default), then
816 all fit nodes will be selected.
817 """
818 self.UnselectAll()
819 if node is None:
820
821 fits = self.GetChildren(self.root)
822 if not fits: return
823 node = fits[0]
824 typelist = self.GetAllType(node)
825 for item in typelist:
826 self.SelectItem(item)
827 return
828
830 """Extend the project tree from the treelist.
831
832 treelist -- A list of control data returned by
833 Oraganizer.organization()
834 clear -- Clear the tree before adding new nodes (default True)
835 paste -- Whether or not the cdata is being pasted from another
836 node (default False).
837
838 The treelist here is of the type returned from pdfguicontrol.load.
839 It is a list of fit lists with the following format.
840 node[0] -- fit object
841 node[1] -- list of (name, dataset) tuples
842 node[2] -- list of (name, phase) tuples
843 node[3] -- list of (name, calculation) tuples
844
845 Note that node[1] should be empty if the node is a calculation.
846
847 Returns the last insterted fit or calculation node
848 """
849
850 if clear:
851 self.DeleteAllItems()
852 self.InitializeTree()
853 roots = []
854
855
856 if not treelist: return
857
858
859 for item in treelist:
860 broot = item[0]
861 name = broot.name
862 node = self.AddFit(name, cdata = broot, paste = paste)
863
864 if node is None:
865 message = "Cannot insert data. Malformed tree list."
866 raise FitTreeError, message
867
868 roots.append(node)
869
870
871
872 phases = item[2]
873 for (name, phase) in phases:
874 self.AddPhase(node, name, makedata = False)
875 dsets = item[1]
876 for (name, set) in dsets:
877 self.AddDataSet(node, name, makedata = False)
878 calcs = item[3]
879 for (name, calc) in calcs:
880 self.AddCalc(node, name, makedata = False)
881
882 for item in roots:
883 self.Expand(item)
884 return node
885
886
887
888
889
894
895
896
897
899 """Increment the name by assigning the lowest number to the end such
900 that the name does not appear in the namelist.
901 """
902 newname = name
903 match = "\d+$"
904 counter = start
905 while newname in namelist:
906 newname = re.sub(match, '', name)
907 counter += 1
908 newname = "%s%i" % (newname, counter)
909 return newname
910
911 __id__ = "$Id: fittree.py 2980 2009-04-02 00:14:33Z juhas $"
912