Source code for schrodinger.application.jaguar.gui.solvent_selector
"""
A filterable selector for solvents.
Copyright Schrodinger, LLC. All rights reserved.
"""
import csv
from functools import partial
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtWidgets
from schrodinger.Qt.QtCore import Qt
from schrodinger.application.jaguar import jaguar_keyword_utils
from schrodinger.application.matsci import msutils
from schrodinger.ui.qt import filter_list
from schrodinger.ui.qt import swidgets
from schrodinger.utils import csv_unicode
[docs]class SolventListWidgetItem(QtWidgets.QListWidgetItem):
"""
A solvent that appears in the selector.
"""
[docs] def __init__(self, name, common, halogenated, aromatic, hydrocarbon,
carbonyl, polar, nonpolar):
super().__init__(name)
self.name = name
self.common = common
self.halogenated = halogenated
self.aromatic = aromatic
self.hydrocarbon = hydrocarbon
self.carbonyl = carbonyl
self.polar = polar
self.nonpolar = nonpolar
[docs]class SolventSelectorFilterListPopUp(filter_list.FilterListPopUp):
"""
A pop up that allows the solvents to be filtered by category.
"""
[docs] def __init__(self, parent):
list_items = self._createListItems()
cbs = self._createFilterCheckBoxes()
super().__init__(parent, list_items, cbs.values(),
'Limit list to matching solvents')
# make the polar and non-polar check boxes mutually exclusive
self._polar_group = swidgets.SCheckboxButtonGroup(self)
self._polar_group.addButton(cbs["polar"])
self._polar_group.addButton(cbs["nonpolar"])
def _createListItems(self):
"""
:return: A tuple of items for the list widget.
:rtype: tuple(SolventListWidgetItem)
"""
list_items = []
with csv_unicode.reader_open(jaguar_keyword_utils.SOLVENTS) as fh:
reader = csv.DictReader(fh)
for row in reader:
name = row.pop("name")
# convert the category values from strings of "0" or "1" to
# Booleans
categories = {
key: msutils.setting_to_bool(val)
for key, val in row.items()
}
list_items.append(SolventListWidgetItem(name, **categories))
return tuple(list_items)
def _createFilterCheckBoxes(self):
"""
:return: A dictionary of filter checkboxes in the form
{`SolventListWidgetItem` attribute name: check box}
:rtype: dict(str, filter_list.FilterCheckBox)
"""
# tuples of (text to display in GUI, attribute name, enabled by default)
cb_text_and_attr_name = (
("Common", "common", True),
("Halogenated", "halogenated", False),
("Aromatic", "aromatic", False),
("Hydrocarbon", "hydrocarbon", False),
("Carbonyl", "carbonyl", False),
("Polar", "polar", False),
("Non-polar", "nonpolar", False),
)
def filter_on(attr_name):
return lambda list_item: getattr(list_item, attr_name)
return {
attr_name: filter_list.FilterCheckBox(
cb_text, filter_on(attr_name), on_by_default=on_by_default)
for cb_text, attr_name, on_by_default in cb_text_and_attr_name
}
[docs] def getSolvent(self):
"""
:return: The currently selected solvent
:rtype: str or None
"""
current_item = self._list_widget.currentItem()
if not current_item:
return None
return current_item.name
[docs] def setSolvent(self, solvent=None):
"""
Set the current solvent.
:param solvent: Solvent value to be set. If None, no solvent will be
selected.
:type solvent: str or None
:raise ValueError: If the specified solvent was not found.
"""
if solvent is None:
self._list_widget.setCurrentItem(None)
return
items = self._list_widget.findItems(solvent,
Qt.MatchFlag.MatchFixedString)
if len(items) != 1:
raise ValueError(f"Solvent {solvent} not found")
self._list_widget.setCurrentItem(items[0])
[docs]class SolventSelectorFilterListToolButton(
filter_list.ToolButtonWithFilterListPopUp):
"""
Custom tool button with a solvent selector filter list pop up.
"""
POP_UP_CLASS = SolventSelectorFilterListPopUp
solventChanged = QtCore.pyqtSignal(str)
[docs] def __init__(self, parent):
super().__init__(parent)
self.popUpClosing.connect(self._emitSolventChanged)
[docs] def getSolvent(self):
"""
:return: The currently selected solvent
:rtype: str or None
"""
return self._pop_up.getSolvent()
[docs] def setSolvent(self, solvent=None):
"""
Set the current solvent.
:param solvent: Solvent value to be set. If None, no solvent will be
selected.
:type solvent: str or None
:raise ValueError: If the specified solvent was not found.
"""
self._pop_up.setSolvent(solvent)
self._emitSolventChanged()
def _emitSolventChanged(self):
self.solventChanged.emit(self.getSolvent())