Source code for schrodinger.application.msv.gui.menu

from schrodinger import get_maestro
from schrodinger import in_dev_env
from schrodinger.application.msv.gui import gui_models
from schrodinger.application.msv.gui import stylesheets
from schrodinger.application.msv.gui.viewconstants import \
    MULTI_ALIGN_DISABLED_TT
from schrodinger.application.msv.gui.viewconstants import MULTI_ALIGN_ENABLED_TT
from schrodinger.application.msv.gui.viewconstants import PROF_ALIGN_DISABLED_TT
from schrodinger.application.msv.gui.viewconstants import Autosave
from schrodinger.models import mappers
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtGui
from schrodinger.Qt import QtWidgets
from schrodinger.ui.qt.mapperwidgets import MappableActionGroup

maestro = get_maestro()
TUTORIAL_BASE_PATH = 'https://www.schrodinger.com/sites/default/files/s3/mkt/Tutorials/current/'
MSV_GUIDE = 'https://www.schrodinger.com/system/files/msv_guide_r3.pdf'

url = TUTORIAL_BASE_PATH + "{}.pdf"
BIOLUMINATE_INTRO = url.format('intro_bioluminate')
CHIMERIC_HOMOLGY_MODELING = url.format('chimeric_homology_building')
BATCH_HOMOLOGY_MODELING = url.format('batch_homology')
ANTIBODY_ANNOTATION = url.format('antibody_annotation')





[docs]class ToggleTextAction(mappers.TargetMixin, MenuAction): """ Menu action that toggles a bool every time it's triggered and updates the text based on the value of the bool """
[docs] def __init__(self, true_text, false_text): super().__init__("") self._texts = [false_text, true_text] self.targetSetValue(False) # Initialize internal state and text self.triggered.connect(self._toggleValue, QtCore.Qt.QueuedConnection) self.setImplemented(True) # Override `MenuAction` default
[docs] def targetGetValue(self): return self._value
[docs] def targetSetValue(self, value: bool): self._value = value self.setText(self._texts[int(self._value)])
def _toggleValue(self): self.targetSetValue(not self.targetGetValue()) self.targetValueChanged.emit()
[docs]class EnabledTargetSpec(mappers.TargetSpec): """ A TargetSpec for mapping a BoolParam to the enabled state of a widget """
[docs] def __init__(self, widget): super().__init__(widget, getter=None, setter=widget.setEnabled, signal=None)
[docs]class MsvMenuBar(mappers.MapperMixin, QtWidgets.QMenuBar): model_class = gui_models.MenuEnabledModel
[docs] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.setNativeMenuBar(False) self.setStyleSheet(stylesheets.MENU) self._setMenuActions() self._makeMenus() self._setupMapperMixin()
[docs] def defineMappings(self): ma = self.menu_actions M = self.model_class actions = [ (ma.edit_as_text, M.can_edit_as_text), (ma.copy, M.can_copy_residues), (ma.delete_sel_seqs, M.can_delete_sequences), (ma.delete_sel_residues, M.can_delete_residues), (ma.delete_sel_gaps, M.can_delete_gaps), (ma.delete_all_predictions, M.can_delete_predictions), (ma.delete_this_tab, M.can_delete_tab), (ma.move_seq, M.can_move_sequence), (ma.set_as_ref_seq, M.can_set_as_ref), (ma.rename_seq, M.can_rename_seq), (ma.move_set_as_ref, M.can_set_as_ref), (ma.duplicate_seq, M.can_duplicate_sequence), (ma.duplicate_as_ref, M.can_duplicate_as_ref), (ma.duplicate_in_place, M.can_duplicate_seq_same_tab), (ma.duplicate_at_bottom, M.can_duplicate_seq_same_tab), (ma.duplicate_at_top, M.can_duplicate_seq_same_tab), (ma.replace_sel_with_gaps, M.can_replace_res_with_gaps), (ma.renumber_residues, M.can_renumber_residues), (ma.select_all_sequences, M.can_select), (ma.select_no_sequences, M.can_select), (ma.select_sequence_with_structure, M.can_select), (ma.select_sequence_by_identity,M.can_select), (ma.select_invert_seq_selection, M.can_select), (ma.select_all_residues, M.can_select), (ma.select_no_residues, M.can_select), (ma.select_residues_with_structure, M.can_select), (ma.select_invert_res_selection, M.can_select), (ma.select_protein_interface, M.can_select_protein_interface), (ma.expand, M.can_expand), (ma.collapse, M.can_expand), (ma.anchor_selection, M.can_anchor_res), (ma.clear_anchoring, M.can_unanchor_res), (ma.hide_sel_columns, M.can_hide_columns), (ma.set_constraints, M.can_set_constraints), (ma.clear_constraints, M.can_clear_constraints), (ma.sort_ascending_by_chain_id, M.can_sort_by_chain), (ma.sort_descending_by_chain_id, M.can_sort_by_chain), (ma.select_sequence_antibody_heavy, M.can_select_antibody_chain), (ma.select_sequence_antibody_light, M.can_select_antibody_chain), (ma.get_pdb_sts, M.can_get_pdb_sts), (ma.select_link_seq_to_entries, M.can_link_or_unlink_sequences), ] # yapf: disable EnabledTS = EnabledTargetSpec mappings = [(EnabledTS(action), param) for (action, param) in actions] update_align_tgt = mappers.TargetSpec(slot=self._updateCanAlign) for param in (M.can_only_multiple_align, M.can_only_profile_align, M.can_aln_set_align): mappings.append((update_align_tgt, param)) return mappings
[docs] @QtCore.pyqtSlot(bool) def canRedoChanged(self, can_redo): """ Update the menu state depending on whether redo is available """ redo_action = self.menu_actions.redo if redo_action.isEnabled() != can_redo: redo_action.setEnabled(can_redo)
[docs] @QtCore.pyqtSlot(bool) def canUndoChanged(self, can_undo): """ Update the menu state depending on whether undo is available """ undo_action = self.menu_actions.undo if undo_action.isEnabled() != can_undo: undo_action.setEnabled(can_undo)
[docs] @QtCore.pyqtSlot(str) def onRedoTextChanged(self, redo_text): """ Update the Red menu action text to reflect the current redo action. :param redo_text: Text of the current redo action :type redo_text: str """ redo_action = self.menu_actions.redo if not redo_text: redo_action.setText('&Redo') else: redo_action.setText('&Redo - {0}'.format(redo_text))
[docs] @QtCore.pyqtSlot(str) def onUndoTextChanged(self, undo_text): """ Update the Undo menu action text to reflect the current undo action. :param undo_text: Text of the current undo action :type undo_text: str """ undo_action = self.menu_actions.undo if not undo_text: undo_action.setText('&Undo') else: undo_action.setText("&Undo - {0}".format(undo_text))
def _updateCanAlign(self): ma = self.menu_actions align_actions = { ma.multiple_alignment, ma.pairwise_alignment, ma.pairwise_ss_alignment, ma.align_from_superposition, ma.profile_alignment, ma.prot_struct_align, ma.align_binding_sites, ma.align_based_sequence } if not self.model.can_aln_set_align: allowed_actions = set() elif self.model.can_only_profile_align: allowed_actions = {ma.profile_alignment} elif self.model.can_only_multiple_align: allowed_actions = {ma.multiple_alignment} else: # Profile alignment is only allowed when it's the only allowed align allowed_actions = align_actions - {ma.profile_alignment} if not maestro: allowed_actions.discard(ma.align_based_sequence) for action in align_actions: enabled = action in allowed_actions action.setEnabled(enabled) prof_align_tooltip = ("" if ma.profile_alignment.isEnabled() else PROF_ALIGN_DISABLED_TT) multi_align_tooltop = (MULTI_ALIGN_ENABLED_TT if ma.multiple_alignment.isEnabled() else MULTI_ALIGN_DISABLED_TT) ma.profile_alignment.setToolTip(prof_align_tooltip) ma.multiple_alignment.setToolTip(multi_align_tooltop) def _setMenuActions(self): self.menu_actions = MenuBarActions() def _makeMenus(self): self._addFileMenu() self._addEditMenu() self._addSelectionMenu() self._addViewMenu() self._addAlignmentMenu() self._addHelpMenu() self._maybeAddDevelopmentMenu() def _addActionsToMenu(self, menu, actions): for action in actions: self._addActionToMenu(menu, action) menu.addSeparator() def _addActionToMenu(self, menu, action): action.setParent(menu) menu.addAction(action) menu.setToolTipsVisible(True) def _addFileMenu(self): file_menu = QtWidgets.QMenu("&File", self) ma = self.menu_actions add_project_group = [ ma.open_project, ma.import_project, ma.close_project ] save_or_close_proj_group = [ma.save_project, ma.save_as] import_group = [ ma.get_pdb, ma.get_sequences, ma.import_sequences, ma.paste_sequences, ma.import_from_maestro ] import_from_maestro = [ ma.import_from_maestro_workspace, ma.import_from_maestro_selected ] export_group = [ma.export_sequences, ma.save_image] close_group = [ma.close] for group in [ add_project_group, save_or_close_proj_group, import_group, export_group, close_group ]: self._addActionsToMenu(file_menu, group) maestro_menu = ma.import_from_maestro.menu self._addActionsToMenu(maestro_menu, import_from_maestro) self.addMenu(file_menu) def _addEditMenu(self): edit_menu = QtWidgets.QMenu("&Edit", self) ma = self.menu_actions edit_group = [ma.undo, ma.redo] copy_del_move_dup_group = [ ma.copy, ma.delete_sub, ma.move_seq, ma.duplicate_seq ] name_group = [ ma.set_as_ref_seq, ma.rename_seq, # MSV-3357: Hiding unimplemented features for beta #ma.color_seq_name ] sort_group = [ma.sort_seq, ma.get_pdb_sts, ma.translate_seq] replace_res_group = [ ma.replace_sel_with_gaps, ma.renumber_residues, ma.edit_as_text ] for group in [ edit_group, [ma.edit_sequence], copy_del_move_dup_group, name_group, sort_group, replace_res_group, [ma.settings], ]: self._addActionsToMenu(edit_menu, group) delete_res_group = [ ma.delete_sel_residues, ma.delete_sel_gaps, ma.delete_gap_cols ] delete_seq_group = [ ma.delete_sel_seqs, ma.delete_redundant_seqs, ma.delete_all_predictions ] delete_tab_group = [ma.delete_this_tab, ma.delete_all_view_tabs] delete_menu = ma.delete_sub.menu self._addActionsToMenu(delete_menu, delete_res_group) self._addActionsToMenu(delete_menu, delete_seq_group) self._addActionsToMenu(delete_menu, delete_tab_group) move_group = [ ma.move_to_top, ma.move_up, ma.move_down, ma.move_to_bottom ] move_ref_group = [ma.move_set_as_ref] move_menu = ma.move_seq.menu self._addActionsToMenu(move_menu, move_group) self._addActionsToMenu(move_menu, move_ref_group) duplicate_menu = ma.duplicate_seq.menu duplicate_group = [ ma.duplicate_in_place, ma.duplicate_at_bottom, ma.duplicate_at_top, ma.duplicate_as_ref ] duplicate_new_tab_group = [ ma.duplicate_into_new_tab, ma.duplicate_into_existing_tab ] self._addActionsToMenu(duplicate_menu, duplicate_group) self._addActionsToMenu(duplicate_menu, duplicate_new_tab_group) sort_seq = [ # MSV-3357: Hiding unimplemented features for beta #[ma.sort_by_tree_order], [ma.sort_ascending, ma.sort_descending], [ma.reverse_last_sort] ] sort_ascending = [ ma.sort_ascending_by_name, ma.sort_ascending_by_chain_id, ma.sort_ascending_by_gaps, ma.sort_ascending_by_length, ma.sort_ascending_by_seq_identity, ma.sort_ascending_by_seq_similarity, ma.sort_ascending_by_seq_homology, ma.sort_ascending_by_seq_score ] sort_descending = [ ma.sort_descending_by_name, ma.sort_descending_by_chain_id, ma.sort_descending_by_gaps, ma.sort_descending_by_length, ma.sort_descending_by_seq_identity, ma.sort_descending_by_seq_similarity, ma.sort_descending_by_seq_homology, ma.sort_descending_by_seq_score ] sort_menu = ma.sort_seq.menu for group in sort_seq: self._addActionsToMenu(sort_menu, group) ascending_menu = ma.sort_ascending.menu self._addActionsToMenu(ascending_menu, sort_ascending) descending_menu = ma.sort_descending.menu self._addActionsToMenu(descending_menu, sort_descending) local_menu = ma.local_server.menu local_group = [ma.sequence_local, ma.blast_local, ma.pdb_local] self._addActionsToMenu(local_menu, local_group) autosave_menu = ma.auto_save.menu autosave_menu_items = [ ma.auto_save_regularly, ma.auto_save_after_edit, ma.auto_save_never ] self._addActionsToMenu(autosave_menu, autosave_menu_items) for action in autosave_menu_items: action.setImplemented(True) menu_action_map = { ma.auto_save_regularly: Autosave.Regularly, ma.auto_save_after_edit: Autosave.OnlyAfterEdit, ma.auto_save_never: Autosave.Never } self.auto_save_group = MappableActionGroup(menu_action_map, parent=self) self.auto_save_group.setExclusive(True) settings_menu = ma.settings.menu #job_group = [ma.job_settings, ma.view_job_log] server_group = [ ma.local_server, ma.reset_remote_server_ask, # MSV-3357: Hiding unimplemented features for beta #ma.reset_job_settings ] #defaults_group = [ma.font_size] for group in ( # MSV-3357: Hiding unimplemented features for beta #job_group, server_group, #defaults_group, [ma.auto_save, ma.light_mode]): self._addActionsToMenu(settings_menu, group) self.addMenu(edit_menu) def _addSelectionMenu(self): selection_menu = QtWidgets.QMenu("&Select", self) ma = self.menu_actions select_antibody_group = [ ma.select_sequence_antibody_heavy, ma.select_sequence_antibody_light ] select_by_feature_group = [ ma.select_sequence_with_structure, ma.select_sequence_by_identity ] select_feature_menu = ma.select_sequences_by_feature.menu for group in (select_by_feature_group, select_antibody_group): self._addActionsToMenu(select_feature_menu, group) seq_res_group = [ ma.select_all_sequences, ma.select_no_sequences, ma.select_sequences_by_feature, ma.select_invert_seq_selection ] residue_group = [ ma.select_all_residues, ma.select_no_residues, ma.select_residues_with_structure, ma.select_pattern_matching_residues, ma.select_deselect_gaps, ma.select_invert_res_selection ] misc_group = [ ma.select_identities, ma.select_aligned_residues, ma.select_binding_sites, ma.select_protein_interface, ma.select_antibody_cdr, ma.select_columns_with_structure ] expand_group = [ ma.select_expand_along_cols, ma.select_expand_ref_sel_only ] for group in [ seq_res_group, residue_group, misc_group, expand_group, [ ma.select_update_workspace_selection, ma.select_link_seq_to_entries ] ]: self._addActionsToMenu(selection_menu, group) self.addMenu(selection_menu) def _addViewMenu(self): view_menu = QtWidgets.QMenu("&View", self) ma = self.menu_actions seq_group = [ ma.hide_selected_seqs, ma.show_workspace_seqs, ma.show_all_seqs, ma.find_seqs_in_list ] expand_collapse_group = [ma.expand, ma.collapse] # MSV-3357: Hiding unimplemented features for beta #cols_group = [ #ma.hide_sel_columns, ma.show_all_cols_within_sel, #ma.show_all_hidden_cols #] annotations_colors_group = [ ma.hide_annotations, ma.hide_colors, ma.configure, ma.reset_to_defaults ] expand_menu = ma.expand.menu collapse_menu = ma.collapse.menu configure_menu = ma.configure.menu expand_sel_group = [ ma.expand_selected, ma.expand_unselected, ma.expand_all ] collapse_sel_group = [ ma.collapse_selected, ma.collapse_unselected, ma.collapse_all ] config_group = [ ma.configure_annotations, ma.configure_colors, ma.configure_view ] for group in [expand_sel_group]: self._addActionsToMenu(expand_menu, group) for group in [collapse_sel_group]: self._addActionsToMenu(collapse_menu, group) for group in [config_group]: self._addActionsToMenu(configure_menu, group) for group in [ seq_group, expand_collapse_group, # MSV-3357: Hiding unimplemented features for beta #cols_group, annotations_colors_group ]: self._addActionsToMenu(view_menu, group) self.addMenu(view_menu) def _addAlignmentMenu(self): align_menu = QtWidgets.QMenu("&Align", self) ma = self.menu_actions align_seq_group = [ ma.multiple_alignment, ma.pairwise_alignment, ma.pairwise_ss_alignment, ma.profile_alignment, ] align_based_superposition = [ma.align_from_superposition] align_seq_menu = ma.align_sequences.menu for group in [align_seq_group, align_based_superposition]: self._addActionsToMenu(align_seq_menu, group) align_struct_menu = ma.align_structures.menu stucture_alignment = [ma.prot_struct_align, ma.align_binding_sites] align_based_seq = [ma.align_based_sequence] for group in [stucture_alignment, align_based_seq]: self._addActionsToMenu(align_struct_menu, group) seq_align_group = [ ma.align_sequences, ma.align_structures, ma.dendrogram ] constrain_group = [ ma.set_constraints, ma.clear_constraints, ] reset_group = [ma.reset_align] anchor_group = [ma.anchor_selection, ma.clear_anchoring] for group in [ [ma.auto_align], seq_align_group, constrain_group, reset_group, anchor_group, ]: self._addActionsToMenu(align_menu, group) self.addMenu(align_menu) def _maybeAddDevelopmentMenu(self): """ Adds the development menu if SCHRODINGER_SRC is set in the user's environment """ if not in_dev_env(): return dev_menu = QtWidgets.QMenu("&Development", self) self._addActionsToMenu(dev_menu, [ self.menu_actions.start_ipython_session, self.menu_actions.show_debug_gui, self.menu_actions.show_color_scheme_editor, self.menu_actions.time_scroll, self.menu_actions.time_scroll_by_page, self.menu_actions.profile_scroll, self.menu_actions.profile_scroll_by_page, self.menu_actions.view_history ]) self.addMenu(dev_menu) def _addHelpMenu(self): help_menu = QtWidgets.QMenu("&Help", self) ma = self.menu_actions self._addActionsToMenu(help_menu, [ ma.msv_help, ma.homology_modeling_help, ma.alignment_pane_help, ]) self._addActionToMenu(help_menu, ma.getting_started_help) self._addActionToMenu(help_menu, ma.tutorials) self.addMenu(help_menu) tutorials_menu = ma.tutorials.menu for act in (ma.bioluminate_intro, ma.chimeric_hm_help, ma.batch_hm_help, ma.antibody_anno_help): self._addActionToMenu(tutorials_menu, act)