Example #1
0
    def body(self, guiFrame):

        guiFrame.grid_columnconfigure(0, weight=1)
        guiFrame.grid_rowconfigure(1, weight=1)

        frame = LabelFrame(guiFrame, text='Options')
        frame.grid(row=0,column=0,sticky='ew')
        frame.grid_columnconfigure(5, weight=1)

        # Choose type of symmetry set to define or change (if allready present in the model)
        self.molLabel = Label(frame, text='Symmetry Operator:')
        self.molLabel.grid(row=0,column=2,sticky='w')
        self.symmCodePulldown = PulldownMenu(frame, callback=self.setSymmCode, entries=['NCS','C2','C3','C5'], do_initial_callback=False)
        self.symmCodePulldown.grid(row=0,column=3,sticky='w')

        frame = LabelFrame(guiFrame, text='Symmetry Operations')
        frame.grid(row=1,column=0,sticky='nsew')
        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        self.molSysPulldown   = PulldownMenu(self, callback=self.setMolSystem, do_initial_callback=False)
        self.chainSelect      = MultiWidget(self, CheckButton, callback=self.setChains, minRows=0, useImages=False)
        self.segStartEntry    = IntEntry(self, returnCallback=self.setSegStart, width=6)
        self.segLengthEntry   = IntEntry(self, returnCallback=self.setSegLength, width=6)

        headings = ['#','Symmetry\noperator','Mol System','Chains','Start\nresidue','Segment\nlength']  
        editWidgets      = [None, None, self.molSysPulldown, self.chainSelect, self.segStartEntry, self.segLengthEntry] 
        editGetCallbacks = [None, None, self.getMolSystem, self.getChains, self.getSegStart, self.getSegLength]
        editSetCallbacks = [None, self.setSymmCode, self.setMolSystem, self.setChains, self.setSegStart, self.setSegLength]
        
        self.symmetryMatrix = ScrolledMatrix(frame,headingList=headings,
                                             callback=self.selectSymmetry,
                                             editWidgets=editWidgets,
                                             editGetCallbacks=editGetCallbacks,
                                             editSetCallbacks=editSetCallbacks)
        self.symmetryMatrix.grid(row=0,column=0,sticky='nsew')

        texts = ['Add Symmetry Set','Remove Symmetry Set']
        commands = [self.addSymmetrySet,self.removeSymmetrySet]
        self.buttonList = createDismissHelpButtonList(guiFrame, texts=texts, commands=commands, expands=True)
        self.buttonList.grid(row=2,column=0,sticky='ew')
        
        self.updateMolPartners()
        self.notify(self.registerNotify)

        #Temporary report of parameters
        print self.molSystem
        print self.molecules
        print self.symmetrySet
        print self.symmetryOp
        print self.symmetryCode
Example #2
0
class PopupTemplate(BasePopup):

  def __init__(self, parent, project=None, *args, **kw):

    self.project = project
    self.parent  = parent
    self.objects = self.getObjects()
    self.object  = None
    
    BasePopup.__init__(self, parent=parent, title='Popup Template', **kw)
                       
    self.updateObjects()

  def body(self, mainFrame):

    mainFrame.grid_columnconfigure(1, weight=1, minsize=100)
    mainFrame.config(borderwidth=5, relief='solid')

    row = 0
    label = Label(mainFrame, text="Frame (with sub-widgets):")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    frame = Frame(mainFrame, relief='raised', border=2, background='#8080D0')
    # Frame expands East-West
    frame.grid(row=row, column=1, sticky=Tkinter.EW)
    # Last column expands => Widgets pusted to the West
    frame.grid_columnconfigure(3, weight=1)
    
    # Label is within the sub frame
    label = Label(frame, text='label ')
    label.grid(row=0, column=0, sticky=Tkinter.W)
    
    entry = Entry(frame, text='Entry', returnCallback=self.showWarning)
    entry.grid(row=0, column=1, sticky=Tkinter.W)
    
    self.check = CheckButton(frame, text='Checkbutton', selected=True, callback=self.updateObjects)
    self.check.grid(row=0, column=2, sticky=Tkinter.W)
    
    # stick a button to the East wall
    button = Button(frame, text='Button', command=self.pressButton)
    button.grid(row=0, column=3, sticky=Tkinter.E)
  
    row += 1
    label = Label(mainFrame, text="Text:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.textWindow = Text(mainFrame, text='Initial Text\n', width=60, height=5)
    self.textWindow.grid(row=row, column=1, sticky=Tkinter.NSEW)
    
    row += 1
    label = Label(mainFrame, text="CheckButtons:")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    entries = ['Alpha','Beta','Gamma','Delta']
    selected = entries[2:]
    self.checkButtons = CheckButtons(mainFrame, entries, selected=selected,select_callback=self.changedCheckButtons)
    self.checkButtons.grid(row=row, column=1, sticky=Tkinter.W)
  
    row += 1
    label = Label(mainFrame, text="PartitionedSelector:")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    labels   = ['Bool','Int','Float','String']
    objects  = [type(0),type(1),type(1.0),type('a')]
    selected = [type('a')]
    self.partitionedSelector= PartitionedSelector(mainFrame, labels=labels,
                                                  objects=objects,
                                                  colors = ['red','yellow','green','#000080'],
                                                  callback=self.toggleSelector,selected=selected)
    self.partitionedSelector.grid(row=row, column=1, sticky=Tkinter.EW)

    row += 1
    label = Label(mainFrame, text="PulldownMenu")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    
    entries = ['Frodo','Pipin','Merry','Sam','Bill','Gandalf','Strider','Gimli','Legolas']
    self.pulldownMenu = PulldownMenu(mainFrame, callback=self.selectPulldown,
                                     entries=entries, selected_index=2,
                                     do_initial_callback=False)
    self.pulldownMenu.grid(row=row, column=1, sticky=Tkinter.W)

    row += 1
    label = Label(mainFrame, text="RadioButtons in a\nScrolledFrame.frame:")
    label.grid(row=row, column=0, sticky=Tkinter.EW)
    
    frame = ScrolledFrame(mainFrame, yscroll = False, doExtraConfig = True, width=100)
    frame.grid(row=row, column=1, sticky=Tkinter.EW)
    frame.grid_columnconfigure(0, weight=1)

    self.radioButtons = RadioButtons(frame.frame, entries=entries,
                                     select_callback=self.checkRadioButtons,
                                     selected_index=1, relief='groove')
    self.radioButtons.grid(row=0, column=0, sticky=Tkinter.W)
    
    row += 1
    label = Label(mainFrame, text="LabelFrame with\nToggleLabels inside:")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    labelFrame = LabelFrame(mainFrame, text='Frame Title')
    labelFrame.grid(row=row, column=1, sticky=Tkinter.NSEW)
    labelFrame.grid_rowconfigure(0, weight=1)
    labelFrame.grid_columnconfigure(3, weight=1)
    
        
    self.toggleLabel1 = ToggleLabel(labelFrame, text='ScrolledMatrix', callback=self.toggleFrame1)
    self.toggleLabel1.grid(row=0, column=0, sticky=Tkinter.W)
    self.toggleLabel1.arrowOn()

    self.toggleLabel2 = ToggleLabel(labelFrame, text='ScrolledGraph', callback=self.toggleFrame2)
    self.toggleLabel2.grid(row=0, column=1, sticky=Tkinter.W)

    self.toggleLabel3 = ToggleLabel(labelFrame, text='ScrolledCanvas', callback=self.toggleFrame3)
    self.toggleLabel3.grid(row=0, column=2, sticky=Tkinter.W)
    
    row += 1
    mainFrame.grid_rowconfigure(row, weight=1)

    label = Label(mainFrame, text="changing/shrinking frames:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    
    self.toggleRow = row
    self.toggleFrame = Frame(mainFrame)
    self.toggleFrame.grid(row=row, column=1, sticky=Tkinter.NSEW)
    self.toggleFrame.grid_rowconfigure(0, weight=1)
    self.toggleFrame.grid_columnconfigure(0, weight=1)
    
    # option 1
    
    self.intEntry = IntEntry(self, returnCallback = self.setNumber, width=8)
    
    self.multiWidget = MultiWidget(self, Entry, options=None, 
                                  values=None, callback=self.setKeywords,
                                  minRows=3, maxRows=5)

    editWidgets      = [None, None, self.intEntry,  self.multiWidget]
    editGetCallbacks = [None, None, self.getNumber, self.getKeywords]
    editSetCallbacks = [None, None, self.setNumber, self.setKeywords]
    
    headingList = ['Name','Color','Number','Keywords']
    self.scrolledMatrix = ScrolledMatrix(self.toggleFrame, headingList=headingList,
                                         editSetCallbacks=editSetCallbacks,
                                         editGetCallbacks=editGetCallbacks,
                                         editWidgets=editWidgets,
                                         callback=self.selectObject,
                                         multiSelect=False) 
                                         
    self.scrolledMatrix.grid(row=0, column=0, sticky=Tkinter.NSEW)

    # option 2
    self.scrolledGraph = ScrolledGraph(self.toggleFrame, width=400,
                                       height=300, symbolSize=5,
                                       symbols=['square','circle'],
                                       dataColors=['#000080','#800000'],
                                       lineWidths=[0,1] )

    self.scrolledGraph.setZoom(1.3)

    dataSet1 = [[0,0],[1,1],[2,4],[3,9],[4,16],[5,25]]
    dataSet2 = [[0,0],[1,3],[2,6],[3,9],[4,12],[5,15]]
    self.scrolledGraph.update(dataSets=[dataSet1,dataSet2],
                              xLabel = 'X axis label',
                              yLabel = 'Y axis label',
                              title  = 'Main Title')
    self.scrolledGraph.draw()

    # option 3
    self.scrolledCanvas = ScrolledCanvas(self.toggleFrame,relief = 'groove', borderwidth = 2, resizeCallback=None)
    canvas = self.scrolledCanvas.canvas
    font   = 'Helvetica 10'
    box    = canvas.create_rectangle(10,10,150,200, outline='grey', fill='grey90')
    line   = canvas.create_line(0,0,200,200,fill='#800000', width=2)
    text   = canvas.create_text(120,50, text='Text', font=font, fill='black')
    circle = canvas.create_oval(30,30,50,50,outline='#008000',fill='#404040',width=3)
     
    row += 1
    label = Label(mainFrame, text="FloatEntry:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.floatEntry = FloatEntry(mainFrame, text=3.14159265, returnCallback=self.floatEntryReturn)
    self.floatEntry.grid(row=row, column=1, sticky=Tkinter.W)
    
     
    row += 1
    label = Label(mainFrame, text="Scale:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.scale = Scale(mainFrame, from_=10, to=90, value=50, orient=Tkinter.HORIZONTAL)
    self.scale.grid(row=row, column=1, sticky=Tkinter.W)

    row += 1
    label = Label(mainFrame, text="Value Ramp:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.valueRamp = ValueRamp(mainFrame, self.valueRampCallback, speed = 1.5, delay = 50)
    self.valueRamp.grid(row=row, column=1, sticky=Tkinter.W)
  

    row += 1
    label = Label(mainFrame, text="ButtonList:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    
    texts    = ['Select File','Close','Quit']
    commands = [self.selectFile, self.close, self.quit]
    bottomButtons = ButtonList(mainFrame, texts=texts, commands=commands, expands=True) 
    bottomButtons.grid(row=row, column=1, sticky=Tkinter.EW)
  
    self.protocol('WM_DELETE_WINDOW', self.quit)

  def floatEntryReturn(self, event):
  
    value = self.floatEntry.get()
    self.textWindow.setText('%s\n' % value)

  def selectObject(self, object, row, col):
  
    self.object = object

  def getKeywords(self, object):
  
    if object :
      values = object.keywords
      self.multiWidget.set(values)
  
  def setKeywords(self, event):
  
    values = self.multiWidget.get()
    self.object.keywords = values
    self.updateObjects()

  def getNumber(self, object):

    if object :
      self.intEntry.set(object.quantity)

  def setNumber(self, event):

    value = self.intEntry.get()
    self.object.quantity = value
    self.updateObjects()

  def toggleFrame1(self, isHidden):
 
    if isHidden:
      self.scrolledMatrix.grid_forget()
      self.toggleFrame.grid_forget()
    else:
      self.scrolledGraph.grid_forget()
      self.scrolledCanvas.grid_forget()
      self.scrolledMatrix.grid(row=0, column=0, sticky=Tkinter.NSEW)
      self.toggleFrame.grid(row=self.toggleRow, column=1,sticky=Tkinter.NSEW)
      self.toggleLabel2.arrowOff()
      self.toggleLabel3.arrowOff()


  def toggleFrame2(self, isHidden):
 
    if isHidden:
      self.scrolledGraph.grid_forget()
      self.toggleFrame.grid_forget()
    else:
      self.scrolledMatrix.grid_forget()
      self.scrolledCanvas.grid_forget()
      self.scrolledGraph.grid(row=0, column=0, sticky=Tkinter.NSEW)
      self.toggleFrame.grid(row=self.toggleRow, column=1,sticky=Tkinter.NSEW)
      self.toggleLabel1.arrowOff()
      self.toggleLabel3.arrowOff()

  def toggleFrame3(self, isHidden):
 
    if isHidden:
      self.scrolledCanvas.grid_forget()
      self.toggleFrame.grid_forget()
    else:
      self.scrolledMatrix.grid_forget()
      self.scrolledGraph.grid_forget()
      self.scrolledCanvas.grid(row=0, column=0, sticky=Tkinter.NSEW)
      self.toggleFrame.grid(row=self.toggleRow, column=1,sticky=Tkinter.NSEW)
      self.toggleLabel1.arrowOff()
      self.toggleLabel2.arrowOff()

 
  def valueRampCallback(self, value):
  
    self.textWindow.setText('%s\n' % value)

  def checkRadioButtons(self, value):
  
    self.textWindow.setText('%s\n' % value)

  def selectPulldown(self, index, name):
  
    self.textWindow.setText('%d, %s\n' % (index, name))

  def toggleSelector(self, value):
  
    self.textWindow.setText('%s\n' % value)

  def changedCheckButtons(self, values):
  
    self.textWindow.setText(','.join(values) + '\n')

  def getObjects(self):
  
    objects = []
    
    objects.append( Fruit('Lemon',   '#FFFF00',1,keywords=['Bitter','Tangy'] ) )
    objects.append( Fruit('Orange',  '#FF8000',4 ) )
    objects.append( Fruit('Banana',  '#FFF000',5 ) )
    objects.append( Fruit('Pinapple','#FFD000',9 ) )
    objects.append( Fruit('Kiwi',    '#008000',12) )
    objects.append( Fruit('Lime',    '#00FF00',2 ) )
    objects.append( Fruit('Apple',   '#800000',5,keywords=['Crunchy'] ) )
    objects.append( Fruit('Pear',    '#408000',6 ) )
    objects.append( Fruit('Peach',   '#FFE0C0',2,keywords=['Sweet','Furry'] ) )
    objects.append( Fruit('Plumb',   '#800080',7 ) )
    
    return objects

  def updateObjects(self, event=None):

    textMatrix = []
    objectList = []
    colorMatrix = []
    
    for object in self.objects:
      datum = []
      datum.append( object.name )
      datum.append( None )
      datum.append( object.quantity )
      datum.append( ','.join(object.keywords) )
    
      colors = [None, object.color, None, None]
    
      textMatrix.append(datum)
      objectList.append(object)
      colorMatrix.append(colors)

    if self.check.get():
      self.scrolledMatrix.update(textMatrix=textMatrix, objectList=objectList)
    else:
      self.scrolledMatrix.update(textMatrix=textMatrix, objectList=objectList, colorMatrix=colorMatrix)

  def selectFile(self):

    fileSelectPopup = FileSelectPopup(self, title = 'Choose file', dismiss_text = 'Cancel',
                                      selected_file_must_exist = True)

    fileName = fileSelectPopup.getFile()

    self.textWindow.setText('File Selected: %s\n' % fileName)

  def showWarning(self, eventObject):
  
    self.textWindow.setText('Text Entry Return Pressed\n')
    showWarning('Warning Title','Warning Message')
    return

  def pressButton(self):
  
    self.textWindow.setText('Button Pressed\n')
    if showYesNo('Title','Prompt: Clear text window?'):
       self.textWindow.clear()
       
    return

  def quit(self):
  
    BasePopup.destroy(self)  
Example #3
0
  def body(self, mainFrame):

    mainFrame.grid_columnconfigure(1, weight=1, minsize=100)
    mainFrame.config(borderwidth=5, relief='solid')

    row = 0
    label = Label(mainFrame, text="Frame (with sub-widgets):")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    frame = Frame(mainFrame, relief='raised', border=2, background='#8080D0')
    # Frame expands East-West
    frame.grid(row=row, column=1, sticky=Tkinter.EW)
    # Last column expands => Widgets pusted to the West
    frame.grid_columnconfigure(3, weight=1)
    
    # Label is within the sub frame
    label = Label(frame, text='label ')
    label.grid(row=0, column=0, sticky=Tkinter.W)
    
    entry = Entry(frame, text='Entry', returnCallback=self.showWarning)
    entry.grid(row=0, column=1, sticky=Tkinter.W)
    
    self.check = CheckButton(frame, text='Checkbutton', selected=True, callback=self.updateObjects)
    self.check.grid(row=0, column=2, sticky=Tkinter.W)
    
    # stick a button to the East wall
    button = Button(frame, text='Button', command=self.pressButton)
    button.grid(row=0, column=3, sticky=Tkinter.E)
  
    row += 1
    label = Label(mainFrame, text="Text:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.textWindow = Text(mainFrame, text='Initial Text\n', width=60, height=5)
    self.textWindow.grid(row=row, column=1, sticky=Tkinter.NSEW)
    
    row += 1
    label = Label(mainFrame, text="CheckButtons:")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    entries = ['Alpha','Beta','Gamma','Delta']
    selected = entries[2:]
    self.checkButtons = CheckButtons(mainFrame, entries, selected=selected,select_callback=self.changedCheckButtons)
    self.checkButtons.grid(row=row, column=1, sticky=Tkinter.W)
  
    row += 1
    label = Label(mainFrame, text="PartitionedSelector:")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    labels   = ['Bool','Int','Float','String']
    objects  = [type(0),type(1),type(1.0),type('a')]
    selected = [type('a')]
    self.partitionedSelector= PartitionedSelector(mainFrame, labels=labels,
                                                  objects=objects,
                                                  colors = ['red','yellow','green','#000080'],
                                                  callback=self.toggleSelector,selected=selected)
    self.partitionedSelector.grid(row=row, column=1, sticky=Tkinter.EW)

    row += 1
    label = Label(mainFrame, text="PulldownMenu")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    
    entries = ['Frodo','Pipin','Merry','Sam','Bill','Gandalf','Strider','Gimli','Legolas']
    self.pulldownMenu = PulldownMenu(mainFrame, callback=self.selectPulldown,
                                     entries=entries, selected_index=2,
                                     do_initial_callback=False)
    self.pulldownMenu.grid(row=row, column=1, sticky=Tkinter.W)

    row += 1
    label = Label(mainFrame, text="RadioButtons in a\nScrolledFrame.frame:")
    label.grid(row=row, column=0, sticky=Tkinter.EW)
    
    frame = ScrolledFrame(mainFrame, yscroll = False, doExtraConfig = True, width=100)
    frame.grid(row=row, column=1, sticky=Tkinter.EW)
    frame.grid_columnconfigure(0, weight=1)

    self.radioButtons = RadioButtons(frame.frame, entries=entries,
                                     select_callback=self.checkRadioButtons,
                                     selected_index=1, relief='groove')
    self.radioButtons.grid(row=0, column=0, sticky=Tkinter.W)
    
    row += 1
    label = Label(mainFrame, text="LabelFrame with\nToggleLabels inside:")
    label.grid(row=row, column=0, sticky=Tkinter.E)

    labelFrame = LabelFrame(mainFrame, text='Frame Title')
    labelFrame.grid(row=row, column=1, sticky=Tkinter.NSEW)
    labelFrame.grid_rowconfigure(0, weight=1)
    labelFrame.grid_columnconfigure(3, weight=1)
    
        
    self.toggleLabel1 = ToggleLabel(labelFrame, text='ScrolledMatrix', callback=self.toggleFrame1)
    self.toggleLabel1.grid(row=0, column=0, sticky=Tkinter.W)
    self.toggleLabel1.arrowOn()

    self.toggleLabel2 = ToggleLabel(labelFrame, text='ScrolledGraph', callback=self.toggleFrame2)
    self.toggleLabel2.grid(row=0, column=1, sticky=Tkinter.W)

    self.toggleLabel3 = ToggleLabel(labelFrame, text='ScrolledCanvas', callback=self.toggleFrame3)
    self.toggleLabel3.grid(row=0, column=2, sticky=Tkinter.W)
    
    row += 1
    mainFrame.grid_rowconfigure(row, weight=1)

    label = Label(mainFrame, text="changing/shrinking frames:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    
    self.toggleRow = row
    self.toggleFrame = Frame(mainFrame)
    self.toggleFrame.grid(row=row, column=1, sticky=Tkinter.NSEW)
    self.toggleFrame.grid_rowconfigure(0, weight=1)
    self.toggleFrame.grid_columnconfigure(0, weight=1)
    
    # option 1
    
    self.intEntry = IntEntry(self, returnCallback = self.setNumber, width=8)
    
    self.multiWidget = MultiWidget(self, Entry, options=None, 
                                  values=None, callback=self.setKeywords,
                                  minRows=3, maxRows=5)

    editWidgets      = [None, None, self.intEntry,  self.multiWidget]
    editGetCallbacks = [None, None, self.getNumber, self.getKeywords]
    editSetCallbacks = [None, None, self.setNumber, self.setKeywords]
    
    headingList = ['Name','Color','Number','Keywords']
    self.scrolledMatrix = ScrolledMatrix(self.toggleFrame, headingList=headingList,
                                         editSetCallbacks=editSetCallbacks,
                                         editGetCallbacks=editGetCallbacks,
                                         editWidgets=editWidgets,
                                         callback=self.selectObject,
                                         multiSelect=False) 
                                         
    self.scrolledMatrix.grid(row=0, column=0, sticky=Tkinter.NSEW)

    # option 2
    self.scrolledGraph = ScrolledGraph(self.toggleFrame, width=400,
                                       height=300, symbolSize=5,
                                       symbols=['square','circle'],
                                       dataColors=['#000080','#800000'],
                                       lineWidths=[0,1] )

    self.scrolledGraph.setZoom(1.3)

    dataSet1 = [[0,0],[1,1],[2,4],[3,9],[4,16],[5,25]]
    dataSet2 = [[0,0],[1,3],[2,6],[3,9],[4,12],[5,15]]
    self.scrolledGraph.update(dataSets=[dataSet1,dataSet2],
                              xLabel = 'X axis label',
                              yLabel = 'Y axis label',
                              title  = 'Main Title')
    self.scrolledGraph.draw()

    # option 3
    self.scrolledCanvas = ScrolledCanvas(self.toggleFrame,relief = 'groove', borderwidth = 2, resizeCallback=None)
    canvas = self.scrolledCanvas.canvas
    font   = 'Helvetica 10'
    box    = canvas.create_rectangle(10,10,150,200, outline='grey', fill='grey90')
    line   = canvas.create_line(0,0,200,200,fill='#800000', width=2)
    text   = canvas.create_text(120,50, text='Text', font=font, fill='black')
    circle = canvas.create_oval(30,30,50,50,outline='#008000',fill='#404040',width=3)
     
    row += 1
    label = Label(mainFrame, text="FloatEntry:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.floatEntry = FloatEntry(mainFrame, text=3.14159265, returnCallback=self.floatEntryReturn)
    self.floatEntry.grid(row=row, column=1, sticky=Tkinter.W)
    
     
    row += 1
    label = Label(mainFrame, text="Scale:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.scale = Scale(mainFrame, from_=10, to=90, value=50, orient=Tkinter.HORIZONTAL)
    self.scale.grid(row=row, column=1, sticky=Tkinter.W)

    row += 1
    label = Label(mainFrame, text="Value Ramp:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    self.valueRamp = ValueRamp(mainFrame, self.valueRampCallback, speed = 1.5, delay = 50)
    self.valueRamp.grid(row=row, column=1, sticky=Tkinter.W)
  

    row += 1
    label = Label(mainFrame, text="ButtonList:")
    label.grid(row=row, column=0, sticky=Tkinter.E)
    
    texts    = ['Select File','Close','Quit']
    commands = [self.selectFile, self.close, self.quit]
    bottomButtons = ButtonList(mainFrame, texts=texts, commands=commands, expands=True) 
    bottomButtons.grid(row=row, column=1, sticky=Tkinter.EW)
  
    self.protocol('WM_DELETE_WINDOW', self.quit)
Example #4
0
class EditSymmetryPopup(BasePopup):

    def __init__(self, parent, project):

        self.parent         = parent
        self.ccpnProject    = project
        self.hProject        = project.currentHaddockProject
        self.molPartner     = None
        self.molecules      = []
        self.symmetrySet    = None
        self.symmetryOp     = None
        self.symmetryCode    = None
        self.waiting        = False

        BasePopup.__init__(self, parent=parent, title='Symmetry Operations')

        self.font = 'Helvetica 12'
        self.setFont()

    def body(self, guiFrame):

        guiFrame.grid_columnconfigure(0, weight=1)
        guiFrame.grid_rowconfigure(1, weight=1)

        frame = LabelFrame(guiFrame, text='Options')
        frame.grid(row=0,column=0,sticky='ew')
        frame.grid_columnconfigure(5, weight=1)

        # Choose type of symmetry set to define or change (if allready present in the model)
        self.molLabel = Label(frame, text='Symmetry Operator:')
        self.molLabel.grid(row=0,column=2,sticky='w')
        self.symmCodePulldown = PulldownMenu(frame, callback=self.setSymmCode, entries=['NCS','C2','C3','C5'], do_initial_callback=False)
        self.symmCodePulldown.grid(row=0,column=3,sticky='w')

        frame = LabelFrame(guiFrame, text='Symmetry Operations')
        frame.grid(row=1,column=0,sticky='nsew')
        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        self.molSysPulldown   = PulldownMenu(self, callback=self.setMolSystem, do_initial_callback=False)
        self.chainSelect      = MultiWidget(self, CheckButton, callback=self.setChains, minRows=0, useImages=False)
        self.segStartEntry    = IntEntry(self, returnCallback=self.setSegStart, width=6)
        self.segLengthEntry   = IntEntry(self, returnCallback=self.setSegLength, width=6)

        headings = ['#','Symmetry\noperator','Mol System','Chains','Start\nresidue','Segment\nlength']  
        editWidgets      = [None, None, self.molSysPulldown, self.chainSelect, self.segStartEntry, self.segLengthEntry] 
        editGetCallbacks = [None, None, self.getMolSystem, self.getChains, self.getSegStart, self.getSegLength]
        editSetCallbacks = [None, self.setSymmCode, self.setMolSystem, self.setChains, self.setSegStart, self.setSegLength]
        
        self.symmetryMatrix = ScrolledMatrix(frame,headingList=headings,
                                             callback=self.selectSymmetry,
                                             editWidgets=editWidgets,
                                             editGetCallbacks=editGetCallbacks,
                                             editSetCallbacks=editSetCallbacks)
        self.symmetryMatrix.grid(row=0,column=0,sticky='nsew')

        texts = ['Add Symmetry Set','Remove Symmetry Set']
        commands = [self.addSymmetrySet,self.removeSymmetrySet]
        self.buttonList = createDismissHelpButtonList(guiFrame, texts=texts, commands=commands, expands=True)
        self.buttonList.grid(row=2,column=0,sticky='ew')
        
        self.updateMolPartners()
        self.notify(self.registerNotify)

        #Temporary report of parameters
        print self.molSystem
        print self.molecules
        print self.symmetrySet
        print self.symmetryOp
        print self.symmetryCode

    def getMolSystem(self, partner):

        """Select molecular system from list of molsystems stored in the project"""

        names = []; index = -1
        molSystem = partner.molSystem
        molSystems = self.ccpnProject.sortedMolSystems()
        if molSystems:
            names = [ms.code for ms in molSystems]
            if molSystem not in molSystems: 
                molSystem = molSystems[0]
                index = molSystems.index(molSystem)

        self.molSysPulldown.setup(names, index)

    def getChains(self, partner):
  
        names  = []
        values = []

        molSystem = partner.molSystem
        if molSystem:
            for chain in molSystem.sortedChains():
                names.append(chain.code)

                if not partner.chains:
                  values.append(True)

                elif partner.findFirstChain(chain=chain):
                  values.append(True)

                else:
                  values.append(False)   

                self.chainSelect.set(values=values,options=names)   

        else:
            showWarning('Warning','Set Mol System or ensemble first',parent=self)
            self.symmetryMatrix.keyPressEscape()        
    
    def getSegLength(self, symmetryOp):
        
        if symmetryOp and symmetryOp.segmentLength: self.segLengthEntry.set(symmetryOp.segmentLength)

    def getSegStart(self):
    
        pass

    def setMolSystem(self, partner, name=None):
  
        """Get all molsystems as stored in the project as list"""

        index =  self.molSysPulldown.getSelectedIndex()
        molSystems = self.ccpnProject.sortedMolSystems()
  
        if molSystems:
            molSystem = molSystems[index]
            self.molPartner.molSystem = molSystem
            chains = molSystem.sortedChains()
            if (not self.molPartner.chains) and chains: setPartnerChains(self.molPartner,chains)

        self.updateAllAfter()

    def setChains(self, obj):

        """Get the list of chains for the selected molsystem"""

        if self.molPartner and self.molPartner.molSystem:
            if obj is not None:
                chains = self.molPartner.molSystem.sortedChains()
                values = self.chainSelect.get()
                chains = [chains[i] for i in range(len(values)) if values[i]]
                setPartnerChains(self.molPartner,chains)

        self.symmetryMatrix.keyPressEscape()  
        self.updateAllAfter()
        
    def setSegLength(self, event):
        
        value = self.segLengthEntry.get() or 1
        self.symmetryOp.segmentLength = value

    def setSegStart(self):
        
        pass    

    def setSymmCode(self, index, name=None): 

        self.symmetryCode = self.symmCodePulldown.getSelected()    

    def selectSymmetry(self, obj, row, col):
        
        self.symmetryOp = obj
        self.updateMolSysPulldown()

    def notify(self, notifyFunc):
  
        for func in ('__init__', 'delete', 'setSymmetryCode','setSegmentLength'):
            notifyFunc(self.updateAllAfter, 'molsim.Symmetry.Symmetry', func)

        for func in ('__init__', 'delete','setfirstSeqId'):
            notifyFunc(self.updateAllAfter, 'molsim.Symmetry.Segment', func)

    def addSymmetrySet(self):
            
        if not self.ccpnProject.molSystems:
            showWarning('Warning','No molecular systems present in CCPN project',parent=self)
            return

            molSystem = self.ccpnProject.findFirstMolSystem()
            partner = self.hProject.newHaddockPartner(code=molSystem.code, molSystem=molSystem)
            setPartnerChains(partner, molSystem.chains)

            self.updateAllAfter()
            
    def removeSymmetrySet(self):
        
        pass            
    
    def updateAllAfter(self, obj=None):

        if self.waiting: return
        else:
            self.waiting = True
            self.after_idle(self.updateSymmetries,
                            self.updateMolPartners)
    
    def updateMolPartners(self):

        textMatrix = []
        objectList = []

        for partner in self.hProject.sortedHaddockPartners():
            datum = [partner.code,
                     self.symmetryCode,
                     partner.molSystem.code,
                     ','.join([c.chain.code for c in partner.chains]),
                     partner.autoHistidinePstate and 'Yes' or 'No',
                     partner.isDna and 'Yes' or 'No']
            
            objectList.append(partner)
            textMatrix.append(datum)

        self.symmetryMatrix.update(objectList=objectList, textMatrix=textMatrix)
        self.updateMolSysPulldown()
    
    def updateMolSysPulldown(self):

        names = []
        index = -1

        partners = self.hProject.sortedHaddockPartners()

        if partners:
            if self.molPartner not in partners:
                self.molPartner = partners[0]

            names = ['Partner %s' % p.code for p in partners]
            index = partners.index(self.molPartner)

        else: self.molPartner = None

        self.molSysPulldown.setup(names, index)
        
    def updateSymmetries(self):

        textMatrix  = []; objectList  = []
        if self.symmetrySet:
            for symmetryOp in self.symmetrySet.symmetries:
                chains = []; segments = [] 
                length = symmetryOp.segmentLength

                for segment in symmetryOp.sortedSegments():
                    code = segment.chainCode
                    chain = self.molSystem.findFirstChain(code=code)

                    if chain:
                        chains.append(code)
                        seqId = segment.firstSeqId
                        residue1 = chain.findFirstResidue(seqId=seqId)
                        residue2 = chain.findFirstResidue(seqId=seqId+length-1)
                        segments.append('%s:%d-%d' % (code,residue1.seqCode,residue2.seqCode))

                datum = [symmetryOp.serial, symmetryOp.symmetryCode, length, '\n'.join(chains), '\n'.join(segments)]
                objectList.append(symmetryOp)
                textMatrix.append(datum)

        self.symmetryMatrix.update(objectList=objectList, textMatrix=textMatrix)
        self.waiting = False

    def destroy(self):

        self.notify(self.unregisterNotify)
        BasePopup.destroy(self)
Example #5
0
class EditSymmetryPopup(BasePopup):
    def __init__(self, parent, project):

        self.parent = parent
        self.project = project
        self.singleMolecule = True
        self.molSystem = None
        self.molecules = []
        self.symmetrySet = None
        self.symmetryOp = None
        self.waiting = False

        BasePopup.__init__(self, parent=parent, title='Symmetry Operations')

    def body(self, guiFrame):

        guiFrame.grid_columnconfigure(0, weight=1)
        guiFrame.grid_rowconfigure(1, weight=1)

        frame = LabelFrame(guiFrame, text='Options')
        frame.grid(row=0, column=0, sticky='ew')
        frame.grid_columnconfigure(5, weight=1)

        label = Label(frame, text='MolSystem:')
        label.grid(row=0, column=0, sticky='w')
        self.molSystemPulldown = PulldownMenu(frame,
                                              callback=self.selectMolSystem)
        self.molSystemPulldown.grid(row=0, column=1, sticky='w')

        self.molLabel = Label(frame, text='Molecule:')
        self.molLabel.grid(row=0, column=2, sticky='w')
        self.moleculePulldown = PulldownMenu(frame,
                                             callback=self.selectMolecule)
        self.moleculePulldown.grid(row=0, column=3, sticky='w')

        label = Label(frame, text='Same Molecule Symmetry:')
        label.grid(row=0, column=4, sticky='w')
        self.molSelect = CheckButton(frame, callback=self.toggleSingleMolecule)
        self.molSelect.grid(row=0, column=5, sticky='w')
        self.molSelect.set(self.singleMolecule)

        frame = LabelFrame(guiFrame, text='Symmetry Operations')
        frame.grid(row=1, column=0, sticky='nsew')
        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        self.symmCodePulldown = PulldownMenu(self,
                                             callback=self.setSymmCode,
                                             do_initial_callback=False)
        self.segLengthEntry = IntEntry(self,
                                       returnCallback=self.setSegLength,
                                       width=6)
        self.setChainMulti = MultiWidget(self,
                                         CheckButton,
                                         callback=self.setChains,
                                         minRows=0,
                                         useImages=False)
        self.setSegmentMulti = MultiWidget(self,
                                           IntEntry,
                                           callback=self.setSegments,
                                           minRows=0,
                                           useImages=False)

        editWidgets = [
            None, self.symmCodePulldown, self.segLengthEntry,
            self.setChainMulti, self.setSegmentMulti
        ]
        editGetCallbacks = [
            None, self.getSymmCode, self.getSegLength, self.getChains,
            self.getSegments
        ]
        editSetCallbacks = [
            None, self.setSymmCode, self.setSegLength, self.setChains,
            self.setSegments
        ]

        headings = [
            '#', 'Symmetry\nType', 'Segment\nLength', 'Chains',
            'Segment\nPositions'
        ]
        self.symmetryMatrix = ScrolledMatrix(frame,
                                             headingList=headings,
                                             callback=self.selectSymmetry,
                                             editWidgets=editWidgets,
                                             editGetCallbacks=editGetCallbacks,
                                             editSetCallbacks=editSetCallbacks)
        self.symmetryMatrix.grid(row=0, column=0, sticky='nsew')

        texts = ['Add Symmetry Op', 'Remove Symmetrey Op']
        commands = [self.addSymmOp, self.removeSymmOp]
        buttonList = createDismissHelpButtonList(guiFrame,
                                                 texts=texts,
                                                 commands=commands,
                                                 expands=True)
        buttonList.grid(row=2, column=0, sticky='ew')

        self.updateMolSystems()
        self.updateMolecules()
        self.updateSymmetriesAfter()

        self.notify(self.registerNotify)

    def open(self):

        self.updateMolSystems()
        self.updateMolecules()
        self.updateSymmetriesAfter()

        BasePopup.open(self)

    def notify(self, notifyFunc):

        for func in ('__init__', 'delete', 'setSymmetryCode',
                     'setSegmentLength'):
            notifyFunc(self.updateSymmetriesAfter, 'molsim.Symmetry.Symmetry',
                       func)

        for func in ('__init__', 'delete', 'setfirstSeqId'):
            notifyFunc(self.updateSymmetriesAfter, 'molsim.Symmetry.Segment',
                       func)

    def getSymmCode(self, symmetryOp):
        """Get allowed symmetry operators from the model"""

        symmetryOpCodes = symmetryOp.parent.metaclass.container.getElement(
            'SymmetryOpCode').enumeration
        index = 0

        if symmetryOp.symmetryCode in symmetryOpCodes:
            index = symmetryOpCodes.index(symmetryOp.symmetryCode)

        self.symmCodePulldown.setup(symmetryOpCodes, index)

    def getSegLength(self, symmetryOp):

        if symmetryOp and symmetryOp.segmentLength:
            self.segLengthEntry.set(symmetryOp.segmentLength)

    def getChains(self, symmetryOp):

        chains = []
        for chain in self.molSystem.chains:
            if chain.residues:
                if chain.molecule in self.molecules: chains.append(chain.code)
        chains.sort()

        values = []
        for chain in chains:
            if symmetryOp.findFirstSegment(chainCode=chain):
                values.append(True)
            else:
                values.append(False)

        self.setChainMulti.set(values=values, options=chains)

    def getSegments(self, symmetryOp):

        values = []
        names = []

        if symmetryOp:
            for segment in symmetryOp.sortedSegments():
                names.append(segment.chainCode)
                values.append(segment.firstSeqId)

        n = len(values)
        self.setSegmentMulti.maxRows = n
        self.setSegmentMulti.minRows = n
        self.setSegmentMulti.set(values=values, options=names)

    def setSymmCode(self, index, name=None):
        """Set the symmetry code as NCS,C2,C3,C4,C5,C6"""

        if self.symmetryOp:
            symmCode = self.symmCodePulldown.getSelected()
            self.symmetryOp.symmetryCode = symmCode

    def setSegLength(self, event):

        value = self.segLengthEntry.get() or 1
        self.symmetryOp.segmentLength = value

    def setChains(self, obj):

        if self.symmetryOp and obj:
            codes = self.setChainMulti.options
            segment = self.symmetryOp.findFirstSegment()
            values = self.setChainMulti.get()

            if segment: seqId0 = segment.firstSeqId
            else: seqId0 = 1

            for i in range(len(values)):
                segment = self.symmetryOp.findFirstSegment(chainCode=codes[i])

                if segment and not values[i]: segment.delete()
                elif values[i] and not segment:
                    chain = self.molSystem.findFirstChain(code=codes[i])
                    residue = chain.findFirstResidue(seqid=seqId0)

                    if residue: seqId = seqId0
                    else:
                        residue = chain.sortedResidues()[0]
                        seqId = residue.seqId

                    residue2 = chain.findFirstResidue(
                        seqid=seqId + self.symmetryOp.segmentLength)
                    if not residue2:
                        residue2 = chain.sortedResidues()[-1]
                        self.symmetryOp.segmentLength = (residue2.seqId -
                                                         seqId) + 1

                    segment = self.symmetryOp.newSegment(chainCode=codes[i],
                                                         firstSeqId=seqId)

        self.symmetryMatrix.keyPressEscape()

    def setSegments(self, obj):

        if self.symmetryOp and obj:
            segments = self.symmetryOp.sortedSegments()
            values = self.setSegmentMulti.get()

            for i in range(len(values)):
                seqCode = values[i]
                chain = self.molSystem.findFirstChain(
                    code=segments[i].chainCode)
                residue = chain.findFirstResidue(seqCode=seqCode)

                if residue: seqId = residue.seqId
                if segments[i].firstSeqId != seqId:
                    segments[i].delete()
                    segments[i] = self.symmetryOp.newSegment(
                        chainCode=chain.code, firstSeqId=seqId)

        self.symmetryMatrix.keyPressEscape()

    def selectSymmetry(self, obj, row, col):

        self.symmetryOp = obj

    def addSymmOp(self):

        if self.molSystem:
            if not self.symmetrySet:
                self.symmetrySet = self.molSystem.findFirstMolSystemSymmetrySet(
                )

            if not self.symmetrySet:
                objGen = self.project.newMolSystemSymmetrySet
                self.symmetrySet = objGen(symmetrySetId=1,
                                          molSystem=self.molSystem)

            segLen = len(self.molSystem.findFirstChain().residues)
            symmetry = self.symmetrySet.newSymmetry(segmentLength=segLen)

    def removeSymmOp(self):

        if self.symmetryOp: self.symmetryOp.delete()

    def toggleSingleMolecule(self, boolean):

        self.singleMolecule = not boolean
        self.updateMolSystems()
        self.updateMolecules()

    def setMolecules(self, molecules):

        self.molecules = molecules
        if self.symmetrySet:
            for symmetryOp in self.symmetrySet.symmetries:
                for segment in symmetryOp.segments:
                    chain = self.molSystem.findFirstChain(
                        code=segment.chainCode)
                if chain and (chain.molecule not in molecules):
                    segment.delete()

    def selectMolecule(self, index, name):

        self.setMolecules(self.getMolecules()[index])
        self.updateSymmetries()

    def getMolecules(self):

        counts = {}
        moleculesList = []

        for chain in self.molSystem.chains:
            molecule = chain.molecule
            counts[molecule] = counts.get(molecule, 0) + 1

        molecules = counts.keys()
        if self.singleMolecule:
            for molecule in counts:
                if counts[molecule] > 1: moleculesList.append([
                        molecule,
                ])

        elif molecules:
            molecules = counts.keys()
            n = len(molecules)
            moleculesList.append([
                molecules[0],
            ])

            if n > 1:
                moleculesList.append([
                    molecules[1],
                ])
                moleculesList.append([molecules[0], molecules[1]])

            if n > 2:
                moleculesList.append([
                    molecules[2],
                ])
                moleculesList.append([molecules[1], molecules[2]])
                moleculesList.append(
                    [molecules[0], molecules[1], molecules[2]])

            if n > 3:
                moleculesList.append([
                    molecules[3],
                ])
                moleculesList.append([molecules[0], molecules[3]])
                moleculesList.append([molecules[1], molecules[3]])
                moleculesList.append([molecules[2], molecules[3]])
                moleculesList.append(
                    [molecules[0], molecules[1], molecules[3]])
                moleculesList.append(
                    [molecules[0], molecules[2], molecules[3]])
                moleculesList.append(
                    [molecules[1], molecules[2], molecules[3]])
                moleculesList.append(
                    [molecules[0], molecules[1], molecules[2], molecules[3]])

        return moleculesList

    def updateMolecules(self):

        names = []
        index = -1
        moleculesList = self.getMolecules()
        if moleculesList:
            if self.molecules not in moleculesList:
                self.setMolecules(moleculesList[0])
                self.symmetrySet = self.molSystem.findFirstMolSystemSymmetrySet(
                )

            index = moleculesList.index(self.molecules)

            names = []
            for molecules in moleculesList:
                names.append(','.join([mol.name for mol in molecules]))

        else:
            self.molecules = []

        self.moleculePulldown.setup(names, index)

    def selectMolSystem(self, index, name):

        self.molSystem = self.getMolSystems()[index]
        self.symmetrySet = self.molSystem.findFirstMolSystemSymmetrySet()
        self.updateSymmetries()

    def getMolSystems(self):

        molSystems = []
        for molSystem in self.project.sortedMolSystems():
            n = len(molSystem.chains)

            if self.singleMolecule and (n > 1): molSystems.append(molSystem)
            elif n > 0: molSystems.append(molSystem)

        return molSystems

    def updateMolSystems(self):

        names = []
        index = -1
        molSystems = self.getMolSystems()

        if molSystems:
            if self.molSystem not in molSystems: self.molSystem = molSystems[0]

            index = molSystems.index(self.molSystem)
            names = [ms.code for ms in molSystems]
        else:
            self.molSystem = None

        self.molSystemPulldown.setup(names, index)

    def updateSymmetriesAfter(self, obj=None):

        if self.waiting: return
        else:
            self.waiting = True
            self.after_idle(self.updateSymmetries)

    def updateSymmetries(self):

        textMatrix = []
        objectList = []
        if self.symmetrySet:
            for symmetryOp in self.symmetrySet.symmetries:
                chains = []
                segments = []
                length = symmetryOp.segmentLength

                for segment in symmetryOp.sortedSegments():
                    code = segment.chainCode
                    chain = self.molSystem.findFirstChain(code=code)

                    if chain:
                        chains.append(code)
                        seqId = segment.firstSeqId
                        residue1 = chain.findFirstResidue(seqId=seqId)
                        residue2 = chain.findFirstResidue(seqId=seqId +
                                                          length - 1)
                        segments.append(
                            '%s:%d-%d' %
                            (code, residue1.seqCode, residue2.seqCode))

                datum = [
                    symmetryOp.serial, symmetryOp.symmetryCode, length,
                    '\n'.join(chains), '\n'.join(segments)
                ]
                objectList.append(symmetryOp)
                textMatrix.append(datum)

        self.symmetryMatrix.update(objectList=objectList,
                                   textMatrix=textMatrix)
        self.waiting = False

    def destroy(self):

        self.notify(self.unregisterNotify)
        BasePopup.destroy(self)
Example #6
0
    def body(self, guiFrame):

        guiFrame.grid_columnconfigure(0, weight=1)
        guiFrame.grid_rowconfigure(1, weight=1)

        frame = LabelFrame(guiFrame, text='Options')
        frame.grid(row=0, column=0, sticky='ew')
        frame.grid_columnconfigure(5, weight=1)

        label = Label(frame, text='MolSystem:')
        label.grid(row=0, column=0, sticky='w')
        self.molSystemPulldown = PulldownMenu(frame,
                                              callback=self.selectMolSystem)
        self.molSystemPulldown.grid(row=0, column=1, sticky='w')

        self.molLabel = Label(frame, text='Molecule:')
        self.molLabel.grid(row=0, column=2, sticky='w')
        self.moleculePulldown = PulldownMenu(frame,
                                             callback=self.selectMolecule)
        self.moleculePulldown.grid(row=0, column=3, sticky='w')

        label = Label(frame, text='Same Molecule Symmetry:')
        label.grid(row=0, column=4, sticky='w')
        self.molSelect = CheckButton(frame, callback=self.toggleSingleMolecule)
        self.molSelect.grid(row=0, column=5, sticky='w')
        self.molSelect.set(self.singleMolecule)

        frame = LabelFrame(guiFrame, text='Symmetry Operations')
        frame.grid(row=1, column=0, sticky='nsew')
        frame.grid_columnconfigure(0, weight=1)
        frame.grid_rowconfigure(0, weight=1)

        self.symmCodePulldown = PulldownMenu(self,
                                             callback=self.setSymmCode,
                                             do_initial_callback=False)
        self.segLengthEntry = IntEntry(self,
                                       returnCallback=self.setSegLength,
                                       width=6)
        self.setChainMulti = MultiWidget(self,
                                         CheckButton,
                                         callback=self.setChains,
                                         minRows=0,
                                         useImages=False)
        self.setSegmentMulti = MultiWidget(self,
                                           IntEntry,
                                           callback=self.setSegments,
                                           minRows=0,
                                           useImages=False)

        editWidgets = [
            None, self.symmCodePulldown, self.segLengthEntry,
            self.setChainMulti, self.setSegmentMulti
        ]
        editGetCallbacks = [
            None, self.getSymmCode, self.getSegLength, self.getChains,
            self.getSegments
        ]
        editSetCallbacks = [
            None, self.setSymmCode, self.setSegLength, self.setChains,
            self.setSegments
        ]

        headings = [
            '#', 'Symmetry\nType', 'Segment\nLength', 'Chains',
            'Segment\nPositions'
        ]
        self.symmetryMatrix = ScrolledMatrix(frame,
                                             headingList=headings,
                                             callback=self.selectSymmetry,
                                             editWidgets=editWidgets,
                                             editGetCallbacks=editGetCallbacks,
                                             editSetCallbacks=editSetCallbacks)
        self.symmetryMatrix.grid(row=0, column=0, sticky='nsew')

        texts = ['Add Symmetry Op', 'Remove Symmetrey Op']
        commands = [self.addSymmOp, self.removeSymmOp]
        buttonList = createDismissHelpButtonList(guiFrame,
                                                 texts=texts,
                                                 commands=commands,
                                                 expands=True)
        buttonList.grid(row=2, column=0, sticky='ew')

        self.updateMolSystems()
        self.updateMolecules()
        self.updateSymmetriesAfter()

        self.notify(self.registerNotify)
Example #7
0
class IsotopeSchemeEditor(BasePopup):
    """
  **Create and Edit Per-residue Reference Isotope Schemes**
  
  This system allows the user to create schemes that describe particular
  patterns of atomic isotope labelling in terms of combinations of isotopically
  labelled forms of residues. Once constructed, these schemes may then be
  applied to a molecule of known residue sequence to gauge the levels of
  spin-active isotope incorporation in an NMR experiment. This information is
  useful in several places withing Analysis, including giving more intelligent
  assignment options and in the generation of distance restraints by matching
  peak positions to chemical shifts. Although the schemes may be used directly
  they are typically used as reference information for configuring the `Isotope
  Labelling`_ system; where isotope labelling patterns are tied to particular
  molecules and experiments.

  Because all of the different isotope labelled versions (isotopomers) of each
  residue type are described independently, a scheme can be used to estimate the
  specific amounts of incorporation present at multiple atom sites at the same
  time. For example, although a residue type may have significant levels of 13C
  at the CA and CB positions on average, there may be no form of the residue
  where CA and CB are labelled at the same time, and thus CA-CB correlations
  would not be observed in NMR.

  This popup window is divided into three main tabs, the first describes the
  overall schemes that are available; that would be applied to a molecule in a
  given situation. The second tab details the residue isotopomer components
  within the selected scheme, i.e. which labelled residue forms are present. The
  last tab displays isotopomer labelling in a graphical, three-dimensional way.
  If any isotope labelling schemes have been created or edited the user may 
  immediately save these to disk via the [Save Schemes] button to the right of
  the tabs, although these will naturally be saved when the main CCPN project
  is.

  **Reference Schemes**

  This table lists all of the reference isotope schemes that are available to
  the project. A number of standard schemes are included by default, as part of
  the main CCPN installation. However, the user is free to create new schemes,
  either from a completely blank description or by copying and modifying one of
  the existing schemes. By selecting on a isttope scheme row in the table the
  scheme is selected to be active for the whole popup and the user can see the
  contents of the scheme via the other two tabs.

  It should be noted that the user cannot edit the standard schemes provided by
  CCPN, given that these are stored with the software. Any new or copied schemes
  that the user creates will be stored inside the current CCPN project. If a new
  scheme should be made available to multiple projects, its XML file can be
  copied into the main CCPN installation, if the user has appropriate write
  access.

  **Isotopomers**
  
  The middle tab allows the user to view, and where appropriate edit, the
  isotope labelling descriptions for the residues within the current scheme
  (selected in the pulldown menu at the top). An isotope scheme is constructed
  by specifying one or more isotopomers for each residue type. Each isotopomer
  represents a different way of incorporating spin-active atom labels into a
  given kind of residue. Often there will only be one labelled form of a
  residue, and hence one isotopomer. However, with some kinds of isotope
  enrichment, for example using glycerol 13C labelled at the C2 position,
  connected labelled and unlabelled atom sites can be incorporated in
  alternative ways, resulting in distinct forms of labelling patterns that are
  not the result of a pure random mix. Knowing which labels are present at the
  same time, in the same isotopomer form, can be very important for determining
  which NMR correlations are possible.

  In general use when looking through the default, immutable reference schemes
  that come with CCPN the user can scroll through the isotopomer versions of
  each residue in the upper table. By clicking on one of these rows the lower
  table is filled with details of the amount of each kind of isotope (on
  average) at each atom site. For the lower "Atom Labels" table only one kind of
  chemical element is shown at a time, but the user may switch to  a different
  one via the "Chemical Element" pulldown.

  **Editing Isotopomers**

  When dealing with copied or new isotope schemes the user is allowed to 
  edit all aspects of the scheme. With a completely new scheme there will be no
  isotopomer records to start with and it is common practice to fill in a
  standard set of isotopomers, one for each residue type, made with a base level
  of isotope incorporation. To set this base level the user can use [Set Default
  Abundances] to manually specify values, although the default is to use natural
  abundance levels, which is appropriate in most circumstances. With the base
  levels set the [Add Default Abundance Set] will automatically fill-in a
  starting set of isotopomers for the scheme. Extra isotopomers can be added for
  a specific type of residue via the [Add New:] function and adjacent pulldown
  menu or by copying existing ones; whichever is easier. Each isotopomer has an
  editable weight to enable the user to indicate the relative abundance within a
  given residue type.

  Once a new isotopomer specification is created clicking on its row allows the 
  user to specify the isotope labelling pattern in the lower "Atom Labels"
  table. Here the user selects which kind of chemical element to consider and
  then  double-clicks to edit the "Weighting" columns in the table. The
  weightings represent the relative abundance of a given nuclear isotope at a
  given atom site. The weightings could be set as ratios, fractions, or
  percentages; it is only the relative proportion that is important. For example
  if a carbon atom site was known to have 5% Carbon-12 and 95% Carbon-13
  isotopes then the respective weights could be entered as 1 & 19 or  0.05 &
  0.95; whatever is most convenient. For efficient setup of schemes the
  [Propagate Abundances] function can be used to spread the same levels of
  incorporation over several atom sites (from the last selected row).

  **Isotopomer Structure**
  
  The last tab is an alternative way of presenting the isotope patterns present
  within the residues of the current scheme (selected in either of the first two
  tabs). Here the user selects a residue type in the upper left pulldown menu
  and then a numbered isotopomer, or an average of all isotopomers, in the right
  hand pulldown menu. The structural display will show a moveable picture of the
  residue (in a standard conformation) where unlabelled atom sites are
  represented with grey spheres, labelled sites with yellow spheres and
  intermediate incorporation with shades in between.

  It should be noted that this kind of 3D display is only possible if there is
  an idealised structure available for a residue type. This data will be 
  present for all of the regular biopolymer residues, but may be missing for
  more unusual compounds; although a lack of coordinates does not impact upon
  the isotopomer setup.

  To move and rotate the three-dimensional residue display the following
  keyboard controls may be used:
  
  * Rotate: Arrow keys
  
  * Zoom: Page Up & Page Down keys

  * Translate: Arrow keys + Control key

  Or alternatively the following mouse controls:
  
  * Rotate: Middle button click & drag
  
  * Zoom: Mouse wheel or middle button click + Shift key & drag up/down

  * Translate: Middle button click & drag + Control key

  Also an options menu appears when the right mouse button is clicked.

  .. _`Isotope Labelling`: EditMolLabellingPopup.html
 
  """
    def __init__(self, parent, project=None, *args, **kw):

        if not project:
            self.project = Implementation.MemopsRoot(
                name='defaultUtilityProject')
        else:
            self.project = project

        self.waiting = False
        self.waitingAtom = False
        self.molType = 'protein'
        self.scheme = None
        self.isotopomer = None
        self.isotopomerV = False  # Not None
        self.ccpCodeV = None
        self.element = 'C'
        self.atomLabelTuple = None
        self.isotopes = [x[0] for x in getSortedIsotopes(self.project, 'C')]
        self.defaultAbun = {}

        BasePopup.__init__(self,
                           parent=parent,
                           title='Molecule : Reference Isotope Schemes',
                           **kw)

    def body(self, guiFrame):

        self.geometry('700x600')

        guiFrame.expandGrid(0, 0)

        tipTexts = [
            'A table of all of the reference isotope scheme definitions available to the project',
            'A list of the residue isotopomers that comprise the selected isotope labelling scheme',
            'A three-dimensional representation of residues and their isotopomer labelling'
        ]

        options = ['Reference Schemes', 'Isotopomers', 'Isotopomer Structure']

        tabbedFrame = TabbedFrame(guiFrame,
                                  options=options,
                                  grid=(0, 0),
                                  tipTexts=tipTexts)

        self.tabbedFrame = tabbedFrame
        frameA, frameB, frameC = tabbedFrame.frames

        #
        # Schemes
        #

        frameA.expandGrid(0, 0)

        tipTexts = [
            'A short textual code that identifies the reference isotope scheme in graphical displays',
            'The full name for the isotope scheme',
            'A detailed description of the isotope scheme including user comments',
            'The name of the CCPN data repository in which the isotope scheme is saved; "refData" is in the CCPn installation'
        ]
        headingList = ['Code', 'Name', 'Description', 'Save Location']
        self.schemeNameEntry = Entry(self,
                                     text='',
                                     returnCallback=self.setSchemeName,
                                     width=20)
        self.schemeDetailsEntry = Entry(self,
                                        text='',
                                        returnCallback=self.setSchemeDetails,
                                        width=20)
        editWidgets = [
            None, self.schemeNameEntry, self.schemeDetailsEntry, None
        ]
        editGetCallbacks = [
            None, self.getSchemeName, self.getSchemeDetails, None
        ]
        editSetCallbacks = [
            None, self.setSchemeName, self.setSchemeDetails, None
        ]

        self.schemeMatrix = ScrolledMatrix(frameA,
                                           headingList=headingList,
                                           callback=self.selectScheme,
                                           editWidgets=editWidgets,
                                           editSetCallbacks=editSetCallbacks,
                                           editGetCallbacks=editGetCallbacks,
                                           multiSelect=False,
                                           grid=(0, 0),
                                           tipTexts=tipTexts)
        self.schemeMatrix.doEditMarkExtraRules = self.schemeEditRules

        tipTexts = [
            'Make a new reference isotope scheme definition based on a copy of the scheme currently selected',
            'Delete the selected isotope scheme',
            'Make a new, blank isotope scheme'
        ]
        texts = ['Copy', 'Delete', 'New']
        commands = [self.copyScheme, self.removeScheme, self.makeNewScheme]
        self.schemeButtons = ButtonList(frameA,
                                        texts=texts,
                                        commands=commands,
                                        grid=(1, 0),
                                        tipTexts=tipTexts)

        #
        # Isotopomers
        #

        frameB.expandGrid(3, 0)

        row = 0
        frame = Frame(frameB, grid=(row, 0))
        frame.expandGrid(0, 2)

        tipText = 'Selects which of the available isotope schemes to view/edit'
        label = Label(frame, text='Reference Scheme:', grid=(0, 0))
        self.schemePulldown = PulldownList(frame,
                                           callback=self.setLabellingScheme,
                                           grid=(0, 1),
                                           tipText=tipText)
        row += 1
        div = LabelDivider(frameB, text='Isotopomers', grid=(row, 0))

        row += 1
        frame = Frame(frameB, grid=(row, 0))
        frame.expandGrid(1, 2)

        self.isotopomerFrame = frame
        self.abundanceWidget = MultiWidget(self,
                                           FloatEntry,
                                           relief='raised',
                                           borderwidth=2,
                                           callback=self.setDefaultAbundances,
                                           useImages=False)

        tipText = 'Opens a panel that allows you to set the basis/default abundances for C, H & N isotopes; used as the starting point for new isotopomer definitions'
        self.abundanceButton = Button(frame,
                                      text='Set Default\nAbundances',
                                      borderwidth=1,
                                      command=self.enterDefaultAbundances,
                                      grid=(0, 0),
                                      tipText=tipText)

        tipText = 'Sets the basis/default abundances for C, H & N isotopes to their natural abundance proportions'
        button = Button(frame,
                        text='Set Natural\nAbundance Default',
                        borderwidth=1,
                        command=self.resetDefaultAbundance,
                        grid=(0, 1),
                        sticky='ew',
                        tipText=tipText)

        label = Label(frame, text='Molecule Type:', grid=(0, 2), sticky='e')
        entries = standardResidueCcpCodes.keys()
        entries.sort()
        entries.reverse()
        tipText = 'Selects which type of bio-polymer to define residue isotopomer labelling for'
        self.molTypePulldown = PulldownList(frame,
                                            callback=self.setMolType,
                                            texts=entries,
                                            grid=(0, 3),
                                            tipText=tipText)

        row += 1
        tipTexts = [
            'The CCPN code that identifies the kind of residue the isotopomer relates to',
            'The number of the particular isotopomer (isotope pattern) within its residue type',
            'The fraction of the total residues, of its kind, that the isotopomer make up'
        ]
        headingList = ['Ccp Code', 'Variant', 'Weight']
        self.isotopomerWeightEntry = FloatEntry(
            self, text='', returnCallback=self.setIsotopomerWeight, width=6)
        editWidgets = [None, None, self.isotopomerWeightEntry]
        editGetCallbacks = [None, None, self.getIsotopomerWeight]
        editSetCallbacks = [None, None, self.setIsotopomerWeight]

        self.isotopomerMatrix = ScrolledMatrix(
            frameB,
            tipTexts=tipTexts,
            headingList=headingList,
            callback=self.selectIsotopomer,
            editWidgets=editWidgets,
            editSetCallbacks=editSetCallbacks,
            editGetCallbacks=editGetCallbacks,
            multiSelect=True,
            grid=(row, 0))
        self.isotopomerMatrix.doEditMarkExtraRules = self.isotopomerEditRules

        row += 1
        frame = Frame(frameB, grid=(row, 0), sticky='ew')
        frame.expandGrid(0, 0)

        tipTexts = [
            'Delete the selected residue isotopomers from the current isotope scheme',
            'Make a new residue isotopomer definition by copying the details of the last selected isotopomer',
            'Add a complete set of isotopomers to the isotope scheme, one for each residue type, based on the states default isotope abundances',
            'For all residue isotopomers in the scheme, set the labelling of one kind of atom (the user is prompted) to its default isotopic incorporation ',
            'Add a new residue isotopomer definition that uses the default isotopic incorporation'
        ]

        texts = [
            'Delete\nSelected', 'Copy\nSelected', 'Add Default\nAbundance Set',
            'Set Atom Type\nTo Default', 'Add\nNew:'
        ]

        commands = [
            self.removeIsotopomers, self.duplicateResidues,
            self.addDefaultIsotopomers, self.setAtomTypeDefault,
            self.addNewIsotopomer
        ]

        self.isotopomerButtons = ButtonList(frame,
                                            texts=texts,
                                            commands=commands,
                                            grid=(0, 0),
                                            tipTexts=tipTexts)
        tipText = 'Selects which kind of residue isotopomer may be added to the current isotope scheme'
        self.ccpCodePulldown = PulldownList(frame,
                                            callback=None,
                                            grid=(0, 1),
                                            sticky='e',
                                            tipText=tipText)

        row += 1
        div = LabelDivider(frameB, text='Atom Labels', grid=(row, 0))

        row += 1
        frame = Frame(frameB, grid=(row, 0))
        frame.expandGrid(1, 3)

        label = Label(frame, text='Chemical Element:', grid=(0, 0))
        tipText = 'Selects which kind of atoms to select from the selected residue isotopomer; to display isotopic incorporation in the below table'
        self.elementPulldown = PulldownList(frame,
                                            callback=self.changeChemElement,
                                            grid=(0, 1),
                                            tipText=tipText)
        self.updateChemElements()

        label = Label(frame, text='Water Exchangeable Atoms:', grid=(0, 2))
        tipText = 'Sets whether to show atoms considered as being "water exchangeable"; their isotopic labelling will rapidly equilibrate with aqueous solvent'
        self.exchangeCheck = CheckButton(frame,
                                         callback=self.updateAtomLabelsAfter,
                                         grid=(0, 3),
                                         selected=False,
                                         tipText=tipText)
        row += 1
        # Tip texts set on update
        headingList = [
            'Atom\nName', 'Weighting\n13C'
            'Weighting\n12C', '%12C', '%13C'
        ]
        self.atomLabelTupleWeightEntry = FloatEntry(
            self, text='', width=6, returnCallback=self.setAtomLabelWeight)

        self.atomsMatrix = ScrolledMatrix(frameB,
                                          headingList=headingList,
                                          callback=self.selectAtomLabel,
                                          multiSelect=True,
                                          grid=(row, 0))
        self.atomsMatrix.doEditMarkExtraRules = self.atomsEditRules

        row += 1
        tipTexts = [
            'For the selected atom sites, in the current isotopomer, set their isotopic incorporation to the default values',
            'Spread the isotopic incorporation values from the last selected atom site to all selected atoms sites'
        ]
        texts = ['Reset Selected to Default Abundance', 'Propagate Abundances']
        commands = [self.setAtomLabelsDefault, self.propagateAbundances]
        self.atomButtons = ButtonList(frameB,
                                      texts=texts,
                                      commands=commands,
                                      grid=(row, 0),
                                      tipTexts=tipTexts)

        #
        # View Frame
        #

        frameC.expandGrid(1, 0)

        row = 0
        frame = Frame(frameC, grid=(row, 0), sticky='ew')
        frame.grid_columnconfigure(3, weight=1)

        label = Label(frame, text='Residue Type:', grid=(0, 0))
        tipText = 'Selects which kind of residue, within the current isotope scheme, to show isotopomer structures for'
        self.viewCcpCodePulldown = PulldownList(
            frame,
            callback=self.selectViewCcpcode,
            grid=(0, 1),
            tipText=tipText)

        label = Label(frame, text='Isotopomer:', grid=(0, 2))
        tipText = 'Selects which kind of isotopomer (labelling pattern) to display, from the selected residue type.'
        self.viewIsotopomerPulldown = PulldownList(
            frame,
            callback=self.selectViewIsotopomer,
            grid=(0, 3),
            tipText=tipText)

        row += 1
        self.viewIsotopomerFrame = ViewIsotopomerFrame(frameC,
                                                       None,
                                                       grid=(row, 0))

        #
        # Main
        #

        tipTexts = [
            'Save all changes to the reference isotope scheme to disk; the saves ALL changes to the CCPN installation for all projects to use',
        ]
        texts = ['Save Schemes']
        commands = [self.saveSchemes]
        self.bottomButtons = UtilityButtonList(tabbedFrame.sideFrame,
                                               texts=texts,
                                               commands=commands,
                                               helpUrl=self.help_url,
                                               grid=(0, 0),
                                               sticky='e',
                                               tipTexts=tipTexts)

        self.updateChemElements()
        self.updateCcpCodes()
        self.updateSchemes()
        self.administerNotifiers(self.registerNotify)

    def atomsEditRules(self, atomLabel, row, col):

        if self.scheme:
            return isSchemeEditable(self.scheme)

        else:
            return False

    def isotopomerEditRules(self, isotopomer, row, col):

        if self.scheme:
            return isSchemeEditable(self.scheme)

        else:
            return False

    def schemeEditRules(self, scheme, row, col):

        return isSchemeEditable(scheme)

    def administerNotifiers(self, notifyFunc):

        for func in ('__init__', 'delete', 'setLongName', 'setDetails'):
            for clazz in ('ccp.molecule.ChemCompLabel.LabelingScheme', ):
                notifyFunc(self.updateSchemes, clazz, func)

        for func in ('__init__', 'delete', 'setWeight'):
            notifyFunc(self.updateIsotopomersAfter,
                       'ccp.molecule.ChemCompLabel.Isotopomer', func)
            notifyFunc(self.updateAtomLabelsAfter,
                       'ccp.molecule.ChemCompLabel.AtomLabel', func)

    def getCcpCodeIsotopomers(self, ccpCode):

        chemCompLabel = self.scheme.findFirstChemCompLabel(
            molType=self.molType, ccpCode=ccpCode)

        if chemCompLabel:
            isotopomers = list(chemCompLabel.isotopomers)

        else:
            isotopomers = []

        return isotopomers

    def selectViewCcpcode(self, ccpCode):

        if ccpCode != self.ccpCodeV:
            self.ccpCodeV = ccpCode
            self.isotopomerV = False
            self.updateViewIsotopomerPulldown()

    def selectViewIsotopomer(self, isotopomer):

        self.isotopomerV = isotopomer

        if isotopomer is None:
            isotopomers = self.getCcpCodeIsotopomers(self.ccpCodeV)
        else:
            isotopomers = [
                isotopomer,
            ]

        self.viewIsotopomerFrame.setIsotopomers(isotopomers)

    def updateViewCcpCodePulldown(self):

        if self.scheme:
            codes = self.getCcpCodes(self.molType)

            if self.ccpCodeV not in codes:
                self.ccpCodeV = codes[0]
                self.isotopomerV = False  # Not None
                self.updateViewIsotopomerPulldown()

            index = codes.index(self.ccpCodeV)

        else:
            codes = []
            index = 0

        self.viewCcpCodePulldown.setup(codes, codes, index)

    def updateViewIsotopomerPulldown(self):

        index = 0
        isotopomers = []
        names = []

        if self.scheme:
            isotopomers = self.getCcpCodeIsotopomers(self.ccpCodeV)
            names = ['%d' % i.serial for i in isotopomers]

            isotopomers.insert(0, None)
            names.insert(0, '<All>')

            if self.isotopomerV not in isotopomers:
                self.isotopomerV = None
                isotopomers = self.getCcpCodeIsotopomers(self.ccpCodeV)
                self.viewIsotopomerFrame.setIsotopomers(isotopomers)

        self.viewIsotopomerPulldown.setup(names, isotopomers, index)

    def updateButtons(self):

        buttonsA = self.schemeButtons.buttons
        buttonsB = self.isotopomerButtons.buttons
        buttonsC = self.atomButtons.buttons

        if self.scheme:
            buttonsA[0].enable()
            isEditable = isSchemeEditable(self.scheme)

            if isEditable:
                buttonsA[1].enable()
            else:
                buttonsA[1].disable()

            buttonsB[2].enable()
            buttonsB[3].enable()
            self.bottomButtons.buttons[0].enable()

            if isEditable:
                if self.isotopomer:
                    for button in buttonsB:
                        button.enable()
                    for button in buttonsC:
                        button.enable()

                else:
                    buttonsB[0].disable()
                    buttonsB[1].disable()
                    buttonsB[3].disable()
                    buttonsC[0].disable()
                    buttonsC[1].disable()

                    buttonsB[2].enable()
                    buttonsB[4].enable()

            else:
                for button in buttonsB:
                    button.disable()
                for button in buttonsC:
                    button.disable()

        else:
            buttonsA[0].disable()
            buttonsA[1].disable()
            for button in buttonsB:
                button.disable()
            for button in buttonsC:
                button.disable()
            self.bottomButtons.buttons[0].disable()

    def resetDefaultAbundance(self):

        self.defaultAbun = {}

    def setDefaultAbundances(self, values):

        self.abundanceWidget.place_forget()

        if values is not None:
            i = 0
            for element in elementSymbols:  # TBD getAllIsotopes
                for code, isotope in getSortedIsotopes(self.project, element):
                    self.defaultAbun[isotope] = values[i]
                    i += 1

    def enterDefaultAbundances(self):

        x = self.isotopomerFrame.winfo_x()
        y = self.isotopomerFrame.winfo_y()
        x0 = self.abundanceButton.winfo_x()
        y0 = self.abundanceButton.winfo_y()

        values = []
        options = []

        for element in elementSymbols:  # TBD getAllIsotopes
            for code, isotope in getSortedIsotopes(self.project, element):
                options.append(code + ':')
                values.append(
                    self.defaultAbun.get(isotope, 100.0 * isotope.abundance))

        N = len(values)
        self.abundanceWidget.maxRows = N
        self.abundanceWidget.minRows = N
        self.abundanceWidget.set(values=values, options=options)
        self.abundanceWidget.place(x=x + x0, y=y + y0)

    def selectAtomLabel(self, obj, row, col):

        self.atomLabelTuple = (obj, col)

    def setMolType(self, molType):

        if molType != self.molType:
            self.molType = molType
            self.isotopomer = None
            self.updateCcpCodes()
            self.updateIsotopomers()

    def getCcpCodes(self, molType):

        codes = []
        for code in standardResidueCcpCodes[molType]:
            codes.append(code)

        codes.sort()

        return codes

    def updateCcpCodes(self):

        codes = self.getCcpCodes(self.molType)

        if self.isotopomer:
            index = codes.index(self.isotopomer.ccpCode)
        else:
            index = 0

        self.ccpCodePulldown.setup(codes, codes, index)

    def setIsotopomerWeight(self, event):

        value = self.isotopomerWeightEntry.get()

        if value is not None:
            self.isotopomer.setWeight(abs(value))

    def getIsotopomerWeight(self, isotopomer):

        if isotopomer:
            self.isotopomerWeightEntry.set(isotopomer.weight)

    def setSchemeName(self, event):

        text = self.schemeNameEntry.get()

        if text:
            text = text.strip() or None
        else:
            text = None

        self.scheme.setLongName(text)

    def getSchemeName(self, scheme):

        if scheme:
            self.schemeNameEntry.set(scheme.longName)

    def getSchemeDetails(self, scheme):

        if scheme:
            self.schemeDetailsEntry.set(scheme.details)

    def setSchemeDetails(self, event):

        text = self.schemeDetailsEntry.get()

        if text:
            text = text.strip() or None
        else:
            text = None

        self.scheme.setDetails(text)

    def updateSchemes(self, obj=None):

        textMatrix = []
        objectList = []

        for labelingScheme in self.project.sortedLabelingSchemes():

            repository = labelingScheme.findFirstActiveRepository()

            if repository:
                saveLocation = repository.name
            else:
                saveLocation = None

            line = [
                labelingScheme.name, labelingScheme.longName,
                labelingScheme.details, saveLocation
            ]

            textMatrix.append(line)
            objectList.append(labelingScheme)

        self.schemeMatrix.update(textMatrix=textMatrix, objectList=objectList)

        self.updateSchemePulldown()
        self.updateIsotopomers()

    def updateSchemePulldown(self):

        scheme = self.scheme
        schemes = self.project.sortedLabelingSchemes()
        names = [ls.longName or ls.name for ls in schemes]

        if names:
            if scheme not in schemes:
                scheme = schemes[0]

            index = schemes.index(scheme)

        else:
            index = 0
            scheme = None

        self.setLabellingScheme(scheme)
        self.schemePulldown.setup(names, schemes, index)

    def copyScheme(self):

        if self.scheme:
            name = askString('Input text', 'New Scheme Code:', '', parent=self)
            scheme = self.project.findFirstLabelingScheme(name=name)
            if scheme:
                showWarning('Failure', 'Scheme name already in use')
                return

            if name:
                newScheme = copySubTree(self.scheme,
                                        self.project,
                                        topObjectParameters={'name': name})

            else:
                showWarning('Failure', 'No name specified')

        else:
            showWarning('Failure', 'No scheme selected to copy')

    def removeScheme(self):

        if self.scheme and isSchemeEditable(self.scheme):
            self.scheme.delete()
            self.scheme = None

    def makeNewScheme(self):

        name = askString('Input text', 'New Scheme Code:', '', parent=self)

        if name:
            scheme = self.project.findFirstLabelingScheme(name=name)
            if scheme:
                showWarning('Failure', 'Scheme name already in use')
            else:
                scheme = self.project.newLabelingScheme(name=name)
                self.scheme = scheme

        else:
            showWarning('Failure', 'No name specified')

    def setLabellingScheme(self, scheme):

        if scheme is not self.scheme:
            self.scheme = scheme
            self.isotopomerV = False
            self.isotopomer = None
            self.updateIsotopomers()

    def selectScheme(self, object, row, col):

        self.setLabellingScheme(object)
        self.updateSchemePulldown()

    def open(self):

        BasePopup.open(self)

        self.updateSchemes()

    def saveSchemes(self):

        schemes = [x for x in self.project.labelingSchemes if x.isModified]

        if schemes:
            for scheme in schemes:
                scheme.save()
            showInfo('Notice', 'Successfully saved %d schemes' % len(schemes))
            self.updateSchemes()

        else:
            showWarning('Notice', 'No modified schemes to save')

    def addNewIsotopomer(self):

        if self.scheme:
            ccpCode = self.ccpCodePulldown.getObject()
            chemCompLabel = self.getChemCompLabel(self.molType, ccpCode)

            self.makeIsotopomer(chemCompLabel)

    def makeIsotopomer(self, chemCompLabel, weight=1.0):

        isotopomer = chemCompLabel.newIsotopomer(weight=weight)

        chemComp = chemCompLabel.chemComp

        for chemAtom in chemComp.chemAtoms:
            if chemAtom.elementSymbol:
                chemElement = chemAtom.chemElement
                for isotope in chemElement.isotopes:
                    code = '%d%s' % (isotope.massNumber,
                                     chemAtom.elementSymbol)
                    weight = self.defaultAbun.get(isotope,
                                                  100.0 * isotope.abundance)
                    isotopomer.newAtomLabel(name=chemAtom.name,
                                            subType=chemAtom.subType,
                                            isotopeCode=code,
                                            weight=weight)

        return isotopomer

    def getChemCompLabel(self, molType, ccpCode):

        chemCompLabel = None
        if self.scheme:
            chemCompLabel = self.scheme.findFirstChemCompLabel(molType=molType,
                                                               ccpCode=ccpCode)
            if not chemCompLabel:
                chemCompLabel = self.scheme.newChemCompLabel(molType=molType,
                                                             ccpCode=ccpCode)
        return chemCompLabel

    def selectIsotopomer(self, obj, row, col):

        self.isotopomer = obj
        self.updateChemElements()
        self.updateAtomLabels()

    def updateIsotopomersAfter(self, obj=None):

        if self.waiting:
            return
        else:
            self.waiting = True
            self.after_idle(self.updateIsotopomers)

    def updateIsotopomers(self):

        self.updateViewCcpCodePulldown()
        self.updateViewIsotopomerPulldown()

        textMatrix = []
        objectList = []

        if self.scheme:
            chemCompLabels = [(label.ccpCode, label)
                              for label in self.scheme.chemCompLabels]
            chemCompLabels.sort()

            for key, chemCompLabel in chemCompLabels:
                if chemCompLabel.molType == self.molType:
                    for isotopomer in chemCompLabel.sortedIsotopomers():

                        line = [
                            chemCompLabel.ccpCode, isotopomer.serial,
                            isotopomer.weight
                        ]

                        textMatrix.append(line)
                        objectList.append(isotopomer)

        self.isotopomerMatrix.update(textMatrix=textMatrix,
                                     objectList=objectList)
        self.updateAtomLabelsAfter()
        self.waiting = False

    def setAtomTypeDefault(self):

        if self.scheme:
            atomName = askString(
                'Query',
                'Specify atom name to set\ndefault abundance for',
                'H',
                parent=self)

            if not atomName:
                return

            atomLabels = []
            for chemCompLabel in self.scheme.chemCompLabels:
                if chemCompLabel.molType == self.molType:
                    for isotopomer in chemCompLabel.isotopomers:
                        # Multiple because of isotopes and subTypes
                        atomLabels += isotopomer.findAllAtomLabels(
                            name=atomName)

            if atomLabels:
                for atomLabel in atomLabels:
                    isotope = atomLabel.isotope
                    weight = self.defaultAbun.get(isotope,
                                                  100.0 * isotope.abundance)
                    atomLabel.weight = weight

            else:
                data = (atomName, self.scheme.name)
                msg = 'Atom name %s does not match any atoms in %s scheme isotopomers' % data
                showWarning('Failure', msg)

    def addDefaultIsotopomers(self):

        if self.scheme:
            codes = self.getCcpCodes(self.molType)

            for ccpCode in codes:
                chemCompLabel = self.getChemCompLabel(self.molType, ccpCode)

                if not chemCompLabel.isotopomers:
                    self.makeIsotopomer(chemCompLabel)

    def removeIsotopomers(self):

        isotopomers = self.isotopomerMatrix.currentObjects

        if isotopomers:
            for isotopomer in isotopomers:
                isotopomer.delete()

            self.isotopomer = None

    def duplicateResidues(self):

        isotopomers = self.isotopomerMatrix.currentObjects

        for isotopomer in isotopomers:
            chemCompLabel = isotopomer.chemCompLabel
            new = copySubTree(isotopomer, chemCompLabel)

    def updateChemElements(self):

        if self.isotopomer:
            chemCompLabel = self.isotopomer.chemCompLabel
            elementDict = {}

            for chemAtom in chemCompLabel.chemComp.chemAtoms:
                symbol = chemAtom.elementSymbol
                if symbol:
                    elementDict[symbol] = True

            names = elementDict.keys()
            names.sort()

        else:
            names = ['C', 'N', 'H']

        if self.element not in names:
            index = 0
        else:
            index = names.index(self.element)

        self.elementPulldown.setup(names, names, index)

    def updateAtomLabelsAfter(self, obj=None):

        if self.waitingAtom:
            return

        else:
            self.waitingAtom = True
            self.after_idle(self.updateAtomLabels)

    def updateAtomLabels(self):

        element = self.elementPulldown.getText()

        textMatrix = []
        objectList = []
        headingList = [
            'Atom Name',
        ]
        tipTexts = [
            'The name of the atom within its residue, for which to set isotopic abundances, within the selected isotopomer',
        ]

        isotopeCodes = [x[0] for x in getSortedIsotopes(self.project, element)]
        headingList.extend(['Weighting\n%s' % x for x in isotopeCodes])
        tip = 'The amount of %s isotope incorporation; can be a ratio, percentage or fraction (the value used is relative to the sum of all weights)'
        tipTexts.extend([tip % x for x in isotopeCodes])

        tip = 'The percentage %s isotope incorporation, calculated using stated weights'
        headingList.extend(['%%%s' % x for x in isotopeCodes])
        tipTexts.extend([tip % x for x in isotopeCodes])

        editWidgets = [
            None,
        ]
        editGetCallbacks = [
            None,
        ]
        editSetCallbacks = [
            None,
        ]
        editWidgets.extend(
            [self.atomLabelTupleWeightEntry for x in isotopeCodes])
        editGetCallbacks.extend(
            [self.getAtomLabelWeight for x in isotopeCodes])
        editSetCallbacks.extend(
            [self.setAtomLabelWeight for x in isotopeCodes])
        editWidgets.extend([None for x in isotopeCodes])
        editGetCallbacks.extend([None for x in isotopeCodes])
        editSetCallbacks.extend([None for x in isotopeCodes])

        doExchangeable = self.exchangeCheck.get()

        if self.isotopomer:

            atomDict = {}
            for atomLabel in self.isotopomer.sortedAtomLabels():
                if atomLabel.chemAtom.elementSymbol == element:
                    if (not doExchangeable) and (
                            atomLabel.chemAtom.waterExchangeable):
                        continue

                    name = atomLabel.name
                    subType = atomLabel.subType
                    atomDict[(name, subType)] = True

            atomNames = atomDict.keys()
            atomNames = greekSortAtomNames(atomNames)

            for atomName, subType in atomNames:

                if subType == 1:
                    name = atomName
                else:
                    name = '%s:%d' % (atomName, subType)

                line = [
                    name,
                ]
                atomLabels = []

                sumWeights = 0.0
                for isotope in isotopeCodes:
                    atomLabel = self.isotopomer.findFirstAtomLabel(
                        name=atomName, subType=subType, isotopeCode=isotope)
                    atomLabels.append(atomLabel)

                    if atomLabel:
                        weight = atomLabel.weight
                        sumWeights += weight
                        line.append(weight)

                    else:
                        line.append(0.0)

                if sumWeights:
                    for atomLabel in atomLabels:
                        line.append(100.0 * atomLabel.weight / sumWeights)

                else:
                    for atomLabel in atomLabels:
                        line.append(None)

                textMatrix.append(line)
                objectList.append(atomLabels)

        self.atomsMatrix.update(textMatrix=textMatrix,
                                objectList=objectList,
                                headingList=headingList,
                                tipTexts=tipTexts,
                                editWidgets=editWidgets,
                                editGetCallbacks=editGetCallbacks,
                                editSetCallbacks=editSetCallbacks)

        self.waitingAtom = False
        self.updateButtons()

    def setAtomLabelWeight(self, event):

        value = self.atomLabelTupleWeightEntry.get()

        if value is not None:
            atomLabels, col = self.atomLabelTuple

            chemAtom = None
            for label in atomLabels:
                if label:
                    chemAtom = label.chemAtom
                    break

            atomLabel = atomLabels[col - 1]

            if chemAtom and (atomLabel is None):
                isotopeCode, isotope = getSortedIsotopes(
                    self.project, chemAtom.elementSymbol)[col - 1]
                atomLabel = self.isotopomer.newAtomLabel(
                    name=chemAtom.name,
                    subType=chemAtom.subType,
                    isotopeCode=isotopeCode,
                    weight=value)
            atomLabel.setWeight(value)

    def setAtomLabelsDefault(self):

        atomLabelTuples = self.atomsMatrix.currentObjects

        for atomLabels in atomLabelTuples:
            for atomLabel in atomLabels:
                isotope = atomLabel.isotope
                weight = self.defaultAbun.get(isotope,
                                              100.0 * isotope.abundance)

                atomLabel.weight = weight

    def propagateAbundances(self):

        atomLabels, col = self.atomLabelTuple
        atomLabelTuples = self.atomsMatrix.currentObjects

        weightDict = {}
        for atomLabel in atomLabels:
            weightDict[atomLabel.isotope] = atomLabel.weight

        for atomLabels0 in atomLabelTuples:
            if atomLabels0 != atomLabels:
                for atomLabel in atomLabels0:
                    atomLabel.weight = weightDict[atomLabel.isotope]

    def getAtomLabelWeight(self, null):

        atomLabels, col = self.atomLabelTuple

        if atomLabels and (col > 0):
            atomLabel = atomLabels[col - 1]

            if atomLabel is None:
                weight = 0.0
            else:
                weight = atomLabel.weight

            self.atomLabelTupleWeightEntry.set(weight)

    def changeChemElement(self, name):

        self.element = name
        self.isotopes = [x[0] for x in getSortedIsotopes(self.project, name)]
        self.updateAtomLabels()

    def destroy(self):

        self.administerNotifiers(self.unregisterNotify)

        BasePopup.destroy(self)
Example #8
0
    def body(self, guiFrame):

        self.geometry('700x600')

        guiFrame.expandGrid(0, 0)

        tipTexts = [
            'A table of all of the reference isotope scheme definitions available to the project',
            'A list of the residue isotopomers that comprise the selected isotope labelling scheme',
            'A three-dimensional representation of residues and their isotopomer labelling'
        ]

        options = ['Reference Schemes', 'Isotopomers', 'Isotopomer Structure']

        tabbedFrame = TabbedFrame(guiFrame,
                                  options=options,
                                  grid=(0, 0),
                                  tipTexts=tipTexts)

        self.tabbedFrame = tabbedFrame
        frameA, frameB, frameC = tabbedFrame.frames

        #
        # Schemes
        #

        frameA.expandGrid(0, 0)

        tipTexts = [
            'A short textual code that identifies the reference isotope scheme in graphical displays',
            'The full name for the isotope scheme',
            'A detailed description of the isotope scheme including user comments',
            'The name of the CCPN data repository in which the isotope scheme is saved; "refData" is in the CCPn installation'
        ]
        headingList = ['Code', 'Name', 'Description', 'Save Location']
        self.schemeNameEntry = Entry(self,
                                     text='',
                                     returnCallback=self.setSchemeName,
                                     width=20)
        self.schemeDetailsEntry = Entry(self,
                                        text='',
                                        returnCallback=self.setSchemeDetails,
                                        width=20)
        editWidgets = [
            None, self.schemeNameEntry, self.schemeDetailsEntry, None
        ]
        editGetCallbacks = [
            None, self.getSchemeName, self.getSchemeDetails, None
        ]
        editSetCallbacks = [
            None, self.setSchemeName, self.setSchemeDetails, None
        ]

        self.schemeMatrix = ScrolledMatrix(frameA,
                                           headingList=headingList,
                                           callback=self.selectScheme,
                                           editWidgets=editWidgets,
                                           editSetCallbacks=editSetCallbacks,
                                           editGetCallbacks=editGetCallbacks,
                                           multiSelect=False,
                                           grid=(0, 0),
                                           tipTexts=tipTexts)
        self.schemeMatrix.doEditMarkExtraRules = self.schemeEditRules

        tipTexts = [
            'Make a new reference isotope scheme definition based on a copy of the scheme currently selected',
            'Delete the selected isotope scheme',
            'Make a new, blank isotope scheme'
        ]
        texts = ['Copy', 'Delete', 'New']
        commands = [self.copyScheme, self.removeScheme, self.makeNewScheme]
        self.schemeButtons = ButtonList(frameA,
                                        texts=texts,
                                        commands=commands,
                                        grid=(1, 0),
                                        tipTexts=tipTexts)

        #
        # Isotopomers
        #

        frameB.expandGrid(3, 0)

        row = 0
        frame = Frame(frameB, grid=(row, 0))
        frame.expandGrid(0, 2)

        tipText = 'Selects which of the available isotope schemes to view/edit'
        label = Label(frame, text='Reference Scheme:', grid=(0, 0))
        self.schemePulldown = PulldownList(frame,
                                           callback=self.setLabellingScheme,
                                           grid=(0, 1),
                                           tipText=tipText)
        row += 1
        div = LabelDivider(frameB, text='Isotopomers', grid=(row, 0))

        row += 1
        frame = Frame(frameB, grid=(row, 0))
        frame.expandGrid(1, 2)

        self.isotopomerFrame = frame
        self.abundanceWidget = MultiWidget(self,
                                           FloatEntry,
                                           relief='raised',
                                           borderwidth=2,
                                           callback=self.setDefaultAbundances,
                                           useImages=False)

        tipText = 'Opens a panel that allows you to set the basis/default abundances for C, H & N isotopes; used as the starting point for new isotopomer definitions'
        self.abundanceButton = Button(frame,
                                      text='Set Default\nAbundances',
                                      borderwidth=1,
                                      command=self.enterDefaultAbundances,
                                      grid=(0, 0),
                                      tipText=tipText)

        tipText = 'Sets the basis/default abundances for C, H & N isotopes to their natural abundance proportions'
        button = Button(frame,
                        text='Set Natural\nAbundance Default',
                        borderwidth=1,
                        command=self.resetDefaultAbundance,
                        grid=(0, 1),
                        sticky='ew',
                        tipText=tipText)

        label = Label(frame, text='Molecule Type:', grid=(0, 2), sticky='e')
        entries = standardResidueCcpCodes.keys()
        entries.sort()
        entries.reverse()
        tipText = 'Selects which type of bio-polymer to define residue isotopomer labelling for'
        self.molTypePulldown = PulldownList(frame,
                                            callback=self.setMolType,
                                            texts=entries,
                                            grid=(0, 3),
                                            tipText=tipText)

        row += 1
        tipTexts = [
            'The CCPN code that identifies the kind of residue the isotopomer relates to',
            'The number of the particular isotopomer (isotope pattern) within its residue type',
            'The fraction of the total residues, of its kind, that the isotopomer make up'
        ]
        headingList = ['Ccp Code', 'Variant', 'Weight']
        self.isotopomerWeightEntry = FloatEntry(
            self, text='', returnCallback=self.setIsotopomerWeight, width=6)
        editWidgets = [None, None, self.isotopomerWeightEntry]
        editGetCallbacks = [None, None, self.getIsotopomerWeight]
        editSetCallbacks = [None, None, self.setIsotopomerWeight]

        self.isotopomerMatrix = ScrolledMatrix(
            frameB,
            tipTexts=tipTexts,
            headingList=headingList,
            callback=self.selectIsotopomer,
            editWidgets=editWidgets,
            editSetCallbacks=editSetCallbacks,
            editGetCallbacks=editGetCallbacks,
            multiSelect=True,
            grid=(row, 0))
        self.isotopomerMatrix.doEditMarkExtraRules = self.isotopomerEditRules

        row += 1
        frame = Frame(frameB, grid=(row, 0), sticky='ew')
        frame.expandGrid(0, 0)

        tipTexts = [
            'Delete the selected residue isotopomers from the current isotope scheme',
            'Make a new residue isotopomer definition by copying the details of the last selected isotopomer',
            'Add a complete set of isotopomers to the isotope scheme, one for each residue type, based on the states default isotope abundances',
            'For all residue isotopomers in the scheme, set the labelling of one kind of atom (the user is prompted) to its default isotopic incorporation ',
            'Add a new residue isotopomer definition that uses the default isotopic incorporation'
        ]

        texts = [
            'Delete\nSelected', 'Copy\nSelected', 'Add Default\nAbundance Set',
            'Set Atom Type\nTo Default', 'Add\nNew:'
        ]

        commands = [
            self.removeIsotopomers, self.duplicateResidues,
            self.addDefaultIsotopomers, self.setAtomTypeDefault,
            self.addNewIsotopomer
        ]

        self.isotopomerButtons = ButtonList(frame,
                                            texts=texts,
                                            commands=commands,
                                            grid=(0, 0),
                                            tipTexts=tipTexts)
        tipText = 'Selects which kind of residue isotopomer may be added to the current isotope scheme'
        self.ccpCodePulldown = PulldownList(frame,
                                            callback=None,
                                            grid=(0, 1),
                                            sticky='e',
                                            tipText=tipText)

        row += 1
        div = LabelDivider(frameB, text='Atom Labels', grid=(row, 0))

        row += 1
        frame = Frame(frameB, grid=(row, 0))
        frame.expandGrid(1, 3)

        label = Label(frame, text='Chemical Element:', grid=(0, 0))
        tipText = 'Selects which kind of atoms to select from the selected residue isotopomer; to display isotopic incorporation in the below table'
        self.elementPulldown = PulldownList(frame,
                                            callback=self.changeChemElement,
                                            grid=(0, 1),
                                            tipText=tipText)
        self.updateChemElements()

        label = Label(frame, text='Water Exchangeable Atoms:', grid=(0, 2))
        tipText = 'Sets whether to show atoms considered as being "water exchangeable"; their isotopic labelling will rapidly equilibrate with aqueous solvent'
        self.exchangeCheck = CheckButton(frame,
                                         callback=self.updateAtomLabelsAfter,
                                         grid=(0, 3),
                                         selected=False,
                                         tipText=tipText)
        row += 1
        # Tip texts set on update
        headingList = [
            'Atom\nName', 'Weighting\n13C'
            'Weighting\n12C', '%12C', '%13C'
        ]
        self.atomLabelTupleWeightEntry = FloatEntry(
            self, text='', width=6, returnCallback=self.setAtomLabelWeight)

        self.atomsMatrix = ScrolledMatrix(frameB,
                                          headingList=headingList,
                                          callback=self.selectAtomLabel,
                                          multiSelect=True,
                                          grid=(row, 0))
        self.atomsMatrix.doEditMarkExtraRules = self.atomsEditRules

        row += 1
        tipTexts = [
            'For the selected atom sites, in the current isotopomer, set their isotopic incorporation to the default values',
            'Spread the isotopic incorporation values from the last selected atom site to all selected atoms sites'
        ]
        texts = ['Reset Selected to Default Abundance', 'Propagate Abundances']
        commands = [self.setAtomLabelsDefault, self.propagateAbundances]
        self.atomButtons = ButtonList(frameB,
                                      texts=texts,
                                      commands=commands,
                                      grid=(row, 0),
                                      tipTexts=tipTexts)

        #
        # View Frame
        #

        frameC.expandGrid(1, 0)

        row = 0
        frame = Frame(frameC, grid=(row, 0), sticky='ew')
        frame.grid_columnconfigure(3, weight=1)

        label = Label(frame, text='Residue Type:', grid=(0, 0))
        tipText = 'Selects which kind of residue, within the current isotope scheme, to show isotopomer structures for'
        self.viewCcpCodePulldown = PulldownList(
            frame,
            callback=self.selectViewCcpcode,
            grid=(0, 1),
            tipText=tipText)

        label = Label(frame, text='Isotopomer:', grid=(0, 2))
        tipText = 'Selects which kind of isotopomer (labelling pattern) to display, from the selected residue type.'
        self.viewIsotopomerPulldown = PulldownList(
            frame,
            callback=self.selectViewIsotopomer,
            grid=(0, 3),
            tipText=tipText)

        row += 1
        self.viewIsotopomerFrame = ViewIsotopomerFrame(frameC,
                                                       None,
                                                       grid=(row, 0))

        #
        # Main
        #

        tipTexts = [
            'Save all changes to the reference isotope scheme to disk; the saves ALL changes to the CCPN installation for all projects to use',
        ]
        texts = ['Save Schemes']
        commands = [self.saveSchemes]
        self.bottomButtons = UtilityButtonList(tabbedFrame.sideFrame,
                                               texts=texts,
                                               commands=commands,
                                               helpUrl=self.help_url,
                                               grid=(0, 0),
                                               sticky='e',
                                               tipTexts=tipTexts)

        self.updateChemElements()
        self.updateCcpCodes()
        self.updateSchemes()
        self.administerNotifiers(self.registerNotify)