Exemplo n.º 1
0
class ProchiralStatusPopup(TemporaryBasePopup):

    help_url = joinPath(getHelpUrlDir(), 'ProchiralStatus.html')

    def __init__(self, parent, chainList, chainAtomSetsDict):

        self.chainList = chainList
        self.chainAtomSetsDict = chainAtomSetsDict

        self.resParentDict = {}
        self.resParentList = []

        self.resParentChainLabelDict = {}
        self.resParentChainLabelList = {}

        self.chainResonancesDict = {}

        for resParent in self.chainAtomSetsDict.keys():
            if isinstance(resParent, NmrConstraint.NmrConstraintStore):
                strucGens = resParent.structureGenerations
                strucGenSerials = [str(sg.serial) for sg in strucGens]
                strucGenLabel = string.join(strucGenSerials, ',')
                resParentLabel = "Constraint set %d (strucGens %s)" % (
                    resParent.serial, strucGenSerials)
            else:
                resParentLabel = "Nmr project %s" % resParent.name

            self.resParentDict[resParentLabel] = resParent
            self.resParentList.append(resParentLabel)

            self.chainResonancesDict[resParent] = {}

            self.resParentChainLabelDict[resParent] = {}
            self.resParentChainLabelList[resParent] = []

            for chain in self.chainList:
                self.project = chain.root
                if self.chainAtomSetsDict[resParent].has_key(
                        chain) and self.chainAtomSetsDict[resParent][chain]:
                    chainLabel = "Molecular system '%s':Chain '%s' (molecule '%s')" % (
                        chain.molSystem.code, chain.code, chain.molecule.name)
                    self.resParentChainLabelList[resParent].append(chainLabel)
                    self.resParentChainLabelDict[resParent][chainLabel] = chain

                    self.chainResonancesDict[resParent][chain] = []

        # modal = true means that it won't continue unless this one returns value
        TemporaryBasePopup.__init__(
            self,
            parent=parent,
            title="Project '%s': " % self.project.name +
            'Set status prochiral atoms/resonances',
            modal=False,
            transient=True)

    def body(self, master):

        #
        # Setup header
        #

        row = 0

        label = Label(master, text='Select the resonance list:')
        label.grid(row=row, column=0, sticky=Tkinter.EW)

        label = Label(master, text='Select the chain:')
        label.grid(row=row, column=1, sticky=Tkinter.EW)

        row += 1

        self.resParentSelect = PulldownMenu(master,
                                            entries=self.resParentList,
                                            callback=self.setupResParentList,
                                            do_initial_callback=False)
        self.resParentSelect.grid(row=row, column=0, sticky=Tkinter.EW)

        self.chainSelect = PulldownMenu(master,
                                        entries=[],
                                        callback=self.setupProchiralList,
                                        do_initial_callback=False)
        self.chainSelect.grid(row=row, column=1, sticky=Tkinter.EW)

        row += 1

        separator = Separator(master, height=3)
        separator.setColor('black', bgColor='black')
        separator.grid(row=row, columnspan=2, sticky=Tkinter.EW)

        row += 1

        # THIS BIT TELLS MASTER TO CONFIGURE WINDOW ON INSIDE WIDGET!!
        master.grid_rowconfigure(row, weight=1)
        for i in range(2):
            master.grid_columnconfigure(i, weight=1)

        self.prochiralListFrame = ScrolledFrame(master,
                                                width=200,
                                                doExtraConfig=False)
        self.prochiralListFrame.grid(row=row,
                                     column=0,
                                     columnspan=2,
                                     sticky=Tkinter.NSEW)
        self.prochiralListFrameRow = row
        self.prochiralListFrameMaster = master

        row = row + 1

        texts = ['Set all', 'Set chain']
        commands = [
            self.ok, self.setStereo
        ]  # This calls 'ok' in BasePopup, this then calls 'apply' in here
        buttons = createDismissHelpButtonList(master,
                                              texts=texts,
                                              commands=commands,
                                              dismiss_text='Exit',
                                              help_url=self.help_url)
        buttons.grid(row=row, column=0, columnspan=2, sticky=Tkinter.EW)

        self.resParentSelect.callback(0, self.resParentList[0])

    def setupResParentList(self, listIndex, resParentLabel):

        resParent = self.resParentDict[resParentLabel]
        self.resParent = resParent

        self.chainSelect.setup(self.resParentChainLabelList[self.resParent], 0)
        self.chainSelect.callback(
            0, self.resParentChainLabelList[self.resParent][0])

    def setupProchiralList(self, listIndex, chainLabel):

        chain = self.resParentChainLabelDict[self.resParent][chainLabel]
        self.chain = chain

        self.prochiralListFrame.destroy()
        self.prochiralListFrame = ScrolledFrame(self.prochiralListFrameMaster,
                                                width=200,
                                                doExtraConfig=False)
        self.prochiralListFrame.grid(row=self.prochiralListFrameRow,
                                     column=0,
                                     columnspan=2,
                                     sticky=Tkinter.NSEW)

        #
        # TODO: also handle case one resonance, two atomSets!?!?
        #

        frameRow = 0
        x = y = 0

        frame = self.prochiralListFrame.frame

        self.resonanceObjects = {}
        self.resonanceLabelDict = {}

        #
        # Reuse previous settings...
        #

        if len(self.chainResonancesDict[self.resParent][chain]) == len(
                self.chainAtomSetsDict[self.resParent][chain]):
            usePreviousSettings = True
        else:
            usePreviousSettings = False

        for i in range(0, len(self.chainAtomSetsDict[self.resParent][chain])):
            atomSetGroup = self.chainAtomSetsDict[self.resParent][chain][i]

            isStereo = False
            hasResonances = False
            isValidCase = False

            resonances = []

            if usePreviousSettings and self.chainResonancesDict[
                    self.resParent][chain][i]:

                resonances = self.chainResonancesDict[
                    self.resParent][chain][i][3]
                isStereo = self.chainResonancesDict[
                    self.resParent][chain][i][0]
                hasResonances = True
                isValidCase = True

            else:

                for atomSet in atomSetGroup:
                    resonanceSets = atomSet.sortedResonanceSets()

                    if resonanceSets:
                        hasResonances = True

                        for resonanceSet in resonanceSets:
                            for resonance in resonanceSet.sortedResonances():
                                if resonance not in resonances:
                                    resonances.append(resonance)

                        if len(resonanceSets) == 1:
                            isValidCase = True
                            if len(resonanceSet.atomSets) == 1:
                                isStereo = True

                    else:
                        # Case only one resonance but stereo assigned
                        resonances.append(0)

                if len(resonances) == 1:
                    # Case only one resonance, not stereo assigned
                    resonances.append(None)

            #
            # Set up only for valid cases
            #

            if hasResonances and isValidCase:

                if not usePreviousSettings:
                    self.chainResonancesDict[self.resParent][chain].append(
                        [isStereo, False, False, resonances])

                residue = atomSetGroup[0].findFirstAtom().residue
                ccpCode = residue.molResidue.ccpCode
                seqCode = residue.seqCode

                rowspan = 2

                checkButton = CheckButton(
                    frame,
                    selected=isStereo,
                    callback=lambda status=isStereo, fr=frameRow, item=i, setup
                    =False: self.toggleResonances(status, fr, item, setup))
                checkButton.grid(row=frameRow,
                                 rowspan=rowspan,
                                 column=0,
                                 sticky=Tkinter.EW)

                label = Label(frame, text=ccpCode, width=5)
                label.grid(row=frameRow,
                           rowspan=rowspan,
                           column=1,
                           sticky=Tkinter.E)
                label = Label(frame, text=str(seqCode), width=5)
                label.grid(row=frameRow,
                           rowspan=rowspan,
                           column=2,
                           sticky=Tkinter.W)

                #
                # Set up the atom names
                #

                for j in range(0, len(atomSetGroup)):
                    atomSet = atomSetGroup[j]
                    label = Label(frame, text=atomSet.name)
                    label.grid(row=frameRow + j,
                               column=3,
                               sticky=Tkinter.E,
                               ipadx=4)

                #
                # Set up the resonances
                #

                self.resonanceObjects[frameRow] = {
                    True: [[], []],
                    False: [[], []]
                }

                resonanceLabelList = []

                for resonance in resonances:

                    if not resonance:

                        resonanceLabel = 'unknown'

                    else:

                        if hasattr(resonance, 'shifts') and resonance.shifts:
                            shiftLabel = " (shifts: "

                            for shift in resonance.sortedShifts():
                                shiftLabel += "%.2f, " % shift.value

                            shiftLabel = shiftLabel[:-2] + ")"

                        else:
                            shiftLabel = ""

                        resonanceLabel = "'%d.%s'%s" % (
                            seqCode, resonance.name, shiftLabel)
                        self.resonanceLabelDict[resonanceLabel] = resonance

                    resonanceLabelList.append(resonanceLabel)

                separator = Separator(frame, height=1, width=30)
                separator.setColor('black', bgColor='black')
                separator.grid(row=frameRow, column=4, sticky=Tkinter.EW)
                self.resonanceObjects[frameRow][True][0].append(separator)

                separator = CrossLine(frame,
                                      height=20,
                                      width=30,
                                      canvas_bg=frame['bg'],
                                      color='dimgray')
                self.resonanceObjects[frameRow][False][0].append(separator)

                resonanceList = PulldownMenu(
                    frame,
                    entries=resonanceLabelList,
                    callback=lambda selInd=x, selItem=y, fr=frameRow, item=i:
                    self.setProchiralLabels(selInd, selItem, fr, item),
                    do_initial_callback=False,
                    label_color='red')
                resonanceList.grid(row=frameRow, column=5, sticky=Tkinter.EW)
                self.resonanceObjects[frameRow][True][0].append(resonanceList)

                resonanceLabel = Label(frame,
                                       text="%s" % resonanceLabelList[0],
                                       fg='dimgray')
                self.resonanceObjects[frameRow][False][0].append(
                    resonanceLabel)

                separator = Separator(frame, height=1, width=30)
                separator.setColor('black', bgColor='black')
                separator.grid(row=frameRow + 1, column=4)
                self.resonanceObjects[frameRow][True][1].append(separator)

                self.resonanceObjects[frameRow][False][1].append(None)

                resonanceLabel = Label(frame,
                                       text="%s" % resonanceLabelList[1],
                                       fg='red')
                resonanceLabel.grid(row=frameRow + 1,
                                    column=5,
                                    sticky=Tkinter.EW)
                self.resonanceObjects[frameRow][True][1].append(resonanceLabel)

                resonanceLabel = Label(frame,
                                       text="%s" % resonanceLabelList[1],
                                       fg='dimgray')
                self.resonanceObjects[frameRow][False][1].append(
                    resonanceLabel)

                if not isStereo:
                    checkButton.callback(isStereo, setup=True)

                separator = Separator(frame, height=1)
                separator.setColor('black', bgColor='black')
                separator.grid(row=frameRow + rowspan,
                               columnspan=6,
                               sticky=Tkinter.EW)

                frameRow += rowspan + 1

            elif not usePreviousSettings:
                self.chainResonancesDict[self.resParent][chain].append(None)

        return True

    def setProchiralLabels(self, selInd, selItem, fr, item):

        resonanceLabel = self.resonanceObjects[fr][True][0][1].entries[selInd]
        self.resonanceObjects[fr][False][0][1].set(resonanceLabel)

        selInd = not selInd
        resonanceLabel = self.resonanceObjects[fr][True][0][1].entries[selInd]
        self.resonanceObjects[fr][True][1][1].set(resonanceLabel)
        self.resonanceObjects[fr][False][1][1].set(resonanceLabel)

        self.chainResonancesDict[self.resParent][
            self.chain][item][2] = not self.chainResonancesDict[
                self.resParent][self.chain][item][2]
        self.chainResonancesDict[self.resParent][self.chain][item][3].reverse()

    def toggleResonances(self, status, frameRow, item, setup):

        if not setup:
            self.chainResonancesDict[self.resParent][
                self.chain][item][0] = status
            self.chainResonancesDict[self.resParent][
                self.chain][item][1] = not self.chainResonancesDict[
                    self.resParent][self.chain][item][1]

        for i in range(0, len(self.resonanceObjects[frameRow])):

            #
            # Remove other widgets from grid
            #

            rpds = self.resonanceObjects[frameRow][not status][i]
            for rpd in rpds:
                if rpd:
                    rpd.grid_forget()

            #
            # Set current widgets
            #

            rpds = self.resonanceObjects[frameRow][status][i]

            for j in range(0, len(rpds)):
                rpd = rpds[j]

                if rpd:
                    keywds = {}

                    if j == 1:
                        keywds['sticky'] = Tkinter.W

                    if j == 0:
                        if not status:
                            keywds['rowspan'] = 2

                    rpd.grid(row=frameRow + i, column=4 + j, **keywds)

    def setStereo(self, chain=None):

        if not chain:
            chain = self.chain

        if self.chainResonancesDict[self.resParent][chain]:
            for i in range(
                    0, len(self.chainResonancesDict[self.resParent][chain])):

                atomSetGroup = self.chainAtomSetsDict[self.resParent][chain][i]
                (stereoStatus, stereoStatusChanged, resChanged, resonances
                 ) = self.chainResonancesDict[self.resParent][chain][i]

                if stereoStatusChanged or (stereoStatus and resChanged):

                    residue = atomSetGroup[0].findFirstAtom().residue
                    ccpCode = residue.molResidue.ccpCode
                    seqCode = residue.seqCode

                    atomText = "%s/%s" % (atomSetGroup[0].name,
                                          atomSetGroup[1].name)

                    if stereoStatusChanged:
                        if stereoStatus:
                            stereoText = "non-stereospecific to stereospecific."
                        else:
                            stereoText = "stereospecific to non-stereospecific."

                        print "  Warning: Changed '%s.%d' prochiral resonances for atoms %s from %s" % (
                            ccpCode, seqCode, atomText, stereoText)
                        self.chainResonancesDict[
                            self.resParent][chain][i][1] = False
                        self.chainResonancesDict[
                            self.resParent][chain][i][2] = False

                        if stereoStatus:
                            resonanceSet = atomSetGroup[
                                0].findFirstResonanceSet()

                            if resonances[0]:
                                resonanceSet.removeAtomSet(atomSetGroup[1])

                            if resonances[1]:

                                if not resonances[0]:
                                    # Remove right atom set if only one resonance...
                                    resonanceSet.removeAtomSet(atomSetGroup[0])
                                else:
                                    # Only create a new resonance set if two resonances present!
                                    resonanceSet.removeResonance(resonances[1])

                                    if isinstance(
                                            self.resParent,
                                            NmrConstraint.NmrConstraintStore):
                                        newResonanceSet = self.resParent.newFixedResonanceSet(
                                            resonances=[resonances[1]],
                                            atomSets=[atomSetGroup[1]])
                                    else:
                                        newResonanceSet = self.resParent.newResonanceSet(
                                            resonances=[resonances[1]],
                                            atomSets=[atomSetGroup[1]])

                        else:

                            if resonances[0]:
                                resonanceSet = atomSetGroup[
                                    0].findFirstResonanceSet()
                                if resonances[1]:
                                    atomSetGroup[1].findFirstResonanceSet(
                                    ).delete()
                                    resonanceSet.addResonance(resonances[1])
                                resonanceSet.addAtomSet(atomSetGroup[1])

                            elif resonances[1]:
                                resonanceSet = atomSetGroup[1].resonanceSets[0]
                                resonanceSet.addAtomSet(atomSetGroup[0])

                    elif stereoStatus and resChanged:
                        print "  Warning: Changed resonance assignment for '%s.%d' stereospecifically assigned atoms %s." % (
                            ccpCode, seqCode, atomText)
                        self.chainResonancesDict[
                            self.resParent][chain][i][2] = False

                        resonanceSets = []

                        for i in range(0, 2):
                            if atomSetGroup[i].resonanceSets:
                                resonanceSets.append(
                                    atomSetGroup[i].findFirstResonanceSet())
                            else:
                                resonanceSets.append(None)

                        for i in range(0, 2):
                            resonanceSet = resonanceSets[i]

                            if resonanceSet:
                                resonanceSet.addAtomSet(atomSetGroup[not i])
                                resonanceSet.removeAtomSet(atomSetGroup[i])

    def apply(self):

        for chain in self.chainList:
            self.setStereo(chain=chain)

        return True
Exemplo n.º 2
0
class GroupChemShiftsPopup(BasePopup):

    help_url = joinPath(getHelpUrlDir(), 'GroupChemShifts.html')

    def __init__(self, parent, project):

        #
        # Info for writing file...
        #

        self.groupText = {}

        #
        # Set up molSystem information
        #

        self.project = project

        self.molSysList = list(project.sortedMolSystems())
        self.molSystems = None

        self.molSysLabelList = []
        self.molSysLabelDict = {}
        self.molSysRelationDict = {}

        molSysLabel = 'All molSystems'

        if self.setChainLabels(molSysLabel, self.molSysList):
            self.molSysLabelList.append(molSysLabel)
            self.molSysLabelDict[molSysLabel] = self.molSysList

        for molSys in self.molSysList:
            molSysLabel = '%s' % molSys.code

            if self.setChainLabels(molSysLabel, [molSys]):
                self.molSysLabelList.append(molSysLabel)
                self.molSysLabelDict[molSysLabel] = [molSys]

        if not self.molSysLabelList:
            showWarning('Warning',
                        'No chemical shift lists available! Exiting...')
            return

        #
        # Some initializing...
        #

        self.chains = None
        self.shiftList = None
        self.shiftListLabel = None
        self.results = None

        # modal = true means that it won't continue unless this one returns value
        BasePopup.__init__(self,
                           parent=parent,
                           title="Project '%s': " % project.name +
                           'Group chemical shift values',
                           modal=False,
                           transient=True)

    def setChainLabels(self, molSysLabel, molSysList):

        #
        # Set up chain information
        #

        chainLabelList = []
        chainLabelDict = {}
        chainLabelShiftListDict = {}

        self.molSysRelationDict[molSysLabel] = [
            chainLabelList, chainLabelDict, chainLabelShiftListDict
        ]

        chains = []

        for molSys in molSysList:
            chains.extend(list(molSys.sortedChains()))

        chainLabel = 'All chains'

        if self.setShiftListLabels(chainLabel, chains,
                                   self.molSysRelationDict[molSysLabel][2]):
            self.molSysRelationDict[molSysLabel][0].append(chainLabel)
            self.molSysRelationDict[molSysLabel][1][chainLabel] = chains

        for chain in chains:
            chainLabel = "'%s' (mol. '%s')" % (chain.code, chain.molecule.name)

            if self.setShiftListLabels(
                    chainLabel, [chain],
                    self.molSysRelationDict[molSysLabel][2]):
                self.molSysRelationDict[molSysLabel][0].append(chainLabel)
                self.molSysRelationDict[molSysLabel][1][chainLabel] = [chain]

        return self.molSysRelationDict[molSysLabel][0]

    def setShiftListLabels(self, chainLabel, chains, chainLabelShiftListDict):

        #
        # Set up chemical shift list information (slooooww so done at start)
        #

        shiftLists = []
        shiftListCount = {}
        resonanceTracker = []
        shiftListLabels = []
        shiftListLabelsDict = {}
        atomCount = 0

        for chain in chains:
            for residue in chain.residues:
                for atom in residue.atoms:
                    atomCount += 1
                    if atom.atomSet:
                        for resonanceSet in atom.atomSet.resonanceSets:
                            for resonance in resonanceSet.resonances:

                                if resonance in resonanceTracker:
                                    continue

                                resonanceTracker.append(resonance)

                                for shift in resonance.shifts:

                                    if shift.parentList not in shiftLists:
                                        shiftLists.append(shift.parentList)
                                        shiftListCount[shift.parentList] = 0

                                    shiftListCount[shift.parentList] += 1

        for shiftList in shiftLists:
            percentage = (shiftListCount[shift.parentList] * 100.0) / atomCount
            shiftListLabel = "%d:%s (%.1f%%)" % (shiftList.serial,
                                                 shiftList.name, percentage)
            shiftListLabels.append(shiftListLabel)
            shiftListLabelsDict[shiftListLabel] = shiftList

        chainLabelShiftListDict[chainLabel] = [
            shiftListLabels, shiftListLabelsDict
        ]

        return shiftListLabels

    def body(self, master):

        #
        # Setup header
        #

        row = 0
        self.columnSpan = 3

        label = Label(
            master,
            text=
            'Select molecular system, chains and chemical shift list to be analyzed:'
        )
        label.grid(row=row,
                   column=0,
                   columnspan=self.columnSpan,
                   sticky=Tkinter.EW)

        row += 1

        self.molSysSelect = PulldownMenu(master,
                                         entries=self.molSysLabelList,
                                         callback=self.setupChains)
        self.molSysSelect.grid(row=row, column=0, sticky=Tkinter.W)

        self.chainSelect = PulldownMenu(master,
                                        entries=self.chainLabelList,
                                        callback=self.setupShiftList)
        self.chainSelect.grid(row=row, column=1, sticky=Tkinter.W)

        self.shiftListSelect = PulldownMenu(master,
                                            entries=self.shiftListLabels,
                                            callback=self.setupPercentageFrame,
                                            do_initial_callback=False)
        self.shiftListSelect.grid(row=row, column=2, sticky=Tkinter.W)

        row += 1

        separator = Separator(master, height=3)
        separator.setColor('black', bgColor='black')
        separator.grid(row=row, columnspan=self.columnSpan, sticky=Tkinter.EW)

        row += 1

        master.grid_rowconfigure(row, weight=1)
        for i in range(self.columnSpan):
            master.grid_columnconfigure(i, weight=1)

        self.percentageFrame = ScrolledFrame(master,
                                             height=180,
                                             doExtraConfig=False)
        self.percentageFrame.grid(row=row,
                                  columnspan=self.columnSpan,
                                  sticky=Tkinter.NSEW)
        self.percentageFrameRow = row
        self.percentageFrameMaster = master

        row += 1

        separator = Separator(master, height=3)
        separator.setColor('black', bgColor='black')
        separator.grid(row=row, columnspan=self.columnSpan, sticky=Tkinter.EW)

        row += 1

        master.grid_rowconfigure(row, weight=1)
        self.resultsFrame = ScrolledFrame(master,
                                          height=180,
                                          doExtraConfig=False)
        self.resultsFrame.grid(row=row,
                               columnspan=self.columnSpan,
                               sticky=Tkinter.NSEW)
        self.resultsFrameRow = row
        self.resultsFrameMaster = master

        row += 1

        separator = Separator(master, height=3)
        separator.setColor('black', bgColor='black')
        separator.grid(row=row, columnspan=self.columnSpan, sticky=Tkinter.EW)

        row += 1

        texts = ['Recalculate', 'Write to file']
        commands = [
            self.recalc, self.writeFile
        ]  # This calls 'ok' in BasePopup, this then calls 'apply' in here
        buttons = createDismissHelpButtonList(master,
                                              texts=texts,
                                              commands=commands,
                                              dismiss_text='Exit',
                                              help_url=self.help_url)
        buttons.grid(row=row, columnspan=self.columnSpan, sticky=Tkinter.EW)

        self.shiftListSelect.callback(0, self.shiftListLabels[0])

    def setupChains(self, listIndex, molSysLabel):

        molSystems = self.molSysLabelDict[molSysLabel]

        if self.molSystems == molSystems:
            return

        self.molSystems = molSystems

        self.chainLabelList = self.molSysRelationDict[molSysLabel][0]
        self.chainLabelDict = self.molSysRelationDict[molSysLabel][1]
        self.chainLabelShiftListDict = self.molSysRelationDict[molSysLabel][2]

        if hasattr(self, 'chainSelect'):
            self.chains = None
            self.chainSelect.callback(0, self.chainLabelList[0])

    def setupShiftList(self, listIndex, chainLabel):

        chains = self.chainLabelDict[chainLabel]

        if self.chains == chains:
            return

        self.chains = chains

        #
        # Reset the pulldown menu
        #

        if hasattr(self, 'chainSelect'):
            self.chainSelect.replace(self.chainLabelList)

        #
        # Set up chemical shift lists
        #

        self.shiftListLabels = self.chainLabelShiftListDict[chainLabel][0]
        self.shiftListLabelsDict = self.chainLabelShiftListDict[chainLabel][1]

        if hasattr(self, 'percentageFrame'):
            self.shiftList = None
            self.shiftListLabel = None
            self.setupPercentageFrame(0, self.shiftListLabels[0])

    def setupPercentageFrame(self, listIndex, shiftListLabel):

        if self.shiftListLabel == shiftListLabel:
            return

        self.shiftList = self.shiftListLabelsDict[shiftListLabel]
        self.shiftListLabel = shiftListLabel

        #
        # Reset chemical shift groups...
        #

        self.shiftGroupsList = []

        for i in range(1, 10):
            shiftGroupLabel = 'Group_%s' % i
            self.shiftGroupsList.append(shiftGroupLabel)

        #
        # Reset the pulldown menu
        #

        if hasattr(self, 'shiftListSelect'):
            if hasattr(self.shiftListSelect,
                       'entries') and tuple(self.shiftListLabels) != tuple(
                           self.shiftListSelect.entries):  # HACK
                # otherwise can get infinite recursion but even with above could
                # if no self.shiftListLabels because of "None" entry in PulldownMenu
                self.shiftListSelect.replace(self.shiftListLabels)
            self.shiftListSelect.setSelected(shiftListLabel)

        #
        # Reset frame...
        #

        self.percentageFrame.destroy()
        self.percentageFrame = ScrolledFrame(self.percentageFrameMaster,
                                             height=180,
                                             doExtraConfig=False)
        self.percentageFrame.grid(row=self.percentageFrameRow,
                                  columnspan=self.columnSpan,
                                  sticky=Tkinter.NSEW)

        #
        # Recalculate results
        #

        self.results = makeChemShiftSelections(self.parent, self.chains,
                                               self.shiftList)
        resultKeys = self.results.keys()
        resultKeys.sort()

        #
        # Set up the information
        #

        frameRow = 0
        frame = self.percentageFrame.frame

        self.shiftGroupObjects = {}

        for resultKey in resultKeys:

            allAtoms = self.results[resultKey][0]
            shiftAtoms = self.results[resultKey][1]

            percentage = shiftAtoms * 100.0 / allAtoms

            label = Label(frame, text=resultKey)
            label.grid(row=frameRow, column=0, sticky=Tkinter.W)

            label = Label(frame, text="%.1f%%" % percentage)
            label.grid(row=frameRow, column=1, sticky=Tkinter.W)

            label = Label(frame, text="(%d/%d)" % (shiftAtoms, allAtoms))
            label.grid(row=frameRow, column=2, sticky=Tkinter.W)

            self.shiftGroupObjects[resultKey] = PulldownMenu(
                frame, entries=self.shiftGroupsList)
            self.shiftGroupObjects[resultKey].grid(row=frameRow,
                                                   column=3,
                                                   sticky=Tkinter.E)

            frameRow += 1

        return True

    def recalc(self):

        groups = {}
        groupsInfo = {}

        for resultKey in self.shiftGroupObjects:
            group = self.shiftGroupObjects[resultKey].getSelected()

            if not groups.has_key(group):
                groups[group] = []
                groupsInfo[group] = [0, 0]

            (allAtoms, shiftAtoms) = self.results[resultKey]
            groupsInfo[group][0] += allAtoms
            groupsInfo[group][1] += shiftAtoms

            groups[group].append(resultKey)

        #
        # Reset frame...
        #

        self.resultsFrame.destroy()
        self.resultsFrame = ScrolledFrame(self.resultsFrameMaster,
                                          height=180,
                                          doExtraConfig=False)
        self.resultsFrame.grid(row=self.resultsFrameRow,
                               columnspan=self.columnSpan,
                               sticky=Tkinter.NSEW)

        #
        # Set info in lower frame
        #

        frameRow = 0
        frame = self.resultsFrame.frame

        groupKeys = groups.keys()
        groupKeys.sort()

        self.groupText = {}

        for group in groupKeys:

            percentage = groupsInfo[group][1] * 100.0 / groupsInfo[group][0]

            label = Label(frame, text=group)
            label.grid(row=frameRow, column=0, sticky=Tkinter.W)

            label = Label(frame, text=groups[group][0])
            label.grid(row=frameRow, column=1, sticky=Tkinter.W)

            label = Label(frame, text="%.1f%%" % percentage)
            label.grid(row=frameRow, column=2, sticky=Tkinter.W)

            label = Label(frame,
                          text="(%d/%d)" %
                          (groupsInfo[group][1], groupsInfo[group][0]))
            label.grid(row=frameRow, column=3, sticky=Tkinter.W)

            self.groupText[group] = "%-10s %-20s %8.1f%% (%d/%d)%s" % (
                group, groups[group][0], percentage, groupsInfo[group][1],
                groupsInfo[group][0], newline)

            frameRow += 1

            for otherResultKey in groups[group][1:]:
                label = Label(frame, text=otherResultKey)
                label.grid(row=frameRow, column=2, sticky=Tkinter.W)

                self.groupText[group] += "%-10s %-20s%s" % ('', otherResultKey,
                                                            newline)

                frameRow += 1

        return True

    def writeFile(self):

        filePopup = FormatFilePopup(self, component='text')

        if filePopup.fileSelected:

            groupKeys = self.groupText.keys()
            groupKeys.sort()

            fout = open(filePopup.file, 'w')
            fout.write("Project: %s" % self.project.name + newline)
            fout.write("Molsystems: %s" % self.molSysSelect.getSelected() +
                       newline)
            fout.write("Chains: %s" % self.chainSelect.getSelected() + newline)
            fout.write("Shiftlist: %s" % self.shiftListSelect.getSelected() +
                       newline * 2)

            for group in groupKeys:

                fout.write(self.groupText[group])

            print "Wrote file %s..." % filePopup.file

    def apply(self):

        return True