Source code for schrodinger.ui.qt.recent_completer

from schrodinger.Qt import QtCore
from schrodinger.Qt import QtWidgets
from schrodinger.ui.qt import swidgets
from schrodinger.ui.qt.appframework2 import settings

STRING_DELIMITER = '@@@'
SEPARATOR = ''


[docs]class StringListModelInterface: """ Interface for Qt classes that can use a QStringListModel. You add to the QStringListModel by calling addSuggestion. If a prefkey is passed to the init, then these suggestions will be stored in Maestro, and reloaded next time the widget is created """ MODEL_CLASS = QtCore.QStringListModel
[docs] def __init__(self, prefkey=None, suggestion_limit=20): """ :param prefkey: if defined, a unique string that defines where this object's suggestions can be saved to and loaded from persistently :type prefkey: str or None :param suggestion_limit: the maximum number of suggestions that this object will store; must be a nonnegative integer or None :type suggestion: int or None """ model = self.MODEL_CLASS(parent=self) self.setModel(model) self._prefkey = prefkey suggestions = self._getPersistentSuggestions() if prefkey else [] self.suggestion_limit = suggestion_limit self.setSuggestions(suggestions)
@property def suggestion_limit(self): """ :return: the maximum number of completion suggestions that this object will remember; if `None`, there is no limit. :rtype: int or None """ return self._suggestion_limit @suggestion_limit.setter def suggestion_limit(self, suggestion_limit): """ :param suggestion_limit: the new limit for the number of completion suggestions. Must be a nonnegative integer or `None` (for no limit) :type suggestion_limit: int or None """ if suggestion_limit is not None and suggestion_limit < 0: msg = 'String limit must be a nonnegative integer or None.' raise ValueError(msg) self._suggestion_limit = suggestion_limit self._updateModel()
[docs] def setSuggestions(self, suggestions): """ Replace the current set of completion suggestions with the supplied values. :param suggestions: a new list of completion suggestions to set on this object :rtype suggestions: list(str) """ model = self.model() model.setStringList(suggestions) self._updateModel()
[docs] def addSuggestion(self, new_suggestion): """ Add a new completion suggestion to this object. If it already exists in this object, put it to the top of the list to indicate that it the most recent suggestion. :param new_suggestion: a new completion suggestion :type new_suggestion: str """ model = self.model() suggestions = model.stringList() if new_suggestion in suggestions: suggestions.remove(new_suggestion) suggestions = [new_suggestion] + suggestions model.setStringList(suggestions) self._updateModel()
def _updateModel(self): """ Cut any extra completion suggestions from this object if a limit is set. Save the resulting completion list persistently if a preference key is set. """ model = self.model() suggestions = model.stringList() limit = self._suggestion_limit while limit is not None and len(suggestions) > limit: suggestions.pop() model.setStringList(suggestions) if self._prefkey is not None: self._setPersistentSuggestions(suggestions) def _getPersistentSuggestions(self): """ Attempt to read and return a list of completion suggestions saved persistently at a location described by this object's preference key. :return: a list of completion suggestions, if found :rtype: list(str) """ store_suggestion = settings.get_persistent_value(self._prefkey, '') if store_suggestion: return store_suggestion.split(STRING_DELIMITER) return [] def _setPersistentSuggestions(self, suggestions): """ Save the specified completion suggestions persistently at a location described by this object's preference key. :param suggestions: a list of completion suggestions :type suggestions: list(str) """ store_suggestion = STRING_DELIMITER.join(suggestions) settings.set_persistent_value(self._prefkey, store_suggestion)
[docs]class RecentCombo(QtWidgets.QComboBox, StringListModelInterface): """ A `QComboBox` which is able to store its past values in Maestro persistent settings. You add to this combobox by using `addSuggestion`. When adding a suggestion, the model gets reset in the process, which may clear selection and emit a signal indicating that the selection has changed. """
[docs]class RecentCompleter(QtWidgets.QCompleter, StringListModelInterface): """ A `QLineEdit` completer that can remember a limited number of completion suggestions, and optionally retain completion suggestions persistently. """
[docs]class PlaceholderRecentCombo(swidgets.PlaceholderComboMixin, RecentCombo): """ A RecentCombo which enables persistent options as well as placeholder text """
[docs]class SeparatorStringModel(QtCore.QStringListModel): """ A QStringList model which supports separator. Subclass needs to add the separator at desired position using 'setStringList' method. """
[docs] def data(self, index, role=QtCore.Qt.DisplayRole): if role == QtCore.Qt.AccessibleDescriptionRole: if self.isSeparator(index): # QComboBox delegate uses the AccessibleDescriptionRole to # indicate that the item is a separator return "separator" else: return super().data(index, role)
[docs] def isSeparator(self, index): """ Returns True if the item corresponding to the given index is a separator """ return self.data(index, QtCore.Qt.DisplayRole) == SEPARATOR
[docs] def flags(self, index): """ The separator row should not be enabled or selectable """ flags = super().flags(index) if self.isSeparator(index): flags &= ~(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) return flags
[docs]class BrowseStringModel(SeparatorStringModel): """ A QStringList model which adds a separator and a browse option for comboboxes that need a browse button appended to the end :cvar BROWSE: Text for browse option. :vartype BROWSE: str """ BROWSE = "Browse..."
[docs] def stringList(self): """ Return the string list, not including the separator and browse :return: """ return super().stringList()[:-2]
[docs] def setStringList(self, strings): """ When setting a string list, add a separator and browse option """ super().setStringList(strings + [SEPARATOR, self.BROWSE])
[docs]class BrowsePlaceholderRecentCombo(PlaceholderRecentCombo): """ A PlaceholderRecentCombo which always keeps a Browse option at the bottom. :ivar browseSelected: A signal emitted when the browse option in the combobox is selected. """ browseSelected = QtCore.pyqtSignal() MODEL_CLASS = BrowseStringModel
[docs] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.currentTextChanged.connect(self._checkBrowseSelected)
@QtCore.pyqtSlot(str) def _checkBrowseSelected(self, text): if text == self.MODEL_CLASS.BROWSE: self.browseSelected.emit()