JAL-4307 View->Ligands submenu, implementation for Jmol and documentation
authorJames Procter <j.procter@dundee.ac.uk>
Thu, 19 Oct 2023 17:27:33 +0000 (18:27 +0100)
committerJames Procter <j.procter@dundee.ac.uk>
Thu, 19 Oct 2023 17:27:33 +0000 (18:27 +0100)
help/help/html/features/jmol.html
help/markdown/releases/release-2_11_3_0.md
resources/lang/Messages.properties
src/jalview/api/structures/JalviewStructureDisplayI.java
src/jalview/ext/jmol/JalviewJmolBinding.java
src/jalview/ext/jmol/JmolCommands.java
src/jalview/gui/StructureViewerBase.java
src/jalview/jbgui/GStructureViewer.java
src/jalview/structure/StructureCommandsI.java
src/jalview/structures/models/AAStructureBindingModel.java

index ac2489b..491a03f 100644 (file)
         <li><strong>Show Chains<br>
         </strong><em>Select which of the PDB file's chains are to be
             displayed.</em></li>
-        <li><strong>Colour by ..<br></strong><em>Submenu
+                               <li><strong>Ligands<br>
+                               </strong><em>When available, allows the display of all, none or specific
+                                               ligands (also known as HETATM groups) in the Jmol view, using CPK
+                                               spacefilling.</em></li>
+                               <li><strong>Colour by ..<br></strong><em>Submenu
             allowing specific alignment views to be selected for
             colouring associated chains in the structure display. This
             menu contains all the alignment views associated with the
index 8847eb2..d7bdd25 100644 (file)
@@ -19,6 +19,7 @@ channel: "release"
 - <!-- JAL-4273 --> Visible adjuster marks to grab and adjust annotation panel height and id width
 - <!-- JAL-4260 --> Adjustable ID margin when alignment is wrapped
 - <!-- JAL-4274 --> Command line options and configurable bitmap export preferences for height, width and scale factor
+- <!-- JAL-4307 --> Show or hide ligands in a Jmol structure view via View Ligands submenu
 
 ### Improved support for working with computationally determined models
 - <!-- JAL-3895 --> Alphafold red/orange/yellow/green colourscheme for structures
index 70eeb95..58f9805 100644 (file)
@@ -1468,3 +1468,4 @@ label.command_line_arguments = Command Line Arguments
 warning.using_old_command_line_arguments = It looks like you are using old command line arguments.  These are now deprecated and will be removed in a future release of Jalview.\nFind out about the new command line arguments at\n
 warning.using_mixed_command_line_arguments = Jalview cannot use both old (-arg) and new (--arg) command line arguments.  Please check your command line arguments.\ne.g. {0} and {1}
 warning.the_following_errors = The following errors and warnings occurred whilst processing files:
+action.show_hetatm = Show Ligands (HETATM)
index 532e545..77f2b6d 100644 (file)
@@ -21,6 +21,8 @@
 package jalview.api.structures;
 
 import java.io.File;
+import java.util.Collections;
+import java.util.List;
 
 import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.PDBEntry;
@@ -192,4 +194,12 @@ public interface JalviewStructureDisplayI
 
   File saveSession();
 
+  /**
+   * 
+   * @return heteroatoms in a form suitable for display and passing to command generator to display hetatms
+   */
+  default List<String> getHetatms() {
+    return Collections.EMPTY_LIST;
+  }
+
 }
index dc18369..c8ce3cd 100644 (file)
@@ -26,6 +26,8 @@ import java.awt.event.ComponentListener;
 import java.io.File;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
@@ -41,6 +43,8 @@ import org.jmol.api.JmolViewer;
 import org.jmol.c.CBK;
 import org.jmol.viewer.Viewer;
 
+import com.google.common.collect.Lists;
+
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureRenderer;
 import jalview.api.FeatureSettingsModelI;
@@ -184,7 +188,25 @@ public abstract class JalviewJmolBinding extends AAStructureBindingModel
 
   // End StructureListener
   // //////////////////////////
-
+  
+  ////////////////////////////
+  // HETATM get
+  //
+  
+  @Override
+  public List<String> getHetatmNames()
+  {
+    HashMap<String,String> hetlist=new HashMap();
+    for (int mc=0;mc<jmolViewer.ms.mc; mc++)
+    {
+      Map<String,String> hets = jmolViewer.ms.getHeteroList(mc);
+      hetlist.putAll(hets);
+    }
+    return Arrays.asList(hetlist.keySet().toArray(new String[0]));
+  }
+  //
+  ////////////////////////////
+  
   @Override
   public float[][] functionXY(String functionName, int x, int y)
   {
index f9ba1e4..106d458 100644 (file)
@@ -323,6 +323,31 @@ public class JmolCommands extends StructureCommandsBase
             "restore STATE \"" + Platform.escapeBackslashes(filePath) + "\"");
   }
 
+  @Override
+  public List<StructureCommandI> showHetatms(List<String> toShow)
+  {
+    // always clear the current hetero cpk display
+    
+    StringBuilder sb = new StringBuilder();
+    sb.append("select hetero; cpk off;");
+    
+    if (toShow != null && !toShow.isEmpty())
+    {
+      // select what was requested
+      sb.append("select ");
+      boolean or = false;
+      for (String k : toShow)
+      {
+        sb.append(or ? " or " : " ");
+        sb.append(k);
+        or = true;
+      }
+      // and show as
+      sb.append("; cpk;");
+    }
+    
+    return Arrays.asList(new StructureCommand(sb.toString()));
+  }
   /**
    * Obsolete method, only referenced from
    * jalview.javascript.MouseOverStructureListener
index ed42ffa..09d2dcb 100644 (file)
@@ -141,6 +141,8 @@ public abstract class StructureViewerBase extends GStructureViewer
 
   protected boolean allChainsSelected = false;
 
+  protected boolean allHetatmBeingSelected = false;
+
   protected JMenu viewSelectionMenu;
 
   /**
@@ -604,6 +606,80 @@ public abstract class StructureViewerBase extends GStructureViewer
       chainMenu.add(menuItem);
     }
   }
+  void setHetatmMenuItems(List<String> hetatmNames)
+  {
+    hetatmMenu.removeAll();
+    if (hetatmNames == null || hetatmNames.isEmpty())
+    {
+      hetatmMenu.setVisible(false);
+      return;
+    }
+    hetatmMenu.setVisible(true);
+    allHetatmBeingSelected=false;
+    JMenuItem allMenuItem = new JMenuItem(
+            MessageManager.getString("label.all"));
+    JMenuItem noneMenuItem = new JMenuItem(
+            MessageManager.getString("label.none"));
+    allMenuItem.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+      {
+        allHetatmBeingSelected=true;
+        // Toggle state of everything - on
+        for (int i = 0; i < hetatmMenu.getItemCount(); i++)
+        {
+          if (hetatmMenu.getItem(i) instanceof JCheckBoxMenuItem)
+          {
+            ((JCheckBoxMenuItem) hetatmMenu.getItem(i)).setSelected(true);
+          }
+        }
+        allHetatmBeingSelected=false;
+        showSelectedHetatms();
+      }
+      }});
+
+    noneMenuItem.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+      {
+        allHetatmBeingSelected=true;
+        // Toggle state of everything off
+        for (int i = 0; i < hetatmMenu.getItemCount(); i++)
+        {
+          if (hetatmMenu.getItem(i) instanceof JCheckBoxMenuItem)
+          {
+            ((JCheckBoxMenuItem) hetatmMenu.getItem(i)).setSelected(false);
+          }
+        }
+        allHetatmBeingSelected=false;
+        showSelectedHetatms();
+      }
+      }});
+    hetatmMenu.add(noneMenuItem);
+    hetatmMenu.add(allMenuItem);
+
+    for (String chain : hetatmNames)
+    {
+      JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(chain, false);
+      menuItem.addItemListener(new ItemListener()
+      {
+        @Override
+        public void itemStateChanged(ItemEvent evt)
+        {
+          if (!allHetatmBeingSelected)
+          { 
+            // update viewer only when we were clicked, not programmatically
+            // checked/unchecked
+            showSelectedHetatms();
+          }
+        }
+      });
+
+      hetatmMenu.add(menuItem);
+    }
+  }
 
   /**
    * Action on selecting one of Jalview's registered colour schemes
@@ -1009,6 +1085,7 @@ public abstract class StructureViewerBase extends GStructureViewer
       return;
     }
     setChainMenuItems(binding.getChainNames());
+    setHetatmMenuItems(binding.getHetatmNames());
 
     this.setTitle(binding.getViewerTitle(getViewerName(), true));
 
@@ -1158,7 +1235,25 @@ public abstract class StructureViewerBase extends GStructureViewer
     }
     getBinding().showChains(toshow);
   }
-
+  /**
+   * Display selected hetatms in viewer
+   */
+  protected void showSelectedHetatms()
+  {
+    List<String> toshow = new ArrayList<>();
+    for (int i = 0; i < hetatmMenu.getItemCount(); i++)
+    {
+      if (hetatmMenu.getItem(i) instanceof JCheckBoxMenuItem)
+      {
+        JCheckBoxMenuItem item = (JCheckBoxMenuItem) hetatmMenu.getItem(i);
+        if (item.isSelected())
+        {
+          toshow.add(item.getText());
+        }
+      }
+    }
+    getBinding().showHetatms(toshow);
+  }
   /**
    * Tries to fetch a PDB file and save to a temporary local file. Returns the
    * saved file path if successful, or null if not.
index 18e4c9f..fceb50c 100644 (file)
@@ -52,6 +52,8 @@ public abstract class GStructureViewer extends JInternalFrame
 
   protected JMenu chainMenu;
 
+  protected JMenu hetatmMenu;
+
   protected JMenu viewerActionMenu;
 
   protected JMenuItem alignStructs;
@@ -152,6 +154,9 @@ public abstract class GStructureViewer extends JInternalFrame
     chainMenu = new JMenu();
     chainMenu.setText(MessageManager.getString("action.show_chain"));
 
+    hetatmMenu = new JMenu();
+    hetatmMenu.setText(MessageManager.getString("action.show_hetatm"));
+
     fitToWindow = new JMenuItem();
     fitToWindow.setText(MessageManager.getString("label.fit_to_window"));
     fitToWindow.addActionListener(new ActionListener()
@@ -197,6 +202,7 @@ public abstract class GStructureViewer extends JInternalFrame
     savemenu.add(png);
     savemenu.add(eps);
     viewMenu.add(chainMenu);
+    viewMenu.add(hetatmMenu);
     helpMenu.add(helpItem);
 
     menuBar.add(fileMenu);
index b1e1486..8ba94b0 100644 (file)
@@ -21,6 +21,7 @@
 package jalview.structure;
 
 import java.awt.Color;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -254,4 +255,8 @@ public interface StructureCommandsI
   StructureCommandI getResidueAttributes(String attName);
 
   List<StructureCommandI> centerViewOn(List<AtomSpecModel> residues);
+
+  default List<StructureCommandI> showHetatms(List<String> toShow) {
+    return Collections.EMPTY_LIST;
+  }
 }
index dcedafa..55955a8 100644 (file)
@@ -26,6 +26,7 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -2006,4 +2007,18 @@ public abstract class AAStructureBindingModel
   {
     return 0;
   }
+
+  public List<String> getHetatmNames() {
+    return Collections.EMPTY_LIST;
+  }
+  /**
+   * Generates and executes a command to show the given hetatm types as CPK
+   * 
+   * @param toShow - one or more of strings from getHetatmNames
+   */
+  public void showHetatms(List<String> toShow)
+  {
+    executeCommands(commandGenerator.showHetatms(toShow), false, "Adjusting hetatm visibility");
+  }
+
 }