Source code for schrodinger.application.bioluminate.bwidgets

"""
Collection of widgets common to multiple BioLuminate panels.

Copyright (c) Schrodinger, LLC. All rights reserved
"""

#- Imports -------------------------------------------------------------------

import os

import schrodinger.ui.qt.filedialog as filedialog
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtGui
from schrodinger.Qt import QtWidgets
from schrodinger.ui.qt import layout
from schrodinger.ui.qt.swidgets import SpinnerIcon
from schrodinger.ui.qt.standard.colors import LightModeColors
from schrodinger.ui.sequencealignment.sequence_viewer import SequenceViewer

from .actions import icons
from .actions.configs import FIND_PATTERN_ACTIONS
from .actions.configs import IMPORT_STRUCTURES
from .actions.factory import Factory

#- Classes -------------------------------------------------------------------


[docs]class ImportWidget(QtWidgets.QWidget): """ """
[docs] def __init__(self, parent): """ Construct widget. """ self.parent = parent super(ImportWidget, self).__init__(parent) self._widgets = []
[docs] def asGrid(self): return layout.grid(self._widgets)
[docs] def createImportWidget(self, button_title, action_params=None, objname=None, action_order=None, icon=icons.MSV_OPEN_FILE): """ Returns a list of widgets that comprise an `ImportWidget`. """ action_params = action_params or IMPORT_STRUCTURES # Set up the actions to parent this widget's parent. All slots # will be in the context of self.parent factory = Factory(self.parent) factory.setActions(action_params, action_order=action_order) self.button = QtWidgets.QPushButton(self.tr(button_title), self.parent) icon = QtGui.QIcon(icon) self.button.setIcon(QtGui.QIcon(icon)) self.button.setMenu(factory.getMenu()) line_edit = QtWidgets.QLineEdit(self.parent) line_edit.setReadOnly(True) line_edit.setMinimumSize(250, 0) widgets = [self.button, line_edit] self._widgets.append(widgets) return widgets
[docs]class SequenceFileDialog(filedialog.FileDialog): """ Custom class to handle opening files related to sequences. """ CAPTION = 'Import Sequences' DEFAULT_FILTERS = ';;'.join([ 'FASTA (*.fasta *.fst *.fas *.seq)', 'Maestro (*.mae *.maegz *.mae.gz )', 'PDB (*.pdb *.ent)', 'SWISSPROT (*.sw *.sp *.swiss *.swissprot)', 'GCG (*.gcg *.msf)', 'EMBL (*.embl *.emb)', 'PIR (*.pir)', 'All Files (*.*)' ]) """ The default MSV filters. """ REFERENCE_FILTERS = ';;'.join([ 'Common (*.fasta *.fst *.fas *.seq *.mae *.maegz *.mae.gz *.pdb *.ent ' '*.txt)', 'FASTA (*.fasta *.fst *.fas *.seq)', 'PDB (*.pdb *.ent)', 'Maestro (*.mae *.maegz *.mae.gz )', 'All Files (*.*)' ]) """ Filters for reference sequences in homology model building. """ STRUCTURE_FILTERS = ';;'.join([ 'Structure files (*.mae *.maegz *.mae.gz *.pdb *.ent)', 'Maestro (*.mae *.maegz *.mae.gz )', 'PDB (*.pdb *.ent)', ]) """ Filters that have structures associated with them. """
[docs] def __init__(self, parent=None, add_options=True, **kwargs): caption = kwargs.get('caption', self.CAPTION) filters = kwargs.get('filter', self.DEFAULT_FILTERS) if not parent: super(SequenceFileDialog, self).__init__() self.setWindowTitle(caption) self.setNameFilter(filters) else: kwargs['caption'] = caption kwargs['filter'] = filters super(SequenceFileDialog, self).__init__(parent, **kwargs) self.setAcceptMode(self.AcceptOpen) self.setLabelText(self.Accept, 'Open') if add_options: self.addOptions()
[docs] def addOptions(self): """ Adds three widgets on the bottom of the dialog window that allow users to optionally: - Align to query sequence - Replace matching sequences - Incorporate PDB files into Maestro """ self.merge_cb = QtWidgets.QCheckBox("Align to query sequence") self.replace_cb = QtWidgets.QCheckBox("Replace matching sequences") self.incorporate_cb = QtWidgets.QCheckBox( "Incorporate PDB files into Maestro") grid = self.layout() row = grid.rowCount() grid.addWidget(self.merge_cb, row, 1) grid.addWidget(self.replace_cb, row + 1, 1) grid.addWidget(self.incorporate_cb, row + 2, 1)
[docs] def getOpenFileName(self, multiple=False): if multiple: self.setFileMode(self.ExistingFiles) elif multiple == False: self.setFileMode(self.ExistingFile) else: raise RuntimeError('The "multiple" arg must be True or False.') # If not cancelled if self.exec_(): files = [os.path.normpath(str(x)) for x in self.selectedFiles()] if not multiple: files = files[0] return files return []
[docs] @staticmethod def get_open_file_names(parent=None, add_options=True, multiple=True, **kwargs): dialog = SequenceFileDialog(parent, add_options=add_options, **kwargs) return dialog.getOpenFileName(multiple)
[docs] @staticmethod def get_open_file_name(parent=None, add_options=True, **kwargs): dialog = SequenceFileDialog.get_open_file_names( parent=parent, add_options=add_options, multiple=False, **kwargs) return dialog
[docs]class NumericLineEdit(QtWidgets.QLineEdit): """ A `QtWidgets.QLineEdit` with a builtin validator for floats or integers. """
[docs] def __init__(self, parent=None, width=50, validate_type='float', minimum=None, maximum=None): QtWidgets.QLineEdit.__init__(self, parent=parent) self.setMaximumSize(QtCore.QSize(width, 16777215)) if not minimum: minimum = 0.0 if not maximum: maximum = 100000000.0 if validate_type == 'float': self.setValidator(QtGui.QDoubleValidator(minimum, maximum, 5, self)) elif validate_type == 'int': self.setValidator(QtGui.QIntValidator(minimum, maximum, self)) self.textChanged.connect(self.validate)
[docs] def validate(self): """ Checks to see if the lineedit has acceptable input and changes the widget to indicate invalid input. Even with a validator set users can input invalid args so this helps out. """ if not self.hasAcceptableInput() and self.text() != '': self.setStyleSheet( f'QLineEdit {{ border: 2px solid {LightModeColors.INVALID_STATE_BORDER}; }}' ) else: self.setStyleSheet('QLineEdit { }')
[docs]class RowActionItem(QtWidgets.QWidget): """ Custom widget to be used in a table cell. It will create a widget that contains multiple small push buttons with icons. This will end up looking like just a small icon in the cell. Multipe actions can be added to a single cell """
[docs] def __init__(self, row): """ :param row: The row associated with the cell. This can be anything (i.e. integer index, row object, etc.) and is used to track the row. :type row: mixed """ super(RowActionItem, self).__init__() self.row = row self.setObjectName('row_action_item') self._action_items = [] """ A private variable that stores the list of actions for the cell """ self.setStyleSheet(f""" QPushButton#cell_button {{ background-color: {LightModeColors.STANDARD_BACKGROUND}; border-width: 0px; border-radius: 3px; border-color: {LightModeColors.STANDARD_BORDER}; padding-top: 3px; padding-bottom: 3px; }} """)
[docs] def addActionItem(self, icon, tooltip, callback): """ Add an action to the cell widget. :param icon: the icon for the action :type icon: QtGui.QIcon :param callback: The callback for the action :type callback: callable """ button = QtWidgets.QPushButton(icon, '', self) button.setToolTip(tooltip) button.setObjectName('cell_button') button.clicked.connect(callback) self._action_items.append(button)
[docs] def paintEvent(self, *args, **kwargs): """ Override the paintEvent to create the layout for the cell. """ if not self.layout(): paint_layout = layout.hbox( self._action_items, spacing=1, margins=(1, 1, 1, 1)) self.setLayout(paint_layout) self.layout_set = True super(RowActionItem, self).paintEvent(*args, **kwargs)
[docs]class QuickHelpButton(QtWidgets.QPushButton): """ A help button that has a blue gradient """
[docs] def __init__(self, message_title, message_text): super(QuickHelpButton, self).__init__('?') # Set the style up self._setStyle() # Remove the focus which gets rid of the dotted background # when clicked self.setFocusPolicy(QtCore.Qt.NoFocus) # Create a dialog for when the button is clicked self.message_box = QtWidgets.QMessageBox(self) self.message_box.setWindowTitle(self.tr(message_title)) self.message_box.setText(self.tr(message_text)) # Connect the button click to open the dialog self.clicked.connect(self.message_box.exec_)
def _setStyle(self): """ Makes the button rounded and gives it a light blue to darker blue gradient """ # Set the object name so this style only effects this button self.setObjectName('help_button') self.setStyleSheet(""" QPushButton#help_button { max-width: 16px; max-height: 16px; min-width: 16px; min-height: 16px; font: bold; border: 2px solid #8f8f91; border-radius: 10px; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #a4ccec, stop: 1 #3282c2); } """)