Source code for schrodinger.ui.qt.messagebox

import sys

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

DEFAULT = object()

#===============================================================================
# Convenience methods
#===============================================================================


[docs]def show_message_box(parent, text, title, save_response_key=None, icon=None, detailed_text=None): """ Shows a general popup message box. For parameter documentation see `MessageBox`. """ msg_box = MessageBox(parent=parent, text=text, title=title, save_response_key=save_response_key, icon=icon) if detailed_text: msg_box.setDetailedText(detailed_text) return msg_box.exec()
[docs]def show_warning(parent, text, title='Warning', save_response_key=None, detailed_text=None): """ Shows a popup warning message box. For parameter documentation see `MessageBox`. """ show_message_box(parent, text, title=title, save_response_key=save_response_key, icon=MessageBox.Warning, detailed_text=detailed_text)
[docs]def show_error(parent, text, title='Error', save_response_key=None, detailed_text=None): """ Shows a popup error message box. For parameter documentation see `MessageBox`. """ show_message_box(parent, text, title=title, save_response_key=save_response_key, icon=MessageBox.Critical, detailed_text=detailed_text)
[docs]def show_info(parent, text, title='Info', save_response_key=None): """ Shows a popup information message box. For parameter documentation see `MessageBox`. """ show_message_box(parent, text, title=title, save_response_key=save_response_key, icon=MessageBox.Information)
[docs]def show_question(parent, text, title='Question', save_response_key=None, yes_text='OK', no_text=None, add_cancel_btn=True, more_btns_list=None, default_btn_txt=DEFAULT, icon=QtWidgets.QMessageBox.Question): """ Shows a popup question message box. For parameter documentation see `QuestionMessageBox`. """ msg_box = QuestionMessageBox(parent=parent, text=text, title=title, save_response_key=save_response_key, yes_text=yes_text, no_text=no_text, add_cancel_btn=add_cancel_btn, more_btns_list=more_btns_list, default_btn_txt=default_btn_txt, icon=icon) return msg_box.exec()
[docs]def show_product_missing_info(parent=None): """ Show the information about getting license and how to download the product, when the product is missing in the installation. """ title = ("License Required") message = """ <html><p><strong>The application you are trying to access requires a license.</strong><br> <br>Free Maestro is a visualization tool. To run calculations you need to download the Schrodinger Suite from the following link:<br> <a href=https://www.schrodinger.com/downloads/releases>https://www.schrodinger.com/downloads/releases</a></p> <p>To request a trial license or pricing information, please see the “Trials/Sales Quote” form here:<br> <a href=https://www.schrodinger.com/request-trial-license>https://www.schrodinger.com/request-trial-license</a><br> <a href=https://www.schrodinger.com/salescenter>https://www.schrodinger.com/salescenter</a></p> """ show_message_box(parent=parent, title=title, text=message)
#=============================================================================== # Message Boxes #===============================================================================
[docs]class MessageBox(QtWidgets.QMessageBox): """ A modal dialog for presenting a text message to the user. Provides an optional "Do not show this again" checkbox, which stores a value in the preferences. """ _pytest_abort_hook = lambda self: None # To prevent showing during tests TYPED_RESPONSES = { 'TRUE_RESPONSE': True, 'FALSE_RESPONSE': False, 'NONE_RESPONSE': None } STRINGED_RESPONSES = {v: k for k, v, in TYPED_RESPONSES.items()}
[docs] def __init__(self, parent=None, title='', text='', save_response_key=None, add_prefix_to_key=True, icon=None): """ :param parent: the parent widget :type parent: QtWidgets.QWidget :param title: the dialog title :type title: str :param text: the message :type text: str :param save_response_key: When set, message box will show a "Do not show again" checkbox. The value provided will be used to generate a preference key. See `add_prefix_to_key` for more information on how the preference key is generated. The preference is *only* stored if the checkbox is checked. If it is unchecked, instead of storing a False, no preference is stored at all. This allows subclasses to make the distinction between saving a False response and not saving the response at all. :type save_response_key: str or NoneType :param add_prefix_to_key: Whether to prepend some basic context to the response_key (module_name, class_name`*`) in order to unique-ify the key. If set to False, the value provided for `save_response_key` will be used as-is, and the user is responsible for ensuring the key does not clash with any other preference keys. `*` If a parent is set for the messagebox, then the class name of parent will be used for `class_name`, otherwise the class name of the message box will be used. :param icon: the icon to show - see QMessageBox documentation for details """ self.save_response_key = None if icon is None: icon = self.NoIcon self.save_response_chk = QtWidgets.QCheckBox('Do not show again') self._title = title super().__init__(icon, title, '', parent=parent) if sys.platform.startswith("darwin"): self.setInformativeText(text) self.setWindowTitle(self._title) else: self.setText(text) if save_response_key: if ':' in save_response_key or ' ' in save_response_key: # A colon causes Maestro to crash, and space causes traceback raise ValueError('Invalid character(s) in save_response_key') key_obj = parent or self if add_prefix_to_key: self.save_response_key = settings.generate_preference_key( key_obj, save_response_key) else: self.save_response_key = save_response_key self.setCheckBox(self.save_response_chk)
[docs] def setWindowTitle(self, title): # bypass QMessageBox.setWindowTitle to force title to be shown on Mac super(QtWidgets.QDialog, self).setWindowTitle(title)
[docs] def exec(self): saved_response = self._checkSavedResponse() if saved_response is not None: return saved_response self._runSuperExec() return self._postProcess()
def _checkSavedResponse(self): if self.save_response_key: return self._getSavedResponse(self.save_response_key) else: return None def _runSuperExec(self): self._pytest_abort_hook() super().exec() def _getSavedResponse(self, key): response = settings.get_persistent_value(key, None) return self.TYPED_RESPONSES.get(response, response) def _postProcess(self): response = self.getResponse() if self.save_response_chk.isChecked() and response is not None: self._saveResponse(self.save_response_key, self.getResponse()) return response def _saveResponse(self, key, response): stringed_response = self.STRINGED_RESPONSES.get(response, response) settings.set_persistent_value(key, stringed_response)
[docs] def forgetResponse(self): try: settings.remove_preference_key(self.save_response_key) except ValueError: # response was never saved pass
[docs] def getResponse(self): """ Override this method to specify the nature of the "response" to save. Here it is simply True, to indicate that the "Do not show this again" checkbox has been checked. """ return True
DEFAULT_YES_TXT = 'Yes' DEFAULT_NO_TXT = 'No'
[docs]class QuestionMessageBox(MessageBox): """ Simple popup dialog for asking a question to the user which can be answered by clicking on a button. The button configuration is customizable. By default, the choices are Yes and No, which return True and False, respectively. The text for these two buttons may be modified via the yes_text and no_text arguments (e.g. Continue/Abort, Save/Discard). The optional "Cancel" button returns a None return value, and a "Cancel" choice is never saved, irrespective of the checkbox state. Additional buttons can be added via the more_btns_list. These additional buttons will be placed between the standard yes and no buttons. The yes and no buttons can also be omitted by passing in None for yes_text or no_text. """
[docs] def __init__(self, yes_text=DEFAULT_YES_TXT, no_text=DEFAULT_NO_TXT, add_cancel_btn=False, more_btns_list=None, default_btn_txt=DEFAULT, icon=QtWidgets.QMessageBox.Question, *args, **kwargs): """ :param yes_text: The text to show on the yes button. If None is passed in, the yes button will not be added. The question box return True when the yes button is clicked. If the yes button text is changed from "Yes" to something else, consider updating the default_btn option to match. :type yes_text: str :param add_cancel_btn: Set to true to add a "Cancel" button. The cancel button differs from the "No" button only in that the response will not be saved, irrespective of the save_response checkbox state. :type add_cancel_btn: bool :param more_btns_list: a list of text for extra buttons to be included between the yes and no buttons. If any of these buttons are clicked, the return value will simply be the button text. Note that this means that if the response is to be saved, the button text is the value that is saved. :type more_btns_list: list of str :param default_btn_txt: the text for the default button (selected when user presses Enter on the keyboard). Set to None for no default button. :type default_btn_txt: str :param icon: Icon for this message box. :type icon: int """ super(QuestionMessageBox, self).__init__(*args, icon=icon, **kwargs) self._setupButtons(yes_text, no_text, add_cancel_btn=add_cancel_btn, more_btns_list=more_btns_list, default_btn_txt=default_btn_txt)
[docs] def getResponse(self): """ Provides the return value for the user's choice. Also provides the value to save if the "Remember my choice" option is checked. """ btn = self.clickedButton() return self.response_map.get(btn)
def _setupButtons(self, yes_text, no_text, add_cancel_btn=False, more_btns_list=None, default_btn_txt=DEFAULT): """ Sets up the buttons based on the values for yes_text, no_text, and more_btns_list. For parameter details, see the __init__() method. Also customizes the save_response_chk text based on what choices are available. """ if default_btn_txt is DEFAULT: default_btn_txt = yes_text self.response_map = {} if yes_text: btn = self.addButton(yes_text, self.ActionRole) self.response_map[btn] = True if more_btns_list: for btn_text in more_btns_list: btn = self.addButton(btn_text, self.ActionRole) self.response_map[btn] = btn_text if no_text: btn = self.addButton(no_text, self.ActionRole) self.response_map[btn] = False if add_cancel_btn: btn = self.addButton('Cancel', self.RejectRole) self.response_map[btn] = None for button in self.buttons(): button.setAutoDefault(False) # Necessary for the no-default case if button.text() == default_btn_txt: self.setDefaultButton(button) button.clearFocus() # If there are choices other than yes or cancel, customize the chk text if no_text or more_btns_list: self.save_response_chk.setText('Always do this')