Source code for ccpn.ui.gui.popups.SubstancePropertiesPopup

"""
Module Documentation here
"""
#=========================================================================================
# Licence, Reference and Credits
#=========================================================================================
__copyright__ = "Copyright (C) CCPN project (http://www.ccpn.ac.uk) 2014 - 2021"
__credits__ = ("Ed Brooksbank, Luca Mureddu, Timothy J Ragan & Geerten W Vuister")
__licence__ = ("CCPN licence. See http://www.ccpn.ac.uk/v3-software/downloads/license")
__reference__ = ("Skinner, S.P., Fogh, R.H., Boucher, W., Ragan, T.J., Mureddu, L.G., & Vuister, G.W.",
                 "CcpNmr AnalysisAssign: a flexible platform for integrated NMR analysis",
                 "J.Biomol.Nmr (2016), 66, 111-124, http://doi.org/10.1007/s10858-016-0060-y")
#=========================================================================================
# Last code modification
#=========================================================================================
__modifiedBy__ = "$modifiedBy: Ed Brooksbank $"
__dateModified__ = "$dateModified: 2021-03-12 18:01:39 +0000 (Fri, March 12, 2021) $"
__version__ = "$Revision: 3.0.3 $"
#=========================================================================================
# Created
#=========================================================================================
__author__ = "$Author: Luca Mureddu $"
__date__ = "$Date: 2017-03-30 11:28:58 +0100 (Thu, March 30, 2017) $"
#=========================================================================================
# Start of code
#=========================================================================================

from PyQt5 import QtCore, QtWidgets
from ccpn.ui.gui.widgets.MoreLessFrame import MoreLessFrame
from ccpn.ui.gui.popups.AttributeEditorPopupABC import ComplexAttributeEditorPopupABC, VList, MoreLess, _complexAttribContainer
from ccpn.ui.gui.widgets.CompoundWidgets import CompoundViewCompoundWidget
from ccpn.core.Substance import Substance


SEP = ', '
SELECT = '> Select <'
LESS_BUTTON = 'Show less'
MORE_BUTTON = 'Show more'
TYPENEW = 'Type_New'
LABELLING = ['', TYPENEW, '15N', '15N,13C', '15N,13C,2H', 'ILV', 'ILVA', 'ILVAT', 'SAIL', '1,3-13C- and 2-13C-Glycerol']
BUTTONSTATES = ['New', 'From Existing']

from ccpn.ui.gui.widgets.CompoundWidgets import EntryCompoundWidget, ScientificSpinBoxCompoundWidget, \
    RadioButtonsCompoundWidget, PulldownListCompoundWidget, SpinBoxCompoundWidget, TextEditorCompoundWidget


[docs]class SubstancePropertiesPopup(ComplexAttributeEditorPopupABC): """ Substance attributes editor popup """ def _getLabelling(self, obj): """Populate the labelling pulldown """ labels = LABELLING.copy() newLabel = str(self.obj.labelling or '') if newLabel not in labels: labels.append(newLabel) self.labelling.modifyTexts(labels) self.labelling.select(newLabel or '') def _getCurrentSubstances(self, obj): """Populate the current substances pulldown """ substancePulldownData = [SELECT] for substance in self.project.substances: substancePulldownData.append(str(substance.id)) self.currentSubstances.pulldownList.setData(substancePulldownData) def _getSpectrum(self, attr, default): """change the value from the substance object into a pid for the pulldown """ value = getattr(self, attr, default) if value and len(value) > 0: return value[0].pid def _setSpectrum(self, attr, value): """change the pid for the pulldown into the tuple for the substance object """ spectrum = self.project.getByPid(value) if spectrum: setattr(self, attr, (spectrum,)) else: setattr(self, attr, []) def _getCurrentSpectra(self, obj): """Populate the spectrum pulldown """ spectrumPulldownData = [SELECT] for spectrum in self.project.spectra: spectrumPulldownData.append(str(spectrum.pid)) self.referenceSpectra.pulldownList.setData(spectrumPulldownData) def _getSynonym(self, attr, default): """change the value from the substance object into a str for the synonym """ value = getattr(self, attr, default) if value and len(value) > 0: return str(value[0]) def _setSynonym(self, attr, value): """change the str for the synonym into the tuple for the substance object """ if value: setattr(self, attr, (str(value),)) else: setattr(self, attr, []) def _setLabelling(self, attr, value): """Set the labelling with None replacing empty string from the pulldown """ value = value if value else None setattr(self, attr, value) klass = Substance HWIDTH = 150 attributes = VList([VList([('Select Source', RadioButtonsCompoundWidget, None, None, None, None, {'texts' : BUTTONSTATES, 'selectedInd': 1, 'direction' : 'h', 'hAlign' : 'l'}), ('Current Substances', PulldownListCompoundWidget, None, None, _getCurrentSubstances, None, {'editable': False}), ('Name', EntryCompoundWidget, getattr, setattr, None, None, {'backgroundText': '> Enter name <'}), ('Labelling', PulldownListCompoundWidget, getattr, _setLabelling, _getLabelling, None, {'editable': True}), ], queueStates=False, hWidth=None, group=1, ), # VList([('comment', TextEditorCompoundWidget, getattr, setattr, None, None, {'backgroundText': '> Optional <', # 'addGrip': False, 'addWordWrap': True, # 'fitToContents': True, # 'maximumRows': 5}), ], VList([('Comment', EntryCompoundWidget, getattr, setattr, None, None, {'backgroundText': '> Optional <',}), ], hWidth=None, group=1, ), MoreLess([('Synonyms', EntryCompoundWidget, _getSynonym, _setSynonym, None, None, {'backgroundText': ''}), ('Reference Spectra', PulldownListCompoundWidget, _getSpectrum, _setSpectrum, _getCurrentSpectra, None, {'editable': False}), ('Empirical Formula', EntryCompoundWidget, getattr, setattr, None, None, {'backgroundText': ''}), ('Molecular Mass', ScientificSpinBoxCompoundWidget, getattr, setattr, None, None, {'min': 0}), ('User Code', EntryCompoundWidget, getattr, setattr, None, None, {'backgroundText': ''}), ('Cas Number', EntryCompoundWidget, getattr, setattr, None, None, {'backgroundText': ''}), ('Atom Count', SpinBoxCompoundWidget, getattr, setattr, None, None, {'min': 0}), ('Bond Count', SpinBoxCompoundWidget, getattr, setattr, None, None, {'min': 0}), ('Ring Count', SpinBoxCompoundWidget, getattr, setattr, None, None, {'min': 0}), ('hBond Donor Count', SpinBoxCompoundWidget, getattr, setattr, None, None, {'min': 0}), ('hBond Acceptor Count', SpinBoxCompoundWidget, getattr, setattr, None, None, {'min': 0}), ('Polar Surface Area', ScientificSpinBoxCompoundWidget, getattr, setattr, None, None, {'min': 0}), ('Log Partition Coefficient', ScientificSpinBoxCompoundWidget, getattr, setattr, None, None, {'min': 0}), ], hWidth=None, name='Advanced', ), MoreLess([VList([('Smiles', EntryCompoundWidget, getattr, setattr, None, None, {'backgroundText': ''})], hWidth=None, group=2, ), VList([('Compound View', CompoundViewCompoundWidget, None, None, None, None, {})], queueStates=False, hWidth=None, group=2, ), ], name='Compound', ), ], hWidth=None, ) USESCROLLWIDGET = True FIXEDWIDTH = False FIXEDHEIGHT = False LABELEDITING = True def __init__(self, parent=None, mainWindow=None, substance=None, sampleComponent=None, newSubstance=False, **kwds): """ Initialise the widget """ self.EDITMODE = not newSubstance self.WINDOWPREFIX = 'New ' if newSubstance else 'Edit ' if newSubstance: obj = _complexAttribContainer(self) else: obj = substance self.sampleComponent = sampleComponent self.substance = substance # initialise the widgets in the popup super().__init__(parent=parent, mainWindow=mainWindow, obj=obj, size=(500, 100), **kwds) # attach callbacks to the new/fromSubstances radioButton if self.EDITMODE: self.selectSource.setEnabled(False) self.currentSubstances.setEnabled(False) self.selectSource.setVisible(False) self.currentSubstances.setVisible(False) self.name.setEnabled(True) # False self.labelling.setEnabled(True) # False else: self.selectSource.radioButtons.buttonGroup.buttonClicked.connect(self._changeSource) self.currentSubstances.pulldownList.activated.connect(self._fillInfoFromSubstance) self.labelling.pulldownList.activated.connect(self._labellingSpecialCases) self.smiles.entry.textEdited.connect(self._smilesChanged) self._initialiseCompoundView() self._firstSize = self.sizeHint() self._size = self.sizeHint() self.mainWidget.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) self._setDialogSize() self._moreLessFrames = [] for item in self.findChildren(MoreLessFrame): item.setCallback(self._moreLessCallback) # assume all are initially closed self._moreLessFrames.append(item) self._baseSize = self.sizeHint() for item in self._moreLessFrames: self._baseSize -= item.sizeHint() def _setEnabledState(self, fromSubstances): if fromSubstances: self.currentSubstances.setEnabled(True) else: self.currentSubstances.setEnabled(False) self.labelling.setEnabled(True) def _changeSource(self, button): self._setEnabledState(True if button.get() == BUTTONSTATES[1] else False) def _fillInfoFromSubstance(self, index): selected = self.currentSubstances.getText() if selected != SELECT: substance = self.project.getByPid('SU:' + selected) if substance: self.name.setText(str(substance.name)) newLabel = str(substance.labelling or '') if newLabel not in self.labelling.getTexts(): self.labelling.pulldownList.addItem(text=newLabel) self.labelling.pulldownList.set(newLabel or '') self.labelling.setEnabled(True) # False else: self.name.setText('') self.labelling.pulldownList.setIndex(0) self.labelling.setEnabled(True) if hasattr(self.name, '_queueCallback'): self.name._queueCallback() if hasattr(self.labelling, '_queueCallback'): self.labelling._queueCallback() def _labellingSpecialCases(self, index): selected = self.labelling.pulldownList.currentText() if selected == TYPENEW: self.labelling.pulldownList.setEditable(True) else: self.labelling.pulldownList.setEditable(self.LABELEDITING) def _populate(self): super()._populate() self.labelling.setEnabled(True) self.labelling.pulldownList.setEditable(self.LABELEDITING) # populate the compoundView on a revert self._smilesChanged(self.obj.smiles) def _applyAllChanges(self, changes): if self.EDITMODE: super()._applyAllChanges(changes) name = self.name.getText() labelling = self.labelling.getText() or None if name != self.obj.name or labelling != self.obj.labelling: self.obj.rename(name=name, labelling=labelling) else: # if new substance then call the new method - self.obj is container of new attributes name = self.name.getText() labelling = self.labelling.getText() or None self.obj = self.project.newSubstance(name=name, labelling=labelling) # only apply items that are not in the _VALIDATTRS list - defined by queueStates=True in attributes super()._applyAllChanges(changes) def _initialiseCompoundView(self): view = self.compoundView.compoundView if self.obj and isinstance(self.obj, Substance): chemComps = self.obj._getChemComps() # will take only if there is one. We don't want display a chain here! if len(chemComps) == 1: # if chemComp give priority to the Smiles, as it preserves the atom nomenclature. from ccpn.ui.gui.widgets.CompoundView import importChemComp compound = importChemComp(chemComps[0]) view.setCompound(compound) self.smiles.entry.setEnabled(False) # otherwise will override the chemComp return if self.obj.smiles is not None: view.setSmiles(self.obj.smiles) else: view.setSmiles('') # NOTE:ED - initial size has been moved to resizeEvent in compoundWidget def _smilesChanged(self, value): view = self.compoundView.compoundView view.setSmiles(value or '') # resize to the new items view.updateAll() view.scene.setSceneRect(view.scene.itemsBoundingRect()) view.resetView() view.zoomLevel = 1.0 def _moreLessCallback(self, moreLessFrame): """Resize the dialog to contain the opened/closed moreLessFrames """ _size = QtCore.QSize(self._baseSize) for item in self._moreLessFrames: _size += item.sizeHint() _size.setWidth(self.width()) self.resize(_size)