class EditResidues_PropertyManager(Command_PropertyManager):
    """
    The ProteinDisplayStyle_PropertyManager class provides a Property Manager
    for the B{Display Style} command on the flyout toolbar in the
    Build > Protein mode.

    @ivar title: The title that appears in the property manager header.
    @type title: str

    @ivar pmName: The name of this property manager. This is used to set
                  the name of the PM_Dialog object via setObjectName().
    @type name: str

    @ivar iconPath: The relative path to the PNG file that contains a
                    22 x 22 icon image that appears in the PM header.
    @type iconPath: str
    """

    title         =  "Edit Residues"
    pmName        =  title
    iconPath      =  "ui/actions/Command Toolbar/BuildProtein/Residues.png"

    rosetta_all_set =    "PGAVILMFWYCSTNQDEHKR"
    rosetta_polar_set =  "___________STNQDEHKR"
    rosetta_apolar_set = "PGAVILMFWYC_________"


    def __init__( self, command ):
        """
        Constructor for the property manager.
        """

        self.currentWorkingDirectory = env.prefs[workingDirectory_prefs_key]

        _superclass.__init__(self, command)

        self.sequenceEditor = self.win.createProteinSequenceEditorIfNeeded()
        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)

        self.editingItem = False
        return

    def connect_or_disconnect_signals(self, isConnect = True):

        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect

        change_connect(self.applyAnyPushButton,
                         SIGNAL("clicked()"),
                         self._applyAny)

        change_connect(self.applySamePushButton,
                         SIGNAL("clicked()"),
                         self._applySame)

        change_connect(self.applyLockedPushButton,
                         SIGNAL("clicked()"),
                         self._applyLocked)

        change_connect(self.applyPolarPushButton,
                         SIGNAL("clicked()"),
                         self._applyPolar)

        change_connect(self.applyApolarPushButton,
                         SIGNAL("clicked()"),
                         self._applyApolar)

        change_connect(self.selectAllPushButton,
                         SIGNAL("clicked()"),
                         self._selectAll)

        change_connect(self.selectNonePushButton,
                         SIGNAL("clicked()"),
                         self._selectNone)

        change_connect(self.selectInvertPushButton,
                         SIGNAL("clicked()"),
                         self._invertSelection)

        change_connect(self.applyDescriptorPushButton,
                         SIGNAL("clicked()"),
                         self._applyDescriptor)

        change_connect(self.removeDescriptorPushButton,
                         SIGNAL("clicked()"),
                         self._removeDescriptor)

        change_connect(self.sequenceTable,
                         SIGNAL("cellClicked(int, int)"),
                         self._sequenceTableCellChanged)

        change_connect(self.sequenceTable,
                         SIGNAL("itemChanged(QTableWidgetItem*)"),
                         self._sequenceTableItemChanged)

        change_connect(self.descriptorsTable,
                         SIGNAL("itemChanged(QTableWidgetItem*)"),
                         self._descriptorsTableItemChanged)

        change_connect(self.newDescriptorPushButton,
                         SIGNAL("clicked()"),
                         self._addNewDescriptor)
        change_connect(self.showSequencePushButton,
                       SIGNAL("clicked()"),
                       self._showSeqEditor)
        return

    def _showSeqEditor(self):
        """
        Shows sequence editor
        """
        if self.showSequencePushButton.isEnabled():
            self.sequenceEditor.show()
        return

    def show(self):
        """
        Shows the Property Manager. Extends superclass method.
        """
        env.history.statusbar_msg("")
        #Urmi 20080728: Set the current protein and this will be used for accessing
        #various properties of this protein
        self.set_current_protein()
        if self.current_protein:
            msg = "Editing structure <b>%s</b>." % self.current_protein.name
            self.showSequencePushButton.setEnabled(True)
        else:
            msg = "Select a single structure to edit."
            self.showSequencePushButton.setEnabled(False)
        self.sequenceEditor.hide()

        _superclass.show(self)

        self._fillSequenceTable()
        self.updateMessage(msg)

        return

    def set_current_protein(self):
        """
        Set the current protein for which all the properties are displayed to the
        one chosen in the build protein combo box
        """
        self.current_protein = self.win.assy.getSelectedProteinChunk()
        return

    def _addGroupBoxes( self ):
        """
        Add the Property Manager group boxes.
        """

        if sys.platform == "darwin":
            # Workaround for table font size difference between Mac/Win
            self.labelfont = QFont("Helvetica", 12)
            self.descriptorfont = QFont("Courier New", 12)
        else:
            self.labelfont = QFont("Helvetica", 9)
            self.descriptorfont = QFont("Courier New", 9)

        self._pmGroupBox1 = PM_GroupBox( self,
                                         title = "Descriptors")
        self._loadGroupBox1( self._pmGroupBox1 )

        self._pmGroupBox2 = PM_GroupBox( self,
                                         title = "Sequence")
        self._loadGroupBox2( self._pmGroupBox2 )


    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in the first group box.
        """

        self.headerdata_desc = ['Name', 'Descriptor']

        self.set_names = ["Any", "Same", "Locked", "Apolar", "Polar"]
        self.rosetta_set_names = ["ALLAA", "NATAA", "NATRO", "APOLA", "POLAR"]
        self.descriptor_list = ["PGAVILMFWYCSTNQDEHKR",
                                "____________________",
                                "____________________",
                                "PGAVILMFWYC_________",
                                "___________STNQDEHKR"]

        self.applyAnyPushButton = PM_PushButton( pmGroupBox,
            text       =  "ALLAA",
            setAsDefault  =  True)

        self.applySamePushButton = PM_PushButton( pmGroupBox,
            text       =  "NATAA",
            setAsDefault  =  True)

        self.applyLockedPushButton = PM_PushButton( pmGroupBox,
            text       =  "NATRO",
            setAsDefault  =  True)

        self.applyPolarPushButton = PM_PushButton( pmGroupBox,
            text       =  "APOLA",
            setAsDefault  =  True)

        self.applyApolarPushButton = PM_PushButton( pmGroupBox,
            text       =  "POLAR",
            setAsDefault  =  True)

        #self.applyBackrubPushButton = PM_PushButton( pmGroupBox,
        #    text       =  "BACKRUB",
        #    setAsDefault  =  True)

        self.applyAnyPushButton.setFixedHeight(25)
        self.applyAnyPushButton.setFixedWidth(60)

        self.applySamePushButton.setFixedHeight(25)
        self.applySamePushButton.setFixedWidth(60)

        self.applyLockedPushButton.setFixedHeight(25)
        self.applyLockedPushButton.setFixedWidth(60)

        self.applyPolarPushButton.setFixedHeight(25)
        self.applyPolarPushButton.setFixedWidth(60)

        self.applyApolarPushButton.setFixedHeight(25)
        self.applyApolarPushButton.setFixedWidth(60)

        applyButtonList = [
            ('PM_PushButton', self.applyAnyPushButton, 0, 0),
            ('PM_PushButton', self.applySamePushButton, 1, 0),
            ('PM_PushButton', self.applyLockedPushButton, 2, 0),
            ('PM_PushButton', self.applyPolarPushButton, 3, 0),
            ('PM_PushButton', self.applyApolarPushButton, 4, 0)  ]

        self.applyButtonGrid = PM_WidgetGrid( pmGroupBox,
                                              label = "Apply standard set",
                                              widgetList = applyButtonList)

        self.descriptorsTable = PM_TableWidget( pmGroupBox,
                                                label = "Custom descriptors")

        self.descriptorsTable.setFixedHeight(100)
        self.descriptorsTable.setRowCount(0)
        self.descriptorsTable.setColumnCount(2)
        self.descriptorsTable.verticalHeader().setVisible(False)
        self.descriptorsTable.horizontalHeader().setVisible(True)
        self.descriptorsTable.setGridStyle(Qt.NoPen)
        self.descriptorsTable.setHorizontalHeaderLabels(self.headerdata_desc)

        self._updateSetLists()

        self._fillDescriptorsTable()

        self.descriptorsTable.resizeColumnsToContents()

        self.newDescriptorPushButton = PM_PushButton( pmGroupBox,
            text         =  "New",
            setAsDefault  =  True)

        self.newDescriptorPushButton.setFixedHeight(25)

        self.removeDescriptorPushButton = PM_PushButton( pmGroupBox,
            text         =  "Remove",
            setAsDefault  =  True)

        self.removeDescriptorPushButton.setFixedHeight(25)

        self.applyDescriptorPushButton = PM_PushButton( pmGroupBox,
            text         =  "Apply",
            setAsDefault  =  True)

        self.applyDescriptorPushButton.setFixedHeight(25)

        addDescriptorButtonList = [('PM_PushButton', self.newDescriptorPushButton, 0, 0),
            ('PM_PushButton', self.removeDescriptorPushButton, 1, 0),
            ('PM_PushButton', self.applyDescriptorPushButton, 2, 0) ]

        self.addDescriptorGrid = PM_WidgetGrid( pmGroupBox,
                                              alignment = "Center",
                                              widgetList = addDescriptorButtonList)

    def _loadGroupBox2(self, pmGroupBox):
        """
        Load widgets in the second group box.
        """

        self.headerdata_seq = ['', 'ID', 'Set', 'BR', 'Descriptor']

        self.recenterViewCheckBox  = \
            PM_CheckBox( pmGroupBox,
                         text          =  "Re-center view on selected residue",
                         setAsDefault  =  True,
                         widgetColumn  = 0,
                         state         = Qt.Unchecked)

        self.selectAllPushButton = PM_PushButton( pmGroupBox,
            text         =  "All",
            setAsDefault  =  True)

        self.selectAllPushButton.setFixedHeight(25)

        self.selectNonePushButton = PM_PushButton( pmGroupBox,
            text       =  "None",
            setAsDefault  =  True)

        self.selectNonePushButton.setFixedHeight(25)

        self.selectInvertPushButton = PM_PushButton( pmGroupBox,
            text       =  "Invert",
            setAsDefault  =  True)

        self.selectInvertPushButton.setFixedHeight(25)

        buttonList = [ ('PM_PushButton', self.selectAllPushButton, 0, 0),
                       ('PM_PushButton', self.selectNonePushButton, 1, 0),
                       ('PM_PushButton', self.selectInvertPushButton, 2, 0)]

        self.buttonGrid = PM_WidgetGrid( pmGroupBox,
                                         widgetList = buttonList)


        self.sequenceTable = PM_TableWidget( pmGroupBox)
        #self.sequenceTable.setModel(self.tableModel)
        self.sequenceTable.resizeColumnsToContents()
        self.sequenceTable.verticalHeader().setVisible(False)
        #self.sequenceTable.setRowCount(0)
        self.sequenceTable.setColumnCount(5)

        self.checkbox = QCheckBox()


        self.sequenceTable.setFixedHeight(345)

        self.sequenceTable.setGridStyle(Qt.NoPen)

        self.sequenceTable.setHorizontalHeaderLabels(self.headerdata_seq)
        ###self._fillSequenceTable()
        self.showSequencePushButton = PM_PushButton( pmGroupBox,
            text       =  "Show Sequence",
            setAsDefault  =  True,
            spanWidth = True)


    def _addWhatsThisText( self ):
        #from ne1_ui.WhatsThisText_for_PropertyManagers import WhatsThis_EditResidues_PropertyManager
        #WhatsThis_EditResidues_PropertyManager(self)
        pass

    def _addToolTipText(self):
        #from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_EditProteinDisplayStyle_PropertyManager
        #ToolTip_EditProteinDisplayStyle_PropertyManager(self)
        pass

    def _fillSequenceTable(self):
        """
        Fills in the sequence table.
        """

        if not self.current_protein:
            return
        else:
            currentProteinChunk = self.current_protein

        self.editingItem = True

        aa_list = currentProteinChunk.protein.get_amino_acids()
        aa_list_len = len(aa_list)
        self.sequenceTable.setRowCount(aa_list_len)
        for index in range(aa_list_len):
            # Selection checkbox column
            item_widget = QTableWidgetItem("")
            item_widget.setFont(self.labelfont)
            item_widget.setCheckState(Qt.Checked)
            item_widget.setTextAlignment(Qt.AlignLeft)
            item_widget.setSizeHint(QSize(20,12))
            item_widget.setFlags(Qt.ItemIsSelectable |
                                 Qt.ItemIsEnabled |
                                 Qt.ItemIsUserCheckable)
            self.sequenceTable.setItem(index, 0, item_widget)

            # Amino acid index column
            item_widget = QTableWidgetItem(str(index+1))
            item_widget.setFont(self.labelfont)
            item_widget.setFlags(
                Qt.ItemIsSelectable |
                Qt.ItemIsEnabled)
            item_widget.setTextAlignment(Qt.AlignCenter)
            self.sequenceTable.setItem(index, 1, item_widget)

            # Mutation descriptor name column
            aa = self._get_aa_for_index(index)
            item_widget = QTableWidgetItem(self._get_descriptor_name(aa))
            item_widget.setFont(self.labelfont)
            item_widget.setFlags(Qt.ItemIsSelectable |
                                 Qt.ItemIsEnabled)
            item_widget.setTextAlignment(Qt.AlignCenter)
            self.sequenceTable.setItem(index, 2, item_widget)

            # Backrub checkbox column
            item_widget = QTableWidgetItem("")
            item_widget.setFont(self.labelfont)
            if aa.get_backrub_mode():
                item_widget.setCheckState(Qt.Checked)
            else:
                item_widget.setCheckState(Qt.Unchecked)
            item_widget.setTextAlignment(Qt.AlignLeft)
            item_widget.setSizeHint(QSize(20,12))
            item_widget.setFlags(Qt.ItemIsSelectable |
                                 Qt.ItemIsEnabled |
                                 Qt.ItemIsUserCheckable)
            self.sequenceTable.setItem(index, 3, item_widget)

            # Mutation descriptor column
            aa_string = self._get_mutation_descriptor(aa)
            item_widget = QTableWidgetItem(aa_string)
            item_widget.setFont(self.descriptorfont)
            self.sequenceTable.setItem(index, 4, item_widget)

            self.sequenceTable.setRowHeight(index, 16)

        self.editingItem = False

        self.sequenceTable.resizeColumnsToContents()

        self.sequenceTable.setColumnWidth(0, 35)
        self.sequenceTable.setColumnWidth(2, 80)
        self.sequenceTable.setColumnWidth(3, 35)
        return

    def _fillDescriptorsTable(self):
        """
        Fills in the descriptors table from descriptors user pref.
        """
        dstr = env.prefs[proteinCustomDescriptors_prefs_key].split(":")
        for i in range(len(dstr) / 2):
            self._addNewDescriptorTableRow(dstr[2*i], dstr[2*i+1])

    def _selectAll(self):
        """
        Select all rows in the sequence table.
        """
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.item(row, 0).setCheckState(Qt.Checked)

    def _selectNone(self):
        """
        Unselect all rows in the sequence table.
        """
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.item(row, 0).setCheckState(Qt.Unchecked)

    def _invertSelection(self):
        """
        Inverto row selection range in the sequence table.
        """
        for row in range(self.sequenceTable.rowCount()):
            item_widget = self.sequenceTable.item(row, 0)
            if item_widget.checkState() == Qt.Checked:
                item_widget.setCheckState(Qt.Unchecked)
            else:
                item_widget.setCheckState(Qt.Checked)

    def _get_mutation_descriptor(self, aa):
        """
        Get mutation descriptor string for a given amino acid.
        """
        aa_string = self.rosetta_all_set

        range = aa.get_mutation_range()
        aa_string = self.rosetta_all_set

        if range == "NATRO" or \
           range == "NATAA":
            code = aa.get_one_letter_code()
            aa_string = re.sub("[^"+code+"]",'_', aa_string)
        elif range == "POLAR":
            aa_string = self.rosetta_polar_set
        elif range == "APOLA":
            aa_string = self.rosetta_apolar_set
        elif range == "PIKAA":
            aa_string = aa.get_mutation_descriptor()

        return aa_string

    def _get_descriptor_name(self, aa):
        """
        Returns a mutation descriptor name for an amino acid.
        """
        range_name = aa.get_mutation_range()
        for i in range(len(self.rosetta_set_names)):
            if range_name == self.rosetta_set_names[i]:
                if range_name == "PIKAA":
                    # Find a descriptor with a list of
                    # custom descriptors.
                    dstr = self._makeProperAAString(aa.get_mutation_descriptor())
                    for i in range(5, len(self.descriptor_list)):
                        if dstr == self.descriptor_list[i]:
                            return self.set_names[i]
                else:
                    return self.set_names[i]
        return "Custom"

    def _get_aa_for_index(self, index, expand = False):
        """
        Get amino acid by index.
        @return: amino acid (Residue)
        """

        if not self.current_protein:
            return None
        else:
            currentProteinChunk = self.current_protein

        currentProteinChunk.protein.set_current_amino_acid_index(index)
        current_aa = currentProteinChunk.protein.get_current_amino_acid()
        if expand:
            currentProteinChunk.protein.collapse_all_rotamers()
            currentProteinChunk.protein.expand_rotamer(current_aa)
        return current_aa

    def _sequenceTableCellChanged(self, crow, ccol):
        """
        Slot for sequence table CellChanged event.
        """
        item = self.sequenceTable.item(crow, ccol)
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.removeCellWidget(row, 2)
            self.sequenceTable.setRowHeight(row, 16)
        if ccol == 2:
            # Make the row a little bit wider.
            self.sequenceTable.setRowHeight(crow, 22)
            # Create and insert a Combo Box into a current cell.
            self.setComboBox = QComboBox()
            self.setComboBox.addItems(self.set_names)

            self.win.connect(self.setComboBox,
                             SIGNAL("activated(int)"),
                             self._setComboBoxIndexChanged)

            self.sequenceTable.setCellWidget(crow, 2, self.setComboBox)

        current_aa = self._get_aa_for_index(crow, expand=True)
        if current_aa:
            # Center on the selected amino acid.
            if self.recenterViewCheckBox.isChecked():
                ca_atom = current_aa.get_c_alpha_atom()
                if ca_atom:
                    self.win.glpane.pov = -ca_atom.posn()
            self.win.glpane.gl_update()

            # Update backrub status for selected amino acid.
            if ccol == 3:
                cbox = self.sequenceTable.item(crow, 3)
                if cbox.checkState() == Qt.Checked:
                    current_aa.set_backrub_mode(True)
                else:
                    current_aa.set_backrub_mode(False)

        from PyQt4.Qt import QTextCursor
        cursor = self.sequenceEditor.sequenceTextEdit.textCursor()
        #boundary condition
        if crow == -1:
            crow = 0
        cursor.setPosition(crow, QTextCursor.MoveAnchor)
        cursor.setPosition(crow + 1, QTextCursor.KeepAnchor)
        self.sequenceEditor.sequenceTextEdit.setTextCursor( cursor )


    def _applyDescriptor(self):
        """
        Apply mutation descriptor to the selected amino acids.
        """
        cdes = self.descriptorsTable.currentRow()
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(cdes + 5, tablerow = row, selectedOnly = True)

    def _setComboBoxIndexChanged( self, index, tablerow = None, selectedOnly = False):
        """
        Slot for mutation descriptor combo box (in third column of the sequence
        table.)
        """
        if tablerow is None:
            crow = self.sequenceTable.currentRow()
        else:
            crow = tablerow
        item = self.sequenceTable.item(crow, 2)
        if item:
            self.editingItem = True

            cbox = self.sequenceTable.item(crow, 0)
            if not selectedOnly or \
               cbox.checkState() == Qt.Checked:
                item.setText(self.set_names[index])
                item = self.sequenceTable.item(crow, 4)
                aa = self._get_aa_for_index(crow)
                set_name = self.rosetta_set_names[index]
                aa.set_mutation_range(set_name)
                if set_name == "PIKAA":
                    aa.set_mutation_descriptor(self.descriptor_list[index])
                item.setText(self._get_mutation_descriptor(aa))
                for row in range(self.sequenceTable.rowCount()):
                    self.sequenceTable.removeCellWidget(row, 2)
                    self.sequenceTable.setRowHeight(row, 16)

            self.editingItem = False

    def scrollToPosition(self, index):
        """
        Scrolls the Sequence Table to a given sequence position.
        """
        item = self.sequenceTable.item(index, 0)
        if item:
            self.sequenceTable.scrollToItem(item)

    def _applyAny(self):
        """
        Apply "ALLAA" descriptor.
        """
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(0, tablerow = row, selectedOnly = True)

    def _applySame(self):
        """
        Apply "NATAA" descriptor.
        """
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(1, tablerow = row, selectedOnly = True)

    def _applyLocked(self):
        """
        Apply "NATRO" descriptor.
        """
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(2, tablerow = row, selectedOnly = True)

    def _applyPolar(self):
        """
        Apply "POLAR" descriptor.
        """
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(3, tablerow = row, selectedOnly = True)

    def _applyApolar(self):
        """
        Apply "APOLA" descriptor.
        """
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(4, tablerow = row, selectedOnly = True)

    def resizeEvent(self, event):
        """
        Called whenever PM width has changed. Sets correct width of the
        rows in descriptor and sequence tables.
        """
        self.descriptorsTable.setColumnWidth(1,
            self.descriptorsTable.width()-self.descriptorsTable.columnWidth(0)-20)

        self.sequenceTable.setColumnWidth(4,
            self.sequenceTable.width()-
            (self.sequenceTable.columnWidth(0) +
             self.sequenceTable.columnWidth(1) +
             self.sequenceTable.columnWidth(2) +
            self.sequenceTable.columnWidth(3))-20)


    def _addNewDescriptorTableRow(self, name, descriptor):
        """
        Adds a new row to the descriptor table.
        """
        row = self.descriptorsTable.rowCount()
        self.descriptorsTable.insertRow(row)

        item_widget = QTableWidgetItem(name)
        item_widget.setFont(self.labelfont)
        item_widget.setFlags(Qt.ItemIsSelectable |
                             Qt.ItemIsEnabled |
                             Qt.ItemIsEditable)
        item_widget.setTextAlignment(Qt.AlignLeft)
        self.descriptorsTable.setItem(row, 0, item_widget)
        self.descriptorsTable.resizeColumnToContents(0)

        s = self._makeProperAAString(descriptor)
        item_widget = QTableWidgetItem(s)
        item_widget.setFont(self.descriptorfont)
        item_widget.setFlags(Qt.ItemIsSelectable |
                             Qt.ItemIsEnabled |
                             Qt.ItemIsEditable)
        item_widget.setTextAlignment(Qt.AlignLeft)
        self.descriptorsTable.setItem(row, 1, item_widget)
        self.descriptorsTable.setColumnWidth(1,
            self.descriptorsTable.width()-self.descriptorsTable.columnWidth(0)-20)

        self.descriptorsTable.setRowHeight(row, 16)

    def _addNewDescriptor(self):
        """
        Adds a new descriptor to the descriptor table.
        """
        self._addNewDescriptorTableRow("New Set", "PGAVILMFWYCSTNQDEHKR")
        self._makeDescriptorUserPref()
        self._updateSetLists()

    def _removeDescriptor(self):
        """
        Removes a highlighted descriptor from the descriptors table.
        """
        crow = self.descriptorsTable.currentRow()
        if crow >= 0:
            self.descriptorsTable.removeRow(crow)
            self._makeDescriptorUserPref()
            self._updateSetLists()

    def _makeDescriptorUserPref(self):
        """
        Constructs a custom descriptors string.
        """
        dstr = ""
        for row in range(self.descriptorsTable.rowCount()):
            item0 = self.descriptorsTable.item(row, 0)
            item1 = self.descriptorsTable.item(row, 1)
            if item0 and \
               item1:
                dstr += item0.text() + \
                     ":" + \
                     item1.text() + \
                     ":"
        env.prefs[proteinCustomDescriptors_prefs_key] = dstr

    def _makeProperAAString(self, string):
        """
        Creates a proper amino acid string from an arbitrary string.
        """
        aa_string = str(string).upper()
        new_aa_string = ""
        for i in range(len(self.rosetta_all_set)):
            if aa_string.find(self.rosetta_all_set[i]) == -1:
                new_aa_string += "_"
            else:
                new_aa_string += self.rosetta_all_set[i]
        return new_aa_string

    def _sequenceTableItemChanged(self, item):
        """
        Called when an item in the sequence table has changed.
        """
        if self.editingItem:
            return
        if self.sequenceTable.column(item) == 4:
            self.editingItem = True
            crow = self.sequenceTable.currentRow()
            dstr = self._makeProperAAString(str(item.text()).upper())
            item.setText(dstr)
            aa = self._get_aa_for_index(crow)
            if aa:
                aa.set_mutation_range("PIKAA")
                aa.set_mutation_descriptor(dstr.replace("_",""))
            item = self.sequenceTable.item(crow, 2)
            if item:
                item.setText("Custom")
            self.editingItem = False

    def _descriptorsTableItemChanged(self, item):
        """
        Called when an item in the descriptors table has changed.
        """
        if self.editingItem:
            return
        if self.descriptorsTable.column(item) == 1:
            self.editingItem = True
            item.setText(self._makeProperAAString(str(item.text()).upper()))
            self.editingItem = False

        self._makeDescriptorUserPref()
        self._updateSetLists()

    def _updateSetLists(self):
        """
        Updates lists of descriptor sets and descriptor set names.
        """
        self.set_names = self.set_names[:5]
        self.descriptor_list = self.descriptor_list[:5]
        self.rosetta_set_names = self.rosetta_set_names[:5]

        dstr = env.prefs[proteinCustomDescriptors_prefs_key].split(":")
        for i in range(len(dstr) / 2):
            self.set_names.append(dstr[2*i])
            self.descriptor_list.append(dstr[2*i+1])
            self.rosetta_set_names.append("PIKAA")
            #self._addNewDescriptorTableRow(dstr[2*i], dstr[2*i+1])
        return

    def _update_UI_do_updates_TEMP(self):
        """
        Overrides superclass method.

        @see: Command_PropertyManager._update_UI_do_updates()
        """

        self.current_protein = self.win.assy.getSelectedProteinChunk()

        if self.current_protein is self.previous_protein:
            print "_update_UI_do_updates(): DO NOTHING."
            return

        # NOTE: Changing the display styles of the protein chunks can take some
        # time. We should put up the wait (hourglass) cursor here and restore
        # before returning.

        # Update all PM widgets that need to be since something has changed.
        print "_update_UI_do_updates(): UPDATING the PMGR."
        self.update_name_field()
        self.sequenceEditor.update()
        self.update_residue_combobox()


        if self.previous_protein:
            self.previous_protein.setDisplayStyle(self.previous_protein_display_style)

        self.previous_protein = self.current_protein

        if self.current_protein:
            self.previous_protein_display_style = self.current_protein.getDisplayStyle()
            self.current_protein.setDisplayStyle(diPROTEIN)

        return
Beispiel #2
0
class EditResidues_PropertyManager(PM_Dialog, DebugMenuMixin):
    """
    The ProteinDisplayStyle_PropertyManager class provides a Property Manager 
    for the B{Display Style} command on the flyout toolbar in the 
    Build > Protein mode. 

    @ivar title: The title that appears in the property manager header.
    @type title: str

    @ivar pmName: The name of this property manager. This is used to set
                  the name of the PM_Dialog object via setObjectName().
    @type name: str

    @ivar iconPath: The relative path to the PNG file that contains a
                    22 x 22 icon image that appears in the PM header.
    @type iconPath: str
    """

    title = "Edit Residues"
    pmName = title
    iconPath = "ui/actions/Edit/EditProteinDisplayStyle.png"

    def __init__(self, parentCommand):
        """
        Constructor for the property manager.
        """

        self.parentMode = parentCommand
        self.w = self.parentMode.w
        self.win = self.parentMode.w

        self.pw = self.parentMode.pw
        self.o = self.win.glpane
        self.currentWorkingDirectory = env.prefs[workingDirectory_prefs_key]

        PM_Dialog.__init__(self, self.pmName, self.iconPath, self.title)

        DebugMenuMixin._init1(self)

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)

        msg = "Edit residues."
        self.updateMessage(msg)

    def connect_or_disconnect_signals(self, isConnect=True):

        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect

        #change_connect(self.nextAAPushButton,
        #               SIGNAL("clicked()"),
        #               self._expandNextRotamer)

    def ok_btn_clicked(self):
        """
        Slot for the OK button
        """
        self.win.toolsDone()

    def cancel_btn_clicked(self):
        """
        Slot for the Cancel button.
        """
        #TODO: Cancel button needs to be removed. See comment at the top
        self.win.toolsDone()

    def show(self):
        """
        Shows the Property Manager. Overrides PM_Dialog.show.
        """
        self.sequenceEditor = self.win.createProteinSequenceEditorIfNeeded()
        self.sequenceEditor.hide()
        PM_Dialog.show(self)

        # Update all PM widgets, then establish their signal-slot connections.
        # note: It is important to update the widgets *first* since doing
        # it in the reverse order will generate signals when updating
        # the PM widgets (via updateDnaDisplayStyleWidgets()), causing
        # unneccessary repaints of the model view.

        self._fillSequenceTable()

        self.connect_or_disconnect_signals(isConnect=True)

    def close(self):
        """
        Closes the Property Manager. Overrides PM_Dialog.close.
        """
        self.connect_or_disconnect_signals(False)
        PM_Dialog.close(self)

    def _addGroupBoxes(self):
        """
        Add the Property Manager group boxes.
        """
        self._pmGroupBox1 = PM_GroupBox(self, title="Sequence")
        self._loadGroupBox1(self._pmGroupBox1)

        #self._pmGroupBox2 = PM_GroupBox( self,
        #                                 title = "Rotamer")
        #self._loadGroupBox2( self._pmGroupBox2 )

    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box.
        """

        self.labelfont = QFont("Helvetica", 12)
        self.descriptorfont = QFont("Courier New", 12)

        self.headerdata = ['', 'ID', 'Set', 'Descriptor']

        self.set_names = ["Any", "Same", "Locked", "Polar", "Apolar"]
        self.rosetta_set_names = ["ALLAA", "NATRO", "NATAA", "POLAR", "APOLA"]
        self.descriptor_list = [
            "GAVILMFWCSTYNQDEHKRP", "____________________",
            "____________________", "________CSTYNQDEHKR_",
            "GAVILMFW___________P"
        ]

        self.descriptorsTable = PM_TableWidget(pmGroupBox)
        self.descriptorsTable.setFixedHeight(100)
        self.descriptorsTable.setRowCount(len(self.set_names))
        self.descriptorsTable.setColumnCount(2)
        self.descriptorsTable.verticalHeader().setVisible(False)
        self.descriptorsTable.horizontalHeader().setVisible(False)

        for index in range(len(self.set_names)):
            item_widget = QTableWidgetItem(self.set_names[index])
            item_widget.setFont(self.labelfont)
            item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                                 | Qt.ItemIsEditable)
            item_widget.setTextAlignment(Qt.AlignCenter)
            self.descriptorsTable.setItem(index, 0, item_widget)

            item_widget = QTableWidgetItem(self.descriptor_list[index])
            item_widget.setFont(self.descriptorfont)
            item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                                 | Qt.ItemIsEditable)
            item_widget.setTextAlignment(Qt.AlignCenter)
            self.descriptorsTable.setItem(index, 1, item_widget)

            self.descriptorsTable.setRowHeight(index, 16)

            pass

        self.descriptorsTable.resizeColumnsToContents()

        self.applyDescriptorPushButton = PM_PushButton(pmGroupBox,
                                                       text="Apply",
                                                       setAsDefault=True)

        self.selectAllPushButton = PM_PushButton(pmGroupBox,
                                                 text="All",
                                                 setAsDefault=True)

        self.selectNonePushButton = PM_PushButton(pmGroupBox,
                                                  text="None",
                                                  setAsDefault=True)

        self.selectInvertPushButton = PM_PushButton(pmGroupBox,
                                                    text="Invert",
                                                    setAsDefault=True)

        self.win.connect(self.applyDescriptorPushButton, SIGNAL("clicked()"),
                         self._applyDescriptor)

        self.win.connect(self.selectAllPushButton, SIGNAL("clicked()"),
                         self._selectAll)

        self.win.connect(self.selectNonePushButton, SIGNAL("clicked()"),
                         self._selectNone)

        self.win.connect(self.selectInvertPushButton, SIGNAL("clicked()"),
                         self._invertSelection)

        buttonList = [('PM_PushButton', self.applyDescriptorPushButton, 0, 0),
                      ('QSpacerItem', 5, 5, 1, 0),
                      ('PM_PushButton', self.selectAllPushButton, 2, 0),
                      ('PM_PushButton', self.selectNonePushButton, 3, 0),
                      ('PM_PushButton', self.selectInvertPushButton, 4, 0)]

        self.buttonGrid = PM_WidgetGrid(pmGroupBox, widgetList=buttonList)


        self.recenterViewCheckBox  = \
            PM_CheckBox( pmGroupBox,
                         text          =  "Re-center view",
                         setAsDefault  =  True,
                         state         = Qt.Checked)

        self.sequenceTable = PM_TableWidget(pmGroupBox)
        #self.sequenceTable.setModel(self.tableModel)
        self.sequenceTable.resizeColumnsToContents()
        self.sequenceTable.verticalHeader().setVisible(False)
        #self.sequenceTable.setRowCount(0)
        self.sequenceTable.setColumnCount(4)

        self.checkbox = QCheckBox()

        self.sequenceTable.setFixedHeight(345)

        self.sequenceTable.setHorizontalHeaderLabels(self.headerdata)
        ###self._fillSequenceTable()

    def _fillSequenceTable(self):
        """
        """

        self.setComboBox = QComboBox()

        for chunk in self.win.assy.molecules:
            if chunk.isProteinChunk():
                aa_list = chunk.protein.get_amino_acids()
                aa_list_len = len(aa_list)
                self.sequenceTable.setRowCount(aa_list_len)
                for index in range(aa_list_len):
                    item_widget = QTableWidgetItem("")
                    item_widget.setFont(self.labelfont)
                    item_widget.setCheckState(Qt.Checked)
                    item_widget.setTextAlignment(Qt.AlignLeft)
                    item_widget.setSizeHint(QSize(20, 12))
                    item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                                         | Qt.ItemIsUserCheckable)
                    self.sequenceTable.setItem(index, 0, item_widget)

                    item_widget = QTableWidgetItem(str(index + 1))
                    item_widget.setFont(self.labelfont)
                    item_widget.setFlags(Qt.ItemIsSelectable
                                         | Qt.ItemIsEnabled)
                    item_widget.setTextAlignment(Qt.AlignCenter)
                    self.sequenceTable.setItem(index, 1, item_widget)

                    item_widget = QTableWidgetItem("Any")
                    item_widget.setFont(self.labelfont)
                    item_widget.setFlags(Qt.ItemIsSelectable
                                         | Qt.ItemIsEnabled)
                    item_widget.setTextAlignment(Qt.AlignCenter)
                    self.sequenceTable.setItem(index, 2, item_widget)

                    aa_string = self._get_mutation_descriptor(
                        self._get_aa_for_index(index))

                    item_widget = QTableWidgetItem(aa_string)
                    item_widget.setFont(self.descriptorfont)
                    self.sequenceTable.setItem(index, 3, item_widget)

                    self.sequenceTable.setRowHeight(index, 16)

        self.win.connect(self.sequenceTable, SIGNAL("cellClicked(int, int)"),
                         self._sequenceTableCellChanged)

        self.sequenceTable.resizeColumnsToContents()

        self.sequenceTable.setColumnWidth(0, 35)
        self.sequenceTable.setColumnWidth(2, 80)

    def _selectAll(self):
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.item(row, 0).setCheckState(Qt.Checked)

    def _selectNone(self):
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.item(row, 0).setCheckState(Qt.Unchecked)

    def _invertSelection(self):
        for row in range(self.sequenceTable.rowCount()):
            item_widget = self.sequenceTable.item(row, 0)
            if item_widget.checkState() == Qt.Checked:
                item_widget.setCheckState(Qt.Unchecked)
            else:
                item_widget.setCheckState(Qt.Checked)

    def _get_mutation_descriptor(self, aa):
        """
        """
        aa_string = "GAVILMFWCSTYNQDEHKRP"

        range = aa.get_mutation_range()
        if range == "NATRO" or \
           range == "NATAA":
            code = aa.get_one_letter_code()
            aa_string = re.sub("[^" + code + "]", '_', aa_string)
        elif range == "POLAR":
            aa_string = "________CSTYNQDEHKR_"
        elif range == "APOLA":
            aa_string = "GAVILMFW___________P"

        return aa_string

    def _get_aa_for_index(self, index, expand=False):
        """
        """
        # Center on a selected amino acid.
        for chunk in self.win.assy.molecules:
            if chunk.isProteinChunk():
                chunk.protein.set_current_amino_acid_index(index)
                current_aa = chunk.protein.get_current_amino_acid()
                if expand:
                    chunk.protein.collapse_all_rotamers()
                    chunk.protein.expand_rotamer(current_aa)
                return current_aa

        return None

    def _sequenceTableCellChanged(self, crow, ccol):
        #print "CELL CHANGED: ", (crow, ccol)
        item = self.sequenceTable.item(crow, ccol)
        #print "ITEM = ", item

        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.removeCellWidget(row, 2)
            self.sequenceTable.setRowHeight(row, 16)
        if ccol == 2:
            # Make the row a little bit wider.
            self.sequenceTable.setRowHeight(crow, 22)
            # Create and insert a Combo Box into a current cell.
            self.setComboBox = QComboBox()
            self.setComboBox.addItems(self.set_names)
            self.win.connect(self.setComboBox,
                             SIGNAL("currentIndexChanged(int)"),
                             self._setComboBoxIndexChanged)

            self.sequenceTable.setCellWidget(crow, 2, self.setComboBox)

        current_aa = self._get_aa_for_index(crow, expand=True)
        if current_aa:
            # Center on the selected amino acid.
            if self.recenterViewCheckBox.isChecked():
                ca_atom = current_aa.get_c_alpha_atom()
                if ca_atom:
                    self.win.glpane.pov = -ca_atom.posn()
            self.win.glpane.gl_update()

    def _applyDescriptor(self):
        """        
        """
        cdes = self.descriptorsTable.currentRow()
        for row in range(self.sequenceTable.rowCount()):
            #print "row = ", row
            self._setComboBoxIndexChanged(cdes,
                                          tablerow=row,
                                          selectedOnly=True)

    def _setComboBoxIndexChanged(self,
                                 index,
                                 tablerow=None,
                                 selectedOnly=False):
        """
        """
        #print "INDEX = ", index
        if tablerow is None:
            crow = self.sequenceTable.currentRow()
        else:
            crow = tablerow
        #print "current row: ", crow
        item = self.sequenceTable.item(crow, 2)
        if item:
            cbox = self.sequenceTable.item(crow, 0)
            if not selectedOnly or \
               cbox.checkState() == Qt.Checked:
                item.setText(self.set_names[index])
                item = self.sequenceTable.item(crow, 3)
                aa = self._get_aa_for_index(crow)
                aa.set_mutation_range(self.rosetta_set_names[index])
                item.setText(self._get_mutation_descriptor(aa))

        ###self._write_resfile()

    def _write_resfile(self):
        from protein.model.Protein import write_rosetta_resfile
        for chunk in self.win.assy.molecules:
            if chunk.isProteinChunk():
                write_rosetta_resfile("/Users/piotr/test.resfile", chunk)
                return

    def _addWhatsThisText(self):

        #from ne1_ui.WhatsThisText_for_PropertyManagers import WhatsThis_EditResidues_PropertyManager
        #WhatsThis_EditResidues_PropertyManager(self)
        pass

    def _addToolTipText(self):
        #from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_EditProteinDisplayStyle_PropertyManager
        #ToolTip_EditProteinDisplayStyle_PropertyManager(self)
        pass

    def scrollToPosition(self, index):
        """
        Scrolls the Sequence Table to a given sequence position.
        """
        item = self.sequenceTable.item(index, 0)
        if item:
            self.sequenceTable.scrollToItem(item)
Beispiel #3
0
class EditResidues_PropertyManager(Command_PropertyManager):
    """
    The ProteinDisplayStyle_PropertyManager class provides a Property Manager 
    for the B{Display Style} command on the flyout toolbar in the 
    Build > Protein mode. 

    @ivar title: The title that appears in the property manager header.
    @type title: str

    @ivar pmName: The name of this property manager. This is used to set
                  the name of the PM_Dialog object via setObjectName().
    @type name: str

    @ivar iconPath: The relative path to the PNG file that contains a
                    22 x 22 icon image that appears in the PM header.
    @type iconPath: str
    """

    title = "Edit Residues"
    pmName = title
    iconPath = "ui/actions/Command Toolbar/BuildProtein/Residues.png"

    rosetta_all_set = "PGAVILMFWYCSTNQDEHKR"
    rosetta_polar_set = "___________STNQDEHKR"
    rosetta_apolar_set = "PGAVILMFWYC_________"

    def __init__(self, command):
        """
        Constructor for the property manager.
        """

        self.currentWorkingDirectory = env.prefs[workingDirectory_prefs_key]

        _superclass.__init__(self, command)

        self.sequenceEditor = self.win.createProteinSequenceEditorIfNeeded()
        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)

        self.editingItem = False
        return

    def connect_or_disconnect_signals(self, isConnect=True):

        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect

        change_connect(self.applyAnyPushButton, SIGNAL("clicked()"),
                       self._applyAny)

        change_connect(self.applySamePushButton, SIGNAL("clicked()"),
                       self._applySame)

        change_connect(self.applyLockedPushButton, SIGNAL("clicked()"),
                       self._applyLocked)

        change_connect(self.applyPolarPushButton, SIGNAL("clicked()"),
                       self._applyPolar)

        change_connect(self.applyApolarPushButton, SIGNAL("clicked()"),
                       self._applyApolar)

        change_connect(self.selectAllPushButton, SIGNAL("clicked()"),
                       self._selectAll)

        change_connect(self.selectNonePushButton, SIGNAL("clicked()"),
                       self._selectNone)

        change_connect(self.selectInvertPushButton, SIGNAL("clicked()"),
                       self._invertSelection)

        change_connect(self.applyDescriptorPushButton, SIGNAL("clicked()"),
                       self._applyDescriptor)

        change_connect(self.removeDescriptorPushButton, SIGNAL("clicked()"),
                       self._removeDescriptor)

        change_connect(self.sequenceTable, SIGNAL("cellClicked(int, int)"),
                       self._sequenceTableCellChanged)

        change_connect(self.sequenceTable,
                       SIGNAL("itemChanged(QTableWidgetItem*)"),
                       self._sequenceTableItemChanged)

        change_connect(self.descriptorsTable,
                       SIGNAL("itemChanged(QTableWidgetItem*)"),
                       self._descriptorsTableItemChanged)

        change_connect(self.newDescriptorPushButton, SIGNAL("clicked()"),
                       self._addNewDescriptor)
        change_connect(self.showSequencePushButton, SIGNAL("clicked()"),
                       self._showSeqEditor)
        return

    def _showSeqEditor(self):
        """
        Shows sequence editor
        """
        if self.showSequencePushButton.isEnabled():
            self.sequenceEditor.show()
        return

    def show(self):
        """
        Shows the Property Manager. Extends superclass method.
        """
        env.history.statusbar_msg("")
        #Urmi 20080728: Set the current protein and this will be used for accessing
        #various properties of this protein
        self.set_current_protein()
        if self.current_protein:
            msg = "Editing structure <b>%s</b>." % self.current_protein.name
            self.showSequencePushButton.setEnabled(True)
        else:
            msg = "Select a single structure to edit."
            self.showSequencePushButton.setEnabled(False)
        self.sequenceEditor.hide()

        _superclass.show(self)

        self._fillSequenceTable()
        self.updateMessage(msg)

        return

    def set_current_protein(self):
        """
        Set the current protein for which all the properties are displayed to the
        one chosen in the build protein combo box
        """
        self.current_protein = self.win.assy.getSelectedProteinChunk()
        return

    def _addGroupBoxes(self):
        """
        Add the Property Manager group boxes.
        """

        if sys.platform == "darwin":
            # Workaround for table font size difference between Mac/Win
            self.labelfont = QFont("Helvetica", 12)
            self.descriptorfont = QFont("Courier New", 12)
        else:
            self.labelfont = QFont("Helvetica", 9)
            self.descriptorfont = QFont("Courier New", 9)

        self._pmGroupBox1 = PM_GroupBox(self, title="Descriptors")
        self._loadGroupBox1(self._pmGroupBox1)

        self._pmGroupBox2 = PM_GroupBox(self, title="Sequence")
        self._loadGroupBox2(self._pmGroupBox2)

    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in the first group box.
        """

        self.headerdata_desc = ['Name', 'Descriptor']

        self.set_names = ["Any", "Same", "Locked", "Apolar", "Polar"]
        self.rosetta_set_names = ["ALLAA", "NATAA", "NATRO", "APOLA", "POLAR"]
        self.descriptor_list = [
            "PGAVILMFWYCSTNQDEHKR", "____________________",
            "____________________", "PGAVILMFWYC_________",
            "___________STNQDEHKR"
        ]

        self.applyAnyPushButton = PM_PushButton(pmGroupBox,
                                                text="ALLAA",
                                                setAsDefault=True)

        self.applySamePushButton = PM_PushButton(pmGroupBox,
                                                 text="NATAA",
                                                 setAsDefault=True)

        self.applyLockedPushButton = PM_PushButton(pmGroupBox,
                                                   text="NATRO",
                                                   setAsDefault=True)

        self.applyPolarPushButton = PM_PushButton(pmGroupBox,
                                                  text="APOLA",
                                                  setAsDefault=True)

        self.applyApolarPushButton = PM_PushButton(pmGroupBox,
                                                   text="POLAR",
                                                   setAsDefault=True)

        #self.applyBackrubPushButton = PM_PushButton( pmGroupBox,
        #    text       =  "BACKRUB",
        #    setAsDefault  =  True)

        self.applyAnyPushButton.setFixedHeight(25)
        self.applyAnyPushButton.setFixedWidth(60)

        self.applySamePushButton.setFixedHeight(25)
        self.applySamePushButton.setFixedWidth(60)

        self.applyLockedPushButton.setFixedHeight(25)
        self.applyLockedPushButton.setFixedWidth(60)

        self.applyPolarPushButton.setFixedHeight(25)
        self.applyPolarPushButton.setFixedWidth(60)

        self.applyApolarPushButton.setFixedHeight(25)
        self.applyApolarPushButton.setFixedWidth(60)

        applyButtonList = [('PM_PushButton', self.applyAnyPushButton, 0, 0),
                           ('PM_PushButton', self.applySamePushButton, 1, 0),
                           ('PM_PushButton', self.applyLockedPushButton, 2, 0),
                           ('PM_PushButton', self.applyPolarPushButton, 3, 0),
                           ('PM_PushButton', self.applyApolarPushButton, 4, 0)]

        self.applyButtonGrid = PM_WidgetGrid(pmGroupBox,
                                             label="Apply standard set",
                                             widgetList=applyButtonList)

        self.descriptorsTable = PM_TableWidget(pmGroupBox,
                                               label="Custom descriptors")

        self.descriptorsTable.setFixedHeight(100)
        self.descriptorsTable.setRowCount(0)
        self.descriptorsTable.setColumnCount(2)
        self.descriptorsTable.verticalHeader().setVisible(False)
        self.descriptorsTable.horizontalHeader().setVisible(True)
        self.descriptorsTable.setGridStyle(Qt.NoPen)
        self.descriptorsTable.setHorizontalHeaderLabels(self.headerdata_desc)

        self._updateSetLists()

        self._fillDescriptorsTable()

        self.descriptorsTable.resizeColumnsToContents()

        self.newDescriptorPushButton = PM_PushButton(pmGroupBox,
                                                     text="New",
                                                     setAsDefault=True)

        self.newDescriptorPushButton.setFixedHeight(25)

        self.removeDescriptorPushButton = PM_PushButton(pmGroupBox,
                                                        text="Remove",
                                                        setAsDefault=True)

        self.removeDescriptorPushButton.setFixedHeight(25)

        self.applyDescriptorPushButton = PM_PushButton(pmGroupBox,
                                                       text="Apply",
                                                       setAsDefault=True)

        self.applyDescriptorPushButton.setFixedHeight(25)

        addDescriptorButtonList = [
            ('PM_PushButton', self.newDescriptorPushButton, 0, 0),
            ('PM_PushButton', self.removeDescriptorPushButton, 1, 0),
            ('PM_PushButton', self.applyDescriptorPushButton, 2, 0)
        ]

        self.addDescriptorGrid = PM_WidgetGrid(
            pmGroupBox, alignment="Center", widgetList=addDescriptorButtonList)

    def _loadGroupBox2(self, pmGroupBox):
        """
        Load widgets in the second group box.
        """

        self.headerdata_seq = ['', 'ID', 'Set', 'BR', 'Descriptor']

        self.recenterViewCheckBox  = \
            PM_CheckBox( pmGroupBox,
                         text          =  "Re-center view on selected residue",
                         setAsDefault  =  True,
                         widgetColumn  = 0,
                         state         = Qt.Unchecked)

        self.selectAllPushButton = PM_PushButton(pmGroupBox,
                                                 text="All",
                                                 setAsDefault=True)

        self.selectAllPushButton.setFixedHeight(25)

        self.selectNonePushButton = PM_PushButton(pmGroupBox,
                                                  text="None",
                                                  setAsDefault=True)

        self.selectNonePushButton.setFixedHeight(25)

        self.selectInvertPushButton = PM_PushButton(pmGroupBox,
                                                    text="Invert",
                                                    setAsDefault=True)

        self.selectInvertPushButton.setFixedHeight(25)

        buttonList = [('PM_PushButton', self.selectAllPushButton, 0, 0),
                      ('PM_PushButton', self.selectNonePushButton, 1, 0),
                      ('PM_PushButton', self.selectInvertPushButton, 2, 0)]

        self.buttonGrid = PM_WidgetGrid(pmGroupBox, widgetList=buttonList)

        self.sequenceTable = PM_TableWidget(pmGroupBox)
        #self.sequenceTable.setModel(self.tableModel)
        self.sequenceTable.resizeColumnsToContents()
        self.sequenceTable.verticalHeader().setVisible(False)
        #self.sequenceTable.setRowCount(0)
        self.sequenceTable.setColumnCount(5)

        self.checkbox = QCheckBox()

        self.sequenceTable.setFixedHeight(345)

        self.sequenceTable.setGridStyle(Qt.NoPen)

        self.sequenceTable.setHorizontalHeaderLabels(self.headerdata_seq)
        ###self._fillSequenceTable()
        self.showSequencePushButton = PM_PushButton(pmGroupBox,
                                                    text="Show Sequence",
                                                    setAsDefault=True,
                                                    spanWidth=True)

    def _addWhatsThisText(self):
        #from ne1_ui.WhatsThisText_for_PropertyManagers import WhatsThis_EditResidues_PropertyManager
        #WhatsThis_EditResidues_PropertyManager(self)
        pass

    def _addToolTipText(self):
        #from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_EditProteinDisplayStyle_PropertyManager
        #ToolTip_EditProteinDisplayStyle_PropertyManager(self)
        pass

    def _fillSequenceTable(self):
        """
        Fills in the sequence table.
        """

        if not self.current_protein:
            return
        else:
            currentProteinChunk = self.current_protein

        self.editingItem = True

        aa_list = currentProteinChunk.protein.get_amino_acids()
        aa_list_len = len(aa_list)
        self.sequenceTable.setRowCount(aa_list_len)
        for index in range(aa_list_len):
            # Selection checkbox column
            item_widget = QTableWidgetItem("")
            item_widget.setFont(self.labelfont)
            item_widget.setCheckState(Qt.Checked)
            item_widget.setTextAlignment(Qt.AlignLeft)
            item_widget.setSizeHint(QSize(20, 12))
            item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                                 | Qt.ItemIsUserCheckable)
            self.sequenceTable.setItem(index, 0, item_widget)

            # Amino acid index column
            item_widget = QTableWidgetItem(str(index + 1))
            item_widget.setFont(self.labelfont)
            item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
            item_widget.setTextAlignment(Qt.AlignCenter)
            self.sequenceTable.setItem(index, 1, item_widget)

            # Mutation descriptor name column
            aa = self._get_aa_for_index(index)
            item_widget = QTableWidgetItem(self._get_descriptor_name(aa))
            item_widget.setFont(self.labelfont)
            item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
            item_widget.setTextAlignment(Qt.AlignCenter)
            self.sequenceTable.setItem(index, 2, item_widget)

            # Backrub checkbox column
            item_widget = QTableWidgetItem("")
            item_widget.setFont(self.labelfont)
            if aa.get_backrub_mode():
                item_widget.setCheckState(Qt.Checked)
            else:
                item_widget.setCheckState(Qt.Unchecked)
            item_widget.setTextAlignment(Qt.AlignLeft)
            item_widget.setSizeHint(QSize(20, 12))
            item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                                 | Qt.ItemIsUserCheckable)
            self.sequenceTable.setItem(index, 3, item_widget)

            # Mutation descriptor column
            aa_string = self._get_mutation_descriptor(aa)
            item_widget = QTableWidgetItem(aa_string)
            item_widget.setFont(self.descriptorfont)
            self.sequenceTable.setItem(index, 4, item_widget)

            self.sequenceTable.setRowHeight(index, 16)

        self.editingItem = False

        self.sequenceTable.resizeColumnsToContents()

        self.sequenceTable.setColumnWidth(0, 35)
        self.sequenceTable.setColumnWidth(2, 80)
        self.sequenceTable.setColumnWidth(3, 35)
        return

    def _fillDescriptorsTable(self):
        """
        Fills in the descriptors table from descriptors user pref.
        """
        dstr = env.prefs[proteinCustomDescriptors_prefs_key].split(":")
        for i in range(len(dstr) / 2):
            self._addNewDescriptorTableRow(dstr[2 * i], dstr[2 * i + 1])

    def _selectAll(self):
        """
        Select all rows in the sequence table.
        """
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.item(row, 0).setCheckState(Qt.Checked)

    def _selectNone(self):
        """
        Unselect all rows in the sequence table.
        """
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.item(row, 0).setCheckState(Qt.Unchecked)

    def _invertSelection(self):
        """
        Inverto row selection range in the sequence table.
        """
        for row in range(self.sequenceTable.rowCount()):
            item_widget = self.sequenceTable.item(row, 0)
            if item_widget.checkState() == Qt.Checked:
                item_widget.setCheckState(Qt.Unchecked)
            else:
                item_widget.setCheckState(Qt.Checked)

    def _get_mutation_descriptor(self, aa):
        """
        Get mutation descriptor string for a given amino acid.
        """
        aa_string = self.rosetta_all_set

        range = aa.get_mutation_range()
        aa_string = self.rosetta_all_set

        if range == "NATRO" or \
           range == "NATAA":
            code = aa.get_one_letter_code()
            aa_string = re.sub("[^" + code + "]", '_', aa_string)
        elif range == "POLAR":
            aa_string = self.rosetta_polar_set
        elif range == "APOLA":
            aa_string = self.rosetta_apolar_set
        elif range == "PIKAA":
            aa_string = aa.get_mutation_descriptor()

        return aa_string

    def _get_descriptor_name(self, aa):
        """
        Returns a mutation descriptor name for an amino acid.
        """
        range_name = aa.get_mutation_range()
        for i in range(len(self.rosetta_set_names)):
            if range_name == self.rosetta_set_names[i]:
                if range_name == "PIKAA":
                    # Find a descriptor with a list of
                    # custom descriptors.
                    dstr = self._makeProperAAString(
                        aa.get_mutation_descriptor())
                    for i in range(5, len(self.descriptor_list)):
                        if dstr == self.descriptor_list[i]:
                            return self.set_names[i]
                else:
                    return self.set_names[i]
        return "Custom"

    def _get_aa_for_index(self, index, expand=False):
        """
        Get amino acid by index.
        @return: amino acid (Residue)
        """

        if not self.current_protein:
            return None
        else:
            currentProteinChunk = self.current_protein

        currentProteinChunk.protein.set_current_amino_acid_index(index)
        current_aa = currentProteinChunk.protein.get_current_amino_acid()
        if expand:
            currentProteinChunk.protein.collapse_all_rotamers()
            currentProteinChunk.protein.expand_rotamer(current_aa)
        return current_aa

    def _sequenceTableCellChanged(self, crow, ccol):
        """
        Slot for sequence table CellChanged event.
        """
        item = self.sequenceTable.item(crow, ccol)
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.removeCellWidget(row, 2)
            self.sequenceTable.setRowHeight(row, 16)
        if ccol == 2:
            # Make the row a little bit wider.
            self.sequenceTable.setRowHeight(crow, 22)
            # Create and insert a Combo Box into a current cell.
            self.setComboBox = QComboBox()
            self.setComboBox.addItems(self.set_names)

            self.win.connect(self.setComboBox, SIGNAL("activated(int)"),
                             self._setComboBoxIndexChanged)

            self.sequenceTable.setCellWidget(crow, 2, self.setComboBox)

        current_aa = self._get_aa_for_index(crow, expand=True)
        if current_aa:
            # Center on the selected amino acid.
            if self.recenterViewCheckBox.isChecked():
                ca_atom = current_aa.get_c_alpha_atom()
                if ca_atom:
                    self.win.glpane.pov = -ca_atom.posn()
            self.win.glpane.gl_update()

            # Update backrub status for selected amino acid.
            if ccol == 3:
                cbox = self.sequenceTable.item(crow, 3)
                if cbox.checkState() == Qt.Checked:
                    current_aa.set_backrub_mode(True)
                else:
                    current_aa.set_backrub_mode(False)

        from PyQt4.Qt import QTextCursor
        cursor = self.sequenceEditor.sequenceTextEdit.textCursor()
        #boundary condition
        if crow == -1:
            crow = 0
        cursor.setPosition(crow, QTextCursor.MoveAnchor)
        cursor.setPosition(crow + 1, QTextCursor.KeepAnchor)
        self.sequenceEditor.sequenceTextEdit.setTextCursor(cursor)

    def _applyDescriptor(self):
        """        
        Apply mutation descriptor to the selected amino acids.
        """
        cdes = self.descriptorsTable.currentRow()
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(cdes + 5,
                                          tablerow=row,
                                          selectedOnly=True)

    def _setComboBoxIndexChanged(self,
                                 index,
                                 tablerow=None,
                                 selectedOnly=False):
        """
        Slot for mutation descriptor combo box (in third column of the sequence
        table.)
        """
        if tablerow is None:
            crow = self.sequenceTable.currentRow()
        else:
            crow = tablerow
        item = self.sequenceTable.item(crow, 2)
        if item:
            self.editingItem = True

            cbox = self.sequenceTable.item(crow, 0)
            if not selectedOnly or \
               cbox.checkState() == Qt.Checked:
                item.setText(self.set_names[index])
                item = self.sequenceTable.item(crow, 4)
                aa = self._get_aa_for_index(crow)
                set_name = self.rosetta_set_names[index]
                aa.set_mutation_range(set_name)
                if set_name == "PIKAA":
                    aa.set_mutation_descriptor(self.descriptor_list[index])
                item.setText(self._get_mutation_descriptor(aa))
                for row in range(self.sequenceTable.rowCount()):
                    self.sequenceTable.removeCellWidget(row, 2)
                    self.sequenceTable.setRowHeight(row, 16)

            self.editingItem = False

    def scrollToPosition(self, index):
        """
        Scrolls the Sequence Table to a given sequence position.
        """
        item = self.sequenceTable.item(index, 0)
        if item:
            self.sequenceTable.scrollToItem(item)

    def _applyAny(self):
        """
        Apply "ALLAA" descriptor.
        """
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(0, tablerow=row, selectedOnly=True)

    def _applySame(self):
        """
        Apply "NATAA" descriptor.
        """
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(1, tablerow=row, selectedOnly=True)

    def _applyLocked(self):
        """
        Apply "NATRO" descriptor.
        """
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(2, tablerow=row, selectedOnly=True)

    def _applyPolar(self):
        """
        Apply "POLAR" descriptor.
        """
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(3, tablerow=row, selectedOnly=True)

    def _applyApolar(self):
        """
        Apply "APOLA" descriptor.
        """
        for row in range(self.sequenceTable.rowCount()):
            self._setComboBoxIndexChanged(4, tablerow=row, selectedOnly=True)

    def resizeEvent(self, event):
        """
        Called whenever PM width has changed. Sets correct width of the
        rows in descriptor and sequence tables.
        """
        self.descriptorsTable.setColumnWidth(
            1,
            self.descriptorsTable.width() -
            self.descriptorsTable.columnWidth(0) - 20)

        self.sequenceTable.setColumnWidth(
            4,
            self.sequenceTable.width() - (self.sequenceTable.columnWidth(0) +
                                          self.sequenceTable.columnWidth(1) +
                                          self.sequenceTable.columnWidth(2) +
                                          self.sequenceTable.columnWidth(3)) -
            20)

    def _addNewDescriptorTableRow(self, name, descriptor):
        """
        Adds a new row to the descriptor table.
        """
        row = self.descriptorsTable.rowCount()
        self.descriptorsTable.insertRow(row)

        item_widget = QTableWidgetItem(name)
        item_widget.setFont(self.labelfont)
        item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                             | Qt.ItemIsEditable)
        item_widget.setTextAlignment(Qt.AlignLeft)
        self.descriptorsTable.setItem(row, 0, item_widget)
        self.descriptorsTable.resizeColumnToContents(0)

        s = self._makeProperAAString(descriptor)
        item_widget = QTableWidgetItem(s)
        item_widget.setFont(self.descriptorfont)
        item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled
                             | Qt.ItemIsEditable)
        item_widget.setTextAlignment(Qt.AlignLeft)
        self.descriptorsTable.setItem(row, 1, item_widget)
        self.descriptorsTable.setColumnWidth(
            1,
            self.descriptorsTable.width() -
            self.descriptorsTable.columnWidth(0) - 20)

        self.descriptorsTable.setRowHeight(row, 16)

    def _addNewDescriptor(self):
        """
        Adds a new descriptor to the descriptor table.
        """
        self._addNewDescriptorTableRow("New Set", "PGAVILMFWYCSTNQDEHKR")
        self._makeDescriptorUserPref()
        self._updateSetLists()

    def _removeDescriptor(self):
        """
        Removes a highlighted descriptor from the descriptors table.
        """
        crow = self.descriptorsTable.currentRow()
        if crow >= 0:
            self.descriptorsTable.removeRow(crow)
            self._makeDescriptorUserPref()
            self._updateSetLists()

    def _makeDescriptorUserPref(self):
        """
        Constructs a custom descriptors string.
        """
        dstr = ""
        for row in range(self.descriptorsTable.rowCount()):
            item0 = self.descriptorsTable.item(row, 0)
            item1 = self.descriptorsTable.item(row, 1)
            if item0 and \
               item1:
                dstr += item0.text() + \
                     ":" + \
                     item1.text() + \
                     ":"
        env.prefs[proteinCustomDescriptors_prefs_key] = dstr

    def _makeProperAAString(self, string):
        """
        Creates a proper amino acid string from an arbitrary string.
        """
        aa_string = str(string).upper()
        new_aa_string = ""
        for i in range(len(self.rosetta_all_set)):
            if aa_string.find(self.rosetta_all_set[i]) == -1:
                new_aa_string += "_"
            else:
                new_aa_string += self.rosetta_all_set[i]
        return new_aa_string

    def _sequenceTableItemChanged(self, item):
        """
        Called when an item in the sequence table has changed.
        """
        if self.editingItem:
            return
        if self.sequenceTable.column(item) == 4:
            self.editingItem = True
            crow = self.sequenceTable.currentRow()
            dstr = self._makeProperAAString(str(item.text()).upper())
            item.setText(dstr)
            aa = self._get_aa_for_index(crow)
            if aa:
                aa.set_mutation_range("PIKAA")
                aa.set_mutation_descriptor(dstr.replace("_", ""))
            item = self.sequenceTable.item(crow, 2)
            if item:
                item.setText("Custom")
            self.editingItem = False

    def _descriptorsTableItemChanged(self, item):
        """
        Called when an item in the descriptors table has changed.
        """
        if self.editingItem:
            return
        if self.descriptorsTable.column(item) == 1:
            self.editingItem = True
            item.setText(self._makeProperAAString(str(item.text()).upper()))
            self.editingItem = False

        self._makeDescriptorUserPref()
        self._updateSetLists()

    def _updateSetLists(self):
        """
        Updates lists of descriptor sets and descriptor set names.
        """
        self.set_names = self.set_names[:5]
        self.descriptor_list = self.descriptor_list[:5]
        self.rosetta_set_names = self.rosetta_set_names[:5]

        dstr = env.prefs[proteinCustomDescriptors_prefs_key].split(":")
        for i in range(len(dstr) / 2):
            self.set_names.append(dstr[2 * i])
            self.descriptor_list.append(dstr[2 * i + 1])
            self.rosetta_set_names.append("PIKAA")
            #self._addNewDescriptorTableRow(dstr[2*i], dstr[2*i+1])
        return

    def _update_UI_do_updates_TEMP(self):
        """
        Overrides superclass method. 
        
        @see: Command_PropertyManager._update_UI_do_updates()
        """

        self.current_protein = self.win.assy.getSelectedProteinChunk()

        if self.current_protein is self.previous_protein:
            print "_update_UI_do_updates(): DO NOTHING."
            return

        # NOTE: Changing the display styles of the protein chunks can take some
        # time. We should put up the wait (hourglass) cursor here and restore
        # before returning.

        # Update all PM widgets that need to be since something has changed.
        print "_update_UI_do_updates(): UPDATING the PMGR."
        self.update_name_field()
        self.sequenceEditor.update()
        self.update_residue_combobox()

        if self.previous_protein:
            self.previous_protein.setDisplayStyle(
                self.previous_protein_display_style)

        self.previous_protein = self.current_protein

        if self.current_protein:
            self.previous_protein_display_style = self.current_protein.getDisplayStyle(
            )
            self.current_protein.setDisplayStyle(diPROTEIN)

        return
class EditResidues_PropertyManager( PM_Dialog, DebugMenuMixin ):
    """
    The ProteinDisplayStyle_PropertyManager class provides a Property Manager 
    for the B{Display Style} command on the flyout toolbar in the 
    Build > Protein mode. 

    @ivar title: The title that appears in the property manager header.
    @type title: str

    @ivar pmName: The name of this property manager. This is used to set
                  the name of the PM_Dialog object via setObjectName().
    @type name: str

    @ivar iconPath: The relative path to the PNG file that contains a
                    22 x 22 icon image that appears in the PM header.
    @type iconPath: str
    """

    title         =  "Edit Residues"
    pmName        =  title
    iconPath      =  "ui/actions/Edit/EditProteinDisplayStyle.png"

    
    def __init__( self, parentCommand ):
        """
        Constructor for the property manager.
        """

        self.parentMode = parentCommand
        self.w = self.parentMode.w
        self.win = self.parentMode.w

        self.pw = self.parentMode.pw        
        self.o = self.win.glpane                 
        self.currentWorkingDirectory = env.prefs[workingDirectory_prefs_key]
        
        PM_Dialog.__init__(self, self.pmName, self.iconPath, self.title)

        DebugMenuMixin._init1( self )

        self.showTopRowButtons( PM_DONE_BUTTON | \
                                PM_WHATS_THIS_BUTTON)

        msg = "Edit residues."
        self.updateMessage(msg)

    def connect_or_disconnect_signals(self, isConnect = True):
        
        if isConnect:
            change_connect = self.win.connect
        else:
            change_connect = self.win.disconnect 
        
        #change_connect(self.nextAAPushButton,
        #               SIGNAL("clicked()"),
        #               self._expandNextRotamer)
        

    def ok_btn_clicked(self):
        """
        Slot for the OK button
        """
        self.win.toolsDone()

    def cancel_btn_clicked(self):
        """
        Slot for the Cancel button.
        """
        #TODO: Cancel button needs to be removed. See comment at the top
        self.win.toolsDone()

    def show(self):
        """
        Shows the Property Manager. Overrides PM_Dialog.show.
        """
        self.sequenceEditor = self.win.createProteinSequenceEditorIfNeeded()
        self.sequenceEditor.hide()
        PM_Dialog.show(self)

        # Update all PM widgets, then establish their signal-slot connections.
        # note: It is important to update the widgets *first* since doing
        # it in the reverse order will generate signals when updating
        # the PM widgets (via updateDnaDisplayStyleWidgets()), causing
        # unneccessary repaints of the model view.
        
        self._fillSequenceTable()
        
        self.connect_or_disconnect_signals(isConnect = True)

    def close(self):
        """
        Closes the Property Manager. Overrides PM_Dialog.close.
        """
        self.connect_or_disconnect_signals(False)
        PM_Dialog.close(self)

    def _addGroupBoxes( self ):
        """
        Add the Property Manager group boxes.
        """
        self._pmGroupBox1 = PM_GroupBox( self,
                                         title = "Sequence")
        self._loadGroupBox1( self._pmGroupBox1 )

        #self._pmGroupBox2 = PM_GroupBox( self,
        #                                 title = "Rotamer")
        #self._loadGroupBox2( self._pmGroupBox2 )


    def _loadGroupBox1(self, pmGroupBox):
        """
        Load widgets in group box.
        """
            
        self.labelfont = QFont("Helvetica", 12)
        self.descriptorfont = QFont("Courier New", 12)        

        self.headerdata = ['', 'ID', 'Set', 'Descriptor']
        
        self.set_names = ["Any", "Same", "Locked", "Polar", "Apolar"]
        self.rosetta_set_names = ["ALLAA", "NATRO", "NATAA", "POLAR", "APOLA"]
        self.descriptor_list = ["GAVILMFWCSTYNQDEHKRP", 
                                "____________________", 
                                "____________________", 
                                "________CSTYNQDEHKR_", 
                                "GAVILMFW___________P"]
        
        self.descriptorsTable = PM_TableWidget( pmGroupBox)
        self.descriptorsTable.setFixedHeight(100)
        self.descriptorsTable.setRowCount(len(self.set_names))
        self.descriptorsTable.setColumnCount(2)
        self.descriptorsTable.verticalHeader().setVisible(False)
        self.descriptorsTable.horizontalHeader().setVisible(False)
        
        for index in range(len(self.set_names)):
            item_widget = QTableWidgetItem(self.set_names[index])
            item_widget.setFont(self.labelfont)
            item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable)
            item_widget.setTextAlignment(Qt.AlignCenter)
            self.descriptorsTable.setItem(index, 0, item_widget)
            
            item_widget = QTableWidgetItem(self.descriptor_list[index])
            item_widget.setFont(self.descriptorfont)
            item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable)
            item_widget.setTextAlignment(Qt.AlignCenter)
            self.descriptorsTable.setItem(index, 1, item_widget)

            self.descriptorsTable.setRowHeight(index, 16)

            pass
        
        self.descriptorsTable.resizeColumnsToContents()

        self.applyDescriptorPushButton = PM_PushButton( pmGroupBox,
            text         =  "Apply",
            setAsDefault  =  True)

        self.selectAllPushButton = PM_PushButton( pmGroupBox,
            text         =  "All",
            setAsDefault  =  True)

        self.selectNonePushButton = PM_PushButton( pmGroupBox,
            text       =  "None",
            setAsDefault  =  True)

        self.selectInvertPushButton = PM_PushButton( pmGroupBox,
            text       =  "Invert",
            setAsDefault  =  True)

        self.win.connect(self.applyDescriptorPushButton,
                         SIGNAL("clicked()"),
                         self._applyDescriptor)
        
        self.win.connect(self.selectAllPushButton,
                         SIGNAL("clicked()"),
                         self._selectAll)
        
        self.win.connect(self.selectNonePushButton,
                         SIGNAL("clicked()"),
                         self._selectNone)
        
        self.win.connect(self.selectInvertPushButton,
                         SIGNAL("clicked()"),
                         self._invertSelection)
        
        buttonList = [('PM_PushButton', self.applyDescriptorPushButton, 0, 0),
                      ('QSpacerItem', 5, 5, 1, 0), 
                      ('PM_PushButton', self.selectAllPushButton, 2, 0),
                      ('PM_PushButton', self.selectNonePushButton, 3, 0),
                      ('PM_PushButton', self.selectInvertPushButton, 4, 0)]

        self.buttonGrid = PM_WidgetGrid( pmGroupBox, 
                                         widgetList = buttonList)
                                         
        
        self.recenterViewCheckBox  = \
            PM_CheckBox( pmGroupBox,
                         text          =  "Re-center view",
                         setAsDefault  =  True,
                         state         = Qt.Checked)

        self.sequenceTable = PM_TableWidget( pmGroupBox)
        #self.sequenceTable.setModel(self.tableModel)
        self.sequenceTable.resizeColumnsToContents()
        self.sequenceTable.verticalHeader().setVisible(False)
        #self.sequenceTable.setRowCount(0)
        self.sequenceTable.setColumnCount(4)
        
        self.checkbox = QCheckBox()
        
        
        self.sequenceTable.setFixedHeight(345)
        
        self.sequenceTable.setHorizontalHeaderLabels(self.headerdata) 
        ###self._fillSequenceTable()
        

    def _fillSequenceTable(self):
        """
        """        
        
        self.setComboBox = QComboBox()
        
        for chunk in self.win.assy.molecules:
            if chunk.isProteinChunk():
                aa_list = chunk.protein.get_amino_acids()
                aa_list_len = len(aa_list)
                self.sequenceTable.setRowCount(aa_list_len)
                for index in range(aa_list_len):                    
                    item_widget = QTableWidgetItem("")
                    item_widget.setFont(self.labelfont)
                    item_widget.setCheckState(Qt.Checked)
                    item_widget.setTextAlignment(Qt.AlignLeft)
                    item_widget.setSizeHint(QSize(20,12))
                    item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable)
                    self.sequenceTable.setItem(index, 0, item_widget)
                
                    item_widget = QTableWidgetItem(str(index+1))
                    item_widget.setFont(self.labelfont)
                    item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)            
                    item_widget.setTextAlignment(Qt.AlignCenter)
                    self.sequenceTable.setItem(index, 1, item_widget)
                    
                    item_widget = QTableWidgetItem("Any")
                    item_widget.setFont(self.labelfont)
                    item_widget.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
                    item_widget.setTextAlignment(Qt.AlignCenter)
                    self.sequenceTable.setItem(index, 2, item_widget)
                    
                    aa_string = self._get_mutation_descriptor(
                        self._get_aa_for_index(index))

                    item_widget = QTableWidgetItem(aa_string)
                    item_widget.setFont(self.descriptorfont)
                    self.sequenceTable.setItem(index, 3, item_widget)
        
                    self.sequenceTable.setRowHeight(index, 16)
                    
        self.win.connect(self.sequenceTable,
                         SIGNAL("cellClicked(int, int)"),
                         self._sequenceTableCellChanged)
        
        self.sequenceTable.resizeColumnsToContents()
        
        self.sequenceTable.setColumnWidth(0, 35)
        self.sequenceTable.setColumnWidth(2, 80)
        
    def _selectAll(self):
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.item(row, 0).setCheckState(Qt.Checked)
            
    def _selectNone(self):
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.item(row, 0).setCheckState(Qt.Unchecked)
            
    def _invertSelection(self):
        for row in range(self.sequenceTable.rowCount()):
            item_widget = self.sequenceTable.item(row, 0)
            if item_widget.checkState() == Qt.Checked:
                item_widget.setCheckState(Qt.Unchecked)
            else:
                item_widget.setCheckState(Qt.Checked)
                
    def _get_mutation_descriptor(self, aa):
        """
        """
        aa_string = "GAVILMFWCSTYNQDEHKRP"
        
        range = aa.get_mutation_range()                    
        if range == "NATRO" or \
           range == "NATAA":
            code = aa.get_one_letter_code()                    
            aa_string = re.sub("[^"+code+"]",'_', aa_string)
        elif range == "POLAR":
            aa_string = "________CSTYNQDEHKR_"
        elif range == "APOLA":
            aa_string = "GAVILMFW___________P"

        return aa_string
    
    def _get_aa_for_index(self, index, expand=False):
        """
        """
        # Center on a selected amino acid.
        for chunk in self.win.assy.molecules:
            if chunk.isProteinChunk():
                chunk.protein.set_current_amino_acid_index(index)
                current_aa = chunk.protein.get_current_amino_acid()
                if expand:
                    chunk.protein.collapse_all_rotamers()
                    chunk.protein.expand_rotamer(current_aa)
                return current_aa 

        return None
    
    def _sequenceTableCellChanged(self, crow, ccol):
        #print "CELL CHANGED: ", (crow, ccol)
        item = self.sequenceTable.item(crow, ccol)
        #print "ITEM = ", item
        
        for row in range(self.sequenceTable.rowCount()):
            self.sequenceTable.removeCellWidget(row, 2)
            self.sequenceTable.setRowHeight(row, 16)
        if ccol == 2:
            # Make the row a little bit wider.
            self.sequenceTable.setRowHeight(crow, 22)
            # Create and insert a Combo Box into a current cell. 
            self.setComboBox = QComboBox()
            self.setComboBox.addItems(self.set_names)
            self.win.connect(self.setComboBox,
                             SIGNAL("currentIndexChanged(int)"),
                             self._setComboBoxIndexChanged)
            
            self.sequenceTable.setCellWidget(crow, 2, self.setComboBox)
        
        current_aa = self._get_aa_for_index(crow, expand=True)
        if current_aa:
            # Center on the selected amino acid.
            if self.recenterViewCheckBox.isChecked():
                ca_atom = current_aa.get_c_alpha_atom()
                if ca_atom:
                    self.win.glpane.pov = -ca_atom.posn()                            
            self.win.glpane.gl_update()
        
    def _applyDescriptor(self):
        """        
        """
        cdes = self.descriptorsTable.currentRow()
        for row in range(self.sequenceTable.rowCount()):
            #print "row = ", row
            self._setComboBoxIndexChanged(cdes, tablerow = row, selectedOnly = True)
            
    def _setComboBoxIndexChanged( self, index, tablerow = None, selectedOnly = False):
        """
        """
        #print "INDEX = ", index
        if tablerow is None: 
            crow = self.sequenceTable.currentRow()
        else:
            crow = tablerow
        #print "current row: ", crow
        item = self.sequenceTable.item(crow, 2)
        if item:
            cbox = self.sequenceTable.item(crow, 0)
            if not selectedOnly or \
               cbox.checkState() == Qt.Checked:
                item.setText(self.set_names[index])
                item = self.sequenceTable.item(crow, 3)
                aa = self._get_aa_for_index(crow)
                aa.set_mutation_range(self.rosetta_set_names[index])
                item.setText(self._get_mutation_descriptor(aa))
        
        ###self._write_resfile()
        
    def _write_resfile(self):
        from protein.model.Protein import write_rosetta_resfile
        for chunk in self.win.assy.molecules:
            if chunk.isProteinChunk():
                write_rosetta_resfile("/Users/piotr/test.resfile", chunk)
                return
        
    def _addWhatsThisText( self ):
        
        #from ne1_ui.WhatsThisText_for_PropertyManagers import WhatsThis_EditResidues_PropertyManager
        #WhatsThis_EditResidues_PropertyManager(self)
        pass
    
    def _addToolTipText(self):
        #from ne1_ui.ToolTipText_for_PropertyManagers import ToolTip_EditProteinDisplayStyle_PropertyManager 
        #ToolTip_EditProteinDisplayStyle_PropertyManager(self)
        pass
        
    def scrollToPosition(self, index):
        """
        Scrolls the Sequence Table to a given sequence position.
        """
        item = self.sequenceTable.item(index, 0)
        if item:
            self.sequenceTable.scrollToItem(item)