Merge branch 'JAL-3878_ws-overhaul-3' into with_ws_overhaul-3
[jalview.git] / src / jalview / gui / AppJmolBinding.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import java.awt.Container;
24 import java.io.File;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Map;
28
29 import javax.swing.JComponent;
30
31 import org.jmol.api.JmolAppConsoleInterface;
32 import org.openscience.jmol.app.jmolpanel.console.AppConsole;
33
34 import jalview.api.AlignmentViewPanel;
35 import jalview.api.structures.JalviewStructureDisplayI;
36 import jalview.bin.Console;
37 import jalview.datamodel.AlignmentI;
38 import jalview.datamodel.PDBEntry;
39 import jalview.datamodel.SequenceI;
40 import jalview.ext.jmol.JalviewJmolBinding;
41 import jalview.io.DataSourceType;
42 import jalview.structure.StructureSelectionManager;
43 import jalview.util.MessageManager;
44 import jalview.util.Platform;
45 import jalview.ws.dbsources.EBIAlfaFold;
46 import jalview.ws.dbsources.Pdb;
47 import jalview.ws.utils.UrlDownloadClient;
48 import javajs.util.BS;
49
50 public class AppJmolBinding extends JalviewJmolBinding
51 {
52   public AppJmolBinding(AppJmol appJmol, StructureSelectionManager sSm,
53           PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
54           DataSourceType protocol)
55   {
56     super(sSm, pdbentry, sequenceIs, protocol);
57     setViewer(appJmol);
58   }
59
60   @Override
61   public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
62   {
63     return new SequenceRenderer(((AlignmentPanel) alignment).av);
64   }
65
66   @Override
67   public void sendConsoleEcho(String strEcho)
68   {
69     if (console != null)
70     {
71       console.sendConsoleEcho(strEcho);
72     }
73   }
74
75   @Override
76   public void sendConsoleMessage(String strStatus)
77   {
78     if (console != null && strStatus != null)
79     // && !strStatus.equals("Script completed"))
80     // should we squash the script completed string ?
81     {
82       console.sendConsoleMessage(strStatus);
83     }
84   }
85
86   @Override
87   public void showUrl(String url, String target)
88   {
89     try
90     {
91       jalview.util.BrowserLauncher.openURL(url);
92     } catch (Exception e)
93     {
94       Console.error("Failed to launch Jmol-associated url " + url, e);
95       // TODO: 2.6 : warn user if browser was not configured.
96     }
97   }
98
99   @Override
100   public void refreshGUI()
101   {
102     if (getMappedStructureCount() == 0)
103     {
104       // too soon!
105       return;
106     }
107     // appJmolWindow.repaint();
108     javax.swing.SwingUtilities.invokeLater(new Runnable()
109     {
110       @Override
111       public void run()
112       {
113         JalviewStructureDisplayI theViewer = getViewer();
114         // invokes colourbySequence() via seqColour_ActionPerformed()
115         theViewer.updateTitleAndMenus();
116         ((JComponent) theViewer).revalidate();
117       }
118     });
119   }
120
121   @Override
122   public void notifyScriptTermination(String strStatus, int msWalltime)
123   {
124     // todo - script termination doesn't happen ?
125     // if (console != null)
126     // console.notifyScriptTermination(strStatus,
127     // msWalltime);
128   }
129
130   @Override
131   public void showUrl(String url)
132   {
133     showUrl(url, "jmol");
134   }
135
136   public void newJmolPopup(String menuName)
137   {
138     // jmolpopup = new JmolAwtPopup();
139     // jmolpopup.jpiInitialize((viewer), menuName);
140   }
141
142   @Override
143   public void selectionChanged(BS arg0)
144   {
145   }
146
147   @Override
148   public void showConsole(boolean b)
149   {
150     getViewer().showConsole(b);
151   }
152
153   @Override
154   protected JmolAppConsoleInterface createJmolConsole(
155           Container consolePanel, String buttonsToShow)
156   {
157     jmolViewer.setJmolCallbackListener(this);
158     // BH comment: can't do this yet [for JS only, or generally?]
159     return Platform.isJS() ? null
160             : new AppConsole(jmolViewer, consolePanel, buttonsToShow);
161   }
162
163   @Override
164   protected void releaseUIResources()
165   {
166     setViewer(null);
167     closeConsole();
168   }
169
170   @Override
171   public void releaseReferences(Object svl)
172   {
173     if (svl instanceof SeqPanel)
174     {
175       getViewer().removeAlignmentPanel(((SeqPanel) svl).ap);
176     }
177   }
178
179   @Override
180   public Map<String, Object> getJSpecViewProperty(String arg0)
181   {
182     // TODO Auto-generated method stub
183     return null;
184   }
185
186   @SuppressWarnings("unused")
187   public void cacheFiles(List<File> files)
188   {
189     if (files == null)
190     {
191       return;
192     }
193     for (File f : files)
194     {
195       Platform.cacheFileData(f);
196     }
197   }
198
199   /**
200    * Retrieves and saves as file any modelled PDB entries for which we do not
201    * already have a file saved. Returns a list of absolute paths to structure
202    * files which were either retrieved, or already stored but not modelled in
203    * the structure viewer (i.e. files to add to the viewer display).
204    * 
205    * Currently only used by Jmol - similar but different code used for Chimera/X
206    * and Pymol so still need to refactor
207    * 
208    * @param structureViewer
209    *          UI proxy for the structure viewer
210    * @return list of absolute paths to structures retrieved that need to be
211    *         added to the display
212    */
213   public List<String> fetchPdbFiles(StructureViewerBase structureViewer)
214   {
215     // todo - record which pdbids were successfully imported.
216     StringBuilder errormsgs = new StringBuilder();
217
218     List<String> files = new ArrayList<>();
219     String pdbid = "";
220     try
221     {
222       String[] filesInViewer = getStructureFiles();
223       // TODO: replace with reference fetching/transfer code (validate PDBentry
224       // as a DBRef?)
225
226       for (int pi = 0; pi < getPdbCount(); pi++)
227       {
228         PDBEntry strucEntry = getPdbEntry(pi);
229
230         String file = strucEntry.getFile();
231         if (file == null)
232         {
233           pdbid = strucEntry.getId();
234           try
235           {
236             file = structureViewer.fetchPdbFile(strucEntry);
237           } catch (OutOfMemoryError oomerror)
238           {
239             new OOMWarning("Retrieving PDB id " + pdbid, oomerror);
240           } catch (Exception ex)
241           {
242             ex.printStackTrace();
243             errormsgs.append("'").append(pdbid).append("'");
244           }
245           if (file != null)
246           {
247             // success
248             files.add(file);
249           }
250           else
251           {
252             errormsgs.append("'").append(pdbid).append("' ");
253           }
254         }
255         else
256         {
257           if (filesInViewer != null && filesInViewer.length > 0)
258           {
259             structureViewer.setAddingStructures(true); // already files loaded.
260             for (int c = 0; c < filesInViewer.length; c++)
261             {
262               if (Platform.pathEquals(filesInViewer[c], file))
263               {
264                 file = null;
265                 break;
266               }
267             }
268           }
269           if (file != null)
270           {
271             files.add(file);
272           }
273         }
274       }
275     } catch (OutOfMemoryError oomerror)
276     {
277       new OOMWarning("Retrieving PDB files: " + pdbid, oomerror);
278     } catch (Exception ex)
279     {
280       ex.printStackTrace();
281       errormsgs.append("When retrieving pdbfiles : current was: '")
282               .append(pdbid).append("'");
283     }
284     if (errormsgs.length() > 0)
285     {
286         JvOptionPane.showInternalMessageDialog(Desktop.getInstance(),
287               MessageManager.formatMessage(
288                       "label.pdb_entries_couldnt_be_retrieved", new String[]
289                       { errormsgs.toString() }),
290               MessageManager.getString("label.couldnt_load_file"),
291               JvOptionPane.ERROR_MESSAGE);
292     }
293     return files;
294   }
295
296 }