# Copyright 2008 Nanorex, Inc. See LICENSE file for details.
"""
CompareProteins_PropertyManager.py
The CompareProteins_PropertyManager class provides a Property Manager
for the B{Compare Proteins} command on the flyout toolbar in the
Build > Protein mode.
@author: Piotr
@version: $Id$
@copyright: 2008 Nanorex, Inc. See LICENSE file for details.
TODO:
- Switch display styles of selected proteins to diPROTEIN (instead of the GDS).
- PM color comboboxes to choose the "difference colors".
BUGS:
- Previously compared proteins still show differences after comparing a new set of proteins.
- "Hide differences" button should be disabled (or hidden) when there are no differences.
"""
import foundation.env as env
from command_support.Command_PropertyManager import Command_PropertyManager
from utilities.prefs_constants import workingDirectory_prefs_key
from utilities.constants import yellow
from PyQt4.Qt import SIGNAL
from PM.PM_PushButton import PM_PushButton
from PM.PM_GroupBox import PM_GroupBox
from PM.PM_LineEdit import PM_LineEdit
from PM.PM_DoubleSpinBox import PM_DoubleSpinBox
from PM.PM_Constants import PM_DONE_BUTTON
from PM.PM_Constants import PM_WHATS_THIS_BUTTON
from protein.model.Protein import getAllProteinChunksInPart
from utilities.constants import diPROTEIN
from utilities.Log import redmsg
_superclass = Command_PropertyManager
class CompareProteins_PropertyManager(Command_PropertyManager):
"""
The CompareProteins_PropertyManager class provides a Property Manager
for the B{Compare Proteins} command on the Build Protein flyout toolbar.
@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
@ivar proteinChunk1: The first currently selected protein to be compared.
@type proteinChunk1: protein chunk
@ivar proteinChunk2: The second currently selected protein to be compared.
@type proteinChunk2: protein chunk
"""
title = "Compare Proteins"
pmName = title
iconPath = "ui/actions/Command Toolbar/BuildProtein/Compare.png"
proteinChunk1 = None
proteinChunk2 = None
def __init__( self, command ):
"""
Constructor for the property manager.
"""
self.threshold = 10.0
_superclass.__init__(self, command)
self.showTopRowButtons( PM_DONE_BUTTON | \
PM_WHATS_THIS_BUTTON)
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.comparePushButton,
SIGNAL("clicked()"),
self._compareProteins)
change_connect(self.thresholdDoubleSpinBox,
SIGNAL("valueChanged(double)"),
self._thresholdChanged)
change_connect(self.hidePushButton,
SIGNAL("clicked()"),
self._hideDifferences)
return
def close(self):
"""
Closes the Property Manager. Overrides EditCommand_PM.close()
"""
env.history.statusbar_msg("")
self._resetAminoAcids()
_superclass.close(self)
# Restore the original global display style.
self.o.setGlobalDisplayStyle(self.originalDisplayStyle)
return
def show(self):
"""
Show the PM. Extends superclass method.
@note: _update_UI_do_updates() gets called immediately after this and
updates PM widgets with their correct values/settings.
"""
_superclass.show(self)
env.history.statusbar_msg("")
# Force the Global Display Style to "Protein" since this is the only way
# to see comparisons. The global display style will be restored when leaving
# this command (via self.close()).
self.originalDisplayStyle = self.o.displayMode
self.o.setGlobalDisplayStyle(diPROTEIN)
return
def _addGroupBoxes( self ):
"""
Add the Property Manager group boxes.
"""
self._pmGroupBox1 = PM_GroupBox( self,
title = "Compare")
self._loadGroupBox1( self._pmGroupBox1 )
return
def _addWhatsThisText( self ):
"""
What's This text for widgets in this Property Manager.
"""
pass
def _addToolTipText(self):
"""
Tool Tip text for widgets in this Property Manager.
"""
pass
def _loadGroupBox1(self, pmGroupBox):
"""
Load widgets in group box.
"""
self.structure1LineEdit = \
PM_LineEdit( pmGroupBox,
label = "First structure:",
setAsDefault = False)
self.structure1LineEdit.setEnabled(False)
self.structure2LineEdit = \
PM_LineEdit( pmGroupBox,
label = "Second structure:",
setAsDefault = False)
self.structure2LineEdit.setEnabled(False)
self.thresholdDoubleSpinBox = \
PM_DoubleSpinBox( pmGroupBox,
label = "Threshold:",
value = self.threshold,
setAsDefault = True,
minimum = 0.0,
maximum = 360.0,
decimals = 1,
singleStep = 30.0,
suffix = " deg",
spanWidth = False)
self.comparePushButton = \
PM_PushButton( pmGroupBox,
text = "Compare",
setAsDefault = True)
self.hidePushButton = \
PM_PushButton( pmGroupBox,
text = "Hide differences",
setAsDefault = True)
return
def _compareProteins(self):
"""
Slot for Compare button.
Compares two selected proteins of the same length.
Amino acids that differ greater than the "threshold"
value are displayed in two colors (red for the first protein
and yellow for the second protein) and are only visible when
the two proteins are displayed in the
reduced display style.
"""
from utilities.constants import red, orange, green, cyan
if not self.proteinChunk1 or \
not self.proteinChunk2:
return
protein_1 = self.proteinChunk1.protein
protein_2 = self.proteinChunk2.protein
if protein_1 and \
protein_2:
aa_list_1 = protein_1.get_amino_acids()
aa_list_2 = protein_2.get_amino_acids()
protein_1.collapse_all_rotamers()
protein_2.collapse_all_rotamers()
if len(aa_list_1) == len(aa_list_2):
for aa1, aa2 in zip (aa_list_1, aa_list_2):
aa1.color = None
aa2.color = None
#aa1.collapse()
#aa2.collapse()
if aa1.get_one_letter_code() != aa2.get_one_letter_code():
aa1.set_color(red)
aa1.expand()
aa2.set_color(yellow)
aa2.expand()
else:
max = 0.0
for chi in range(0, 3):
angle1 = aa1.get_chi_angle(chi)
angle2 = aa2.get_chi_angle(chi)
if angle1 and \
angle2:
if angle1 < 0.0:
angle1 += 360.0
if angle2 < 0.0:
angle2 += 360.0
diff = abs(angle1 - angle2)
if diff > max:
max = diff
if max >= self.threshold:
# This be a parameter.
aa1.set_color(green)
aa1.expand()
aa2.set_color(cyan)
aa2.expand()
self.win.glpane.gl_update()
else:
msg = "The lengths of compared proteins are not equal."
self.updateMessage(msg)
env.history.redmsg(msg)
return
def _hideDifferences(self):
"""
Slot for the "Hide differences" button.
Hides amino acids that differ greater than the "threshold" value.
@warning: Untested. Code looks suspicious.
"""
if not self.proteinChunk1 or \
not self.proteinChunk2:
return
protein_1 = self.proteinChunk1.protein
protein_2 = self.proteinChunk2.protein
if protein_1 and \
protein_2:
aa_list_1 = protein_1.get_amino_acids()
aa_list_2 = protein_2.get_amino_acids()
if len(aa_list_1) == len(aa_list_2):
protein_1.collapse_all_rotamers() #@@@
protein_2.collapse_all_rotamers() #@@@
for aa1, aa2 in zip (aa_list_1, aa_list_2):
aa1.color = None
aa2.color = None
aa1.collapse()
aa2.collapse()
self.win.glpane.gl_update()
return
def _thresholdChanged(self, value):
"""
Slot for Threshold spinbox.
"""
self.threshold = value
self._compareProteins()
return
def _resetAminoAcids(self):
"""
Resets the color and collapse all amino acids of all proteins.
"""
proteinChunkList = getAllProteinChunksInPart(self.win.assy)
for proteinChunk in proteinChunkList:
proteinChunk.protein.collapse_all_rotamers()
aa_list = proteinChunk.protein.get_amino_acids()
for aa in aa_list:
aa.color = None
aa.collapse()
self.win.glpane.gl_update()
return
def _update_UI_do_updates(self):
"""
Overrides superclass method.
@see: Command_PropertyManager._update_UI_do_updates()
"""
self.proteinChunk1 = None
self.proteinChunk2 = None
self.comparePushButton.setEnabled(False)
self.hidePushButton.setEnabled(False)
selectedProteinList = self.win.assy.getSelectedProteinChunks()
if len(selectedProteinList) == 0:
self.structure1LineEdit.setText("")
self.structure2LineEdit.setText("")
msg = "Select two structures of the same length in the graphics area, "\
"then click the Compare button to compare them."
elif len(selectedProteinList) == 1:
self.proteinChunk1 = selectedProteinList[0]
aa1_count = " (%d)" % self.proteinChunk1.protein.count_amino_acids()
self.structure1LineEdit.setText(self.proteinChunk1.name + aa1_count)
self.structure2LineEdit.setText("")
msg = "Select one more structure in the graphics area that is the same "\
"length as " + self.proteinChunk1.name + ". "\
"Then click the Compare button to compare them."
elif len(selectedProteinList) == 2:
self.proteinChunk1 = selectedProteinList[0]
aa1_count = " (%d)" % self.proteinChunk1.protein.count_amino_acids()
self.structure1LineEdit.setText(self.proteinChunk1.name + aa1_count)
self.proteinChunk2 = selectedProteinList[1]
aa2_count = " (%d)" % self.proteinChunk2.protein.count_amino_acids()
self.structure2LineEdit.setText(self.proteinChunk2.name + aa2_count)
if aa1_count == aa2_count:
self.comparePushButton.setEnabled(True)
self.hidePushButton.setEnabled(True)
msg = "Click the Compare button to compare the two selected structures."
else:
msg = "%s and %s are not the same length." % \
(self.proteinChunk1.name, self.proteinChunk2.name)
msg = redmsg(msg)
else:
self.structure1LineEdit.setText("")
self.structure2LineEdit.setText("")
msg = redmsg("Too many proteins selected.")
self.updateMessage(msg)
env.history.redmsg(msg)
return